Remove fribidize in translation class
This commit is contained in:
parent
b5e5d44808
commit
9a7210614b
@ -405,7 +405,7 @@ public:
|
||||
\return Pointer to the created static text. Returns 0 if an error
|
||||
occurred. This pointer should not be dropped. See
|
||||
IReferenceCounted::drop() for more information. */
|
||||
virtual IGUIStaticText* addStaticText(const wchar_t* text, const core::rect<s32>& rectangle,
|
||||
virtual IGUIStaticText* addStaticText(const core::stringw& text, const core::rect<s32>& rectangle,
|
||||
bool border=false, bool wordWrap=true, IGUIElement* parent=0, s32 id=-1,
|
||||
bool fillBackground = false) = 0;
|
||||
|
||||
|
@ -81,7 +81,7 @@ IGUIElement* CDefaultGUIElementFactory::addGUIElement(EGUI_ELEMENT_TYPE type, IG
|
||||
case EGUIET_SCROLL_BAR:
|
||||
return Environment->addScrollBar(false,core::rect<s32>(0,0,100,100),parent);
|
||||
case EGUIET_STATIC_TEXT:
|
||||
return Environment->addStaticText(0,core::rect<s32>(0,0,100,100),false,true,parent);
|
||||
return Environment->addStaticText(L"",core::rect<s32>(0,0,100,100),false,true,parent);
|
||||
case EGUIET_TAB:
|
||||
return Environment->addTab(core::rect<s32>(0,0,100,100),parent);
|
||||
case EGUIET_TAB_CONTROL:
|
||||
|
@ -403,7 +403,7 @@ void CGUIEnvironment::OnPostRender( u32 time )
|
||||
|
||||
pos.constrainTo(getAbsolutePosition());
|
||||
|
||||
ToolTip.Element = addStaticText(HoveredNoSubelement->getToolTipText().c_str(), pos, true, true, this, -1, true);
|
||||
ToolTip.Element = addStaticText(HoveredNoSubelement->getToolTipText(), pos, true, true, this, -1, true);
|
||||
ToolTip.Element->setOverrideColor(getSkin()->getColor(EGDC_TOOLTIP));
|
||||
ToolTip.Element->setBackgroundColor(getSkin()->getColor(EGDC_TOOLTIP_BACKGROUND));
|
||||
ToolTip.Element->setOverrideFont(getSkin()->getFont(EGDF_TOOLTIP));
|
||||
@ -1232,7 +1232,7 @@ IGUIColorSelectDialog* CGUIEnvironment::addColorSelectDialog(const wchar_t* titl
|
||||
|
||||
|
||||
//! adds a static text. The returned pointer must not be dropped.
|
||||
IGUIStaticText* CGUIEnvironment::addStaticText(const wchar_t* text,
|
||||
IGUIStaticText* CGUIEnvironment::addStaticText(const core::stringw& text,
|
||||
const core::rect<s32>& rectangle,
|
||||
bool border, bool wordWrap,
|
||||
IGUIElement* parent, s32 id, bool background)
|
||||
|
@ -142,7 +142,7 @@ public:
|
||||
virtual IGUIColorSelectDialog* addColorSelectDialog(const wchar_t* title = 0, bool modal=true, IGUIElement* parent=0, s32 id=-1);
|
||||
|
||||
//! adds a static text. The returned pointer must not be dropped.
|
||||
virtual IGUIStaticText* addStaticText(const wchar_t* text, const core::rect<s32>& rectangle,
|
||||
virtual IGUIStaticText* addStaticText(const core::stringw& text, const core::rect<s32>& rectangle,
|
||||
bool border=false, bool wordWrap=true, IGUIElement* parent=0, s32 id=-1, bool drawBackground = false);
|
||||
|
||||
//! Adds an edit box. The returned pointer must not be dropped.
|
||||
|
@ -17,7 +17,7 @@ namespace gui
|
||||
{
|
||||
|
||||
//! constructor
|
||||
CGUIStaticText::CGUIStaticText(const wchar_t* text, bool border,
|
||||
CGUIStaticText::CGUIStaticText(const core::stringw& text, bool border,
|
||||
IGUIEnvironment* environment, IGUIElement* parent,
|
||||
s32 id, const core::rect<s32>& rectangle,
|
||||
bool background)
|
||||
|
@ -21,7 +21,7 @@ namespace gui
|
||||
public:
|
||||
|
||||
//! constructor
|
||||
CGUIStaticText(const wchar_t* text, bool border, IGUIEnvironment* environment,
|
||||
CGUIStaticText(const core::stringw& text, bool border, IGUIEnvironment* environment,
|
||||
IGUIElement* parent, s32 id, const core::rect<s32>& rectangle,
|
||||
bool background = false);
|
||||
|
||||
|
@ -85,7 +85,7 @@ void STKTextBillboard::updateAbsolutePosition()
|
||||
} // updateAbsolutePosition
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void STKTextBillboard::init(core::stringw text, FontWithFace* face)
|
||||
void STKTextBillboard::init(const core::stringw& text, FontWithFace* face)
|
||||
{
|
||||
m_chars = new std::vector<STKTextBillboardChar>();
|
||||
core::dimension2du size = face->getDimension(text);
|
||||
@ -255,7 +255,7 @@ void STKTextBillboard::init(core::stringw text, FontWithFace* face)
|
||||
} // init
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void STKTextBillboard::initLegacy(core::stringw text, FontWithFace* face)
|
||||
void STKTextBillboard::initLegacy(const core::stringw& text, FontWithFace* face)
|
||||
{
|
||||
m_chars = new std::vector<STKTextBillboardChar>();
|
||||
core::dimension2du size = face->getDimension(text);
|
||||
|
@ -125,9 +125,9 @@ public:
|
||||
// ------------------------------------------------------------------------
|
||||
virtual const core::aabbox3df& getBoundingBox() const { return m_bbox; }
|
||||
// ------------------------------------------------------------------------
|
||||
void init(core::stringw text, FontWithFace* face);
|
||||
void init(const core::stringw& text, FontWithFace* face);
|
||||
// ------------------------------------------------------------------------
|
||||
void initLegacy(core::stringw text, FontWithFace* face);
|
||||
void initLegacy(const core::stringw& text, FontWithFace* face);
|
||||
// ------------------------------------------------------------------------
|
||||
void draw(video::ITexture* tex) const
|
||||
{
|
||||
|
@ -745,7 +745,7 @@ namespace GUIEngine
|
||||
irr::core::stringw m_message;
|
||||
float m_time;
|
||||
|
||||
MenuMessage(const wchar_t* message, const float time)
|
||||
MenuMessage(const core::stringw& message, const float time)
|
||||
: m_message(message), m_time(time)
|
||||
{
|
||||
}
|
||||
@ -754,7 +754,7 @@ namespace GUIEngine
|
||||
std::vector<MenuMessage> gui_messages;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
void showMessage(const wchar_t* message, const float time)
|
||||
void showMessage(const core::stringw& message, const float time)
|
||||
{
|
||||
// check for duplicates
|
||||
const int count = (int) gui_messages.size();
|
||||
|
@ -40,6 +40,8 @@ namespace irr
|
||||
#include "utils/constants.hpp"
|
||||
#include "utils/ptr_vector.hpp"
|
||||
|
||||
#include "irrString.h"
|
||||
|
||||
/**
|
||||
* \ingroup guiengine
|
||||
* \brief Contains all GUI engine related classes and functions
|
||||
@ -195,7 +197,7 @@ namespace GUIEngine
|
||||
* \param message the message to display
|
||||
* \param time the time to display the message, in seconds
|
||||
*/
|
||||
void showMessage(const wchar_t* message, const float time=5.0f);
|
||||
void showMessage(const irr::core::stringw& message, const float time=5.0f);
|
||||
|
||||
/** \brief Add a screen to the list of screens known by the gui engine */
|
||||
void addScreenToList(Screen* screen);
|
||||
|
@ -251,7 +251,7 @@ public:
|
||||
}
|
||||
}
|
||||
// ------------------------------------------------------------------------
|
||||
void setProgress(int progress, const wchar_t* msg)
|
||||
void setProgress(int progress, const core::stringw& msg)
|
||||
{
|
||||
if (progress < 0)
|
||||
return;
|
||||
@ -344,7 +344,7 @@ void update(float dt)
|
||||
* used each time.
|
||||
* \param progress Progress from 0 to 100.
|
||||
*/
|
||||
void showProgressBar(int progress, const wchar_t* msg)
|
||||
void showProgressBar(int progress, const core::stringw& msg)
|
||||
{
|
||||
#ifndef SERVER_ONLY
|
||||
if (ProfileWorld::isNoGraphics())
|
||||
|
@ -44,7 +44,7 @@ namespace MessageQueue
|
||||
};
|
||||
|
||||
void add(MessageType mt, const core::stringw &message);
|
||||
void showProgressBar(int progress, const wchar_t* msg);
|
||||
void showProgressBar(int progress, const core::stringw& msg);
|
||||
void updatePosition();
|
||||
void update(float dt);
|
||||
|
||||
|
@ -481,7 +481,7 @@ void RibbonWidget::add()
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void RibbonWidget::addTextChild(const wchar_t* text, const std::string &id)
|
||||
void RibbonWidget::addTextChild(const core::stringw& text, const std::string &id)
|
||||
{
|
||||
// This method should only be called BEFORE a widget is added
|
||||
assert(m_element == NULL);
|
||||
@ -495,7 +495,7 @@ void RibbonWidget::addTextChild(const wchar_t* text, const std::string &id)
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void RibbonWidget::addIconChild(const wchar_t* text, const std::string &id,
|
||||
void RibbonWidget::addIconChild(const core::stringw& text, const std::string &id,
|
||||
const int w, const int h,
|
||||
const std::string &icon,
|
||||
const IconButtonWidget::IconPathType icon_path_type)
|
||||
|
@ -180,7 +180,7 @@ namespace GUIEngine
|
||||
* \pre only valid for ribbons that take text-only contents
|
||||
* (e.g. tab bars)
|
||||
*/
|
||||
void addTextChild(const wchar_t* text, const std::string &id);
|
||||
void addTextChild(const core::stringw& text, const std::string &id);
|
||||
|
||||
|
||||
/** \brief Dynamically (at runtime) add an icon item to this ribbon.
|
||||
@ -188,7 +188,7 @@ namespace GUIEngine
|
||||
* is not yet displayed
|
||||
* \pre only valid for ribbons that take icon contents
|
||||
*/
|
||||
void addIconChild(const wchar_t* text, const std::string &id,
|
||||
void addIconChild(const core::stringw& text, const std::string &id,
|
||||
const int w, const int h, const std::string &icon,
|
||||
const IconButtonWidget::IconPathType iconPathType=
|
||||
IconButtonWidget::ICON_PATH_TYPE_RELATIVE);
|
||||
|
@ -517,7 +517,7 @@ public:
|
||||
// -------------------------------------------------------------------------
|
||||
/** Set a text that is displayed on top of a kart.
|
||||
*/
|
||||
virtual void setOnScreenText(const wchar_t *text) = 0;
|
||||
virtual void setOnScreenText(const core::stringw& text) = 0;
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns whether this kart wins or loses. */
|
||||
virtual bool getRaceResult() const = 0;
|
||||
|
@ -3424,7 +3424,7 @@ btQuaternion Kart::getVisualRotation() const
|
||||
* output.
|
||||
* \param text The text to display
|
||||
*/
|
||||
void Kart::setOnScreenText(const wchar_t *text)
|
||||
void Kart::setOnScreenText(const core::stringw& text)
|
||||
{
|
||||
#ifndef SERVER_ONLY
|
||||
if (ProfileWorld::isNoGraphics())
|
||||
|
@ -543,7 +543,7 @@ public:
|
||||
return m_terrain_info;
|
||||
}
|
||||
// ------------------------------------------------------------------------
|
||||
virtual void setOnScreenText(const wchar_t *text) OVERRIDE;
|
||||
virtual void setOnScreenText(const core::stringw& text) OVERRIDE;
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the normal of the terrain the kart is over atm. This is
|
||||
* defined even if the kart is flying. */
|
||||
|
@ -31,7 +31,7 @@ using namespace GUIEngine;
|
||||
using namespace irr::core;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
GeneralTextFieldDialog::GeneralTextFieldDialog(const wchar_t* title,
|
||||
GeneralTextFieldDialog::GeneralTextFieldDialog(const core::stringw& title,
|
||||
DismissCallback dm_cb,
|
||||
ValidationCallback val_cb)
|
||||
: ModalDialog(0.95f, 0.4f,
|
||||
|
@ -21,6 +21,8 @@
|
||||
#include "guiengine/modaldialog.hpp"
|
||||
#include "utils/cpp2011.hpp"
|
||||
|
||||
#include "irrString.h"
|
||||
|
||||
#include <functional>
|
||||
|
||||
namespace GUIEngine
|
||||
@ -55,7 +57,7 @@ private:
|
||||
bool m_self_destroy;
|
||||
|
||||
public:
|
||||
GeneralTextFieldDialog(const wchar_t* title, DismissCallback dm_cb,
|
||||
GeneralTextFieldDialog(const core::stringw& title, DismissCallback dm_cb,
|
||||
ValidationCallback val_cb = []
|
||||
(GUIEngine::LabelWidget* lw, GUIEngine::TextBoxWidget* tb)->bool
|
||||
{
|
||||
|
@ -399,16 +399,16 @@ void OptionsScreenDevice::updateInputButtons()
|
||||
GUIEngine::Widget* conflict_label =
|
||||
getWidget<GUIEngine::LabelWidget>("conflict");
|
||||
|
||||
std::wostringstream oss;
|
||||
core::stringw warning;
|
||||
if (conflicts_between)
|
||||
{
|
||||
oss << _("* A blue item means a conflict with another configuration");
|
||||
warning = _("* A blue item means a conflict with another configuration");
|
||||
if (conflicts_inside)
|
||||
oss << "\n";
|
||||
warning += "\n";
|
||||
}
|
||||
if (conflicts_inside)
|
||||
oss << _("* A red item means a conflict in the current configuration");
|
||||
conflict_label->setText(oss.str().c_str());
|
||||
warning += _("* A red item means a conflict in the current configuration");
|
||||
conflict_label->setText(warning);
|
||||
|
||||
} // updateInputButtons
|
||||
|
||||
|
@ -405,7 +405,7 @@ void RaceGUI::drawGlobalTimer()
|
||||
{
|
||||
sw = _("Challenge Failed");
|
||||
int string_width =
|
||||
GUIEngine::getFont()->getDimension(_("Challenge Failed")).Width;
|
||||
GUIEngine::getFont()->getDimension(sw.c_str()).Width;
|
||||
dist_from_right = 10 + string_width;
|
||||
time_color = video::SColor(255,255,0,0);
|
||||
use_digit_font = false;
|
||||
@ -429,7 +429,7 @@ void RaceGUI::drawGlobalTimer()
|
||||
font->setShadow(video::SColor(255, 128, 0, 0));
|
||||
font->setScale(1.0f);
|
||||
font->setBlackBorder(true);
|
||||
font->draw(sw.c_str(), pos, time_color, false, false, NULL,
|
||||
font->draw(sw, pos, time_color, false, false, NULL,
|
||||
true /* ignore RTL */);
|
||||
font->setBlackBorder(false);
|
||||
|
||||
|
@ -707,9 +707,9 @@ namespace StringUtils
|
||||
* convenience function to type less in calls.
|
||||
* \parameter s The string to which the loading dots are appended.
|
||||
*/
|
||||
irr::core::stringw loadingDots(const wchar_t *s)
|
||||
irr::core::stringw loadingDots(const irr::core::stringw& s)
|
||||
{
|
||||
return irr::core::stringw(s) + loadingDots();
|
||||
return s + loadingDots();
|
||||
} // loadingDots
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
@ -51,7 +51,7 @@ namespace StringUtils
|
||||
std::string timeToString(float time, unsigned int precision=2,
|
||||
bool display_minutes_if_zero = true, bool display_hours = false);
|
||||
irr::core::stringw loadingDots(float interval = 0.5f, int max_dots = 3);
|
||||
irr::core::stringw loadingDots(const wchar_t *s);
|
||||
irr::core::stringw loadingDots(const irr::core::stringw& s);
|
||||
std::string toUpperCase(const std::string&);
|
||||
std::string toLowerCase(const std::string&);
|
||||
std::vector<std::string> split(const std::string& s, char c,
|
||||
|
@ -521,55 +521,6 @@ Translations::~Translations()
|
||||
} // ~Translations
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
const wchar_t* Translations::fribidize(const wchar_t* in_ptr)
|
||||
{
|
||||
#ifdef SERVER_ONLY
|
||||
return in_ptr;
|
||||
#else
|
||||
if (isRTLText(in_ptr))
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_fribidized_mutex);
|
||||
// Test if this string was already fribidized
|
||||
std::map<const irr::core::stringw, const irr::core::stringw>::const_iterator
|
||||
found = m_fribidized_strings.find(in_ptr);
|
||||
if (found != m_fribidized_strings.cend())
|
||||
return found->second.c_str();
|
||||
|
||||
// Use fribidi to fribidize the string
|
||||
// Split text into lines
|
||||
std::vector<core::stringw> input_lines = StringUtils::split(in_ptr, '\n');
|
||||
// Reverse lines for RTL strings, irrlicht will reverse them back
|
||||
// This is needed because irrlicht inserts line breaks itself if a text
|
||||
// is too long for one line and then reverses the lines again.
|
||||
std::reverse(input_lines.begin(), input_lines.end());
|
||||
|
||||
// Fribidize and concat lines
|
||||
core::stringw converted_string;
|
||||
for (std::vector<core::stringw>::iterator it = input_lines.begin();
|
||||
it != input_lines.end(); it++)
|
||||
{
|
||||
if (it == input_lines.begin())
|
||||
converted_string = fribidizeLine(*it);
|
||||
else
|
||||
{
|
||||
converted_string += "\n";
|
||||
converted_string += fribidizeLine(*it);
|
||||
}
|
||||
}
|
||||
|
||||
// Save it in the map
|
||||
m_fribidized_strings.insert(std::pair<const irr::core::stringw, const irr::core::stringw>(
|
||||
in_ptr, converted_string));
|
||||
found = m_fribidized_strings.find(in_ptr);
|
||||
|
||||
return found->second.c_str();
|
||||
}
|
||||
else
|
||||
return in_ptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool Translations::isRTLText(const wchar_t *in_ptr)
|
||||
{
|
||||
#if ENABLE_BIDI
|
||||
@ -699,57 +650,6 @@ const wchar_t* Translations::w_ngettext(const char* singular, const char* plural
|
||||
|
||||
}
|
||||
|
||||
core::stringw Translations::fribidizeLine(const core::stringw &str)
|
||||
{
|
||||
#if ENABLE_BIDI
|
||||
FriBidiChar *fribidiInput = toFribidiChar(str.c_str());
|
||||
std::size_t length = 0;
|
||||
while (fribidiInput[length])
|
||||
length++;
|
||||
|
||||
// Assume right to left as start direction.
|
||||
#if FRIBIDI_MINOR_VERSION==10
|
||||
// While the doc for older fribidi versions is somewhat sparse,
|
||||
// using the RIGHT-TO-LEFT EMBEDDING character here appears to
|
||||
// work correct.
|
||||
FriBidiCharType pbase_dir = L'\u202B';
|
||||
#else
|
||||
FriBidiCharType pbase_dir = FRIBIDI_PAR_ON;
|
||||
#endif
|
||||
|
||||
// Reverse text line by line
|
||||
FriBidiChar *fribidiOutput = new FriBidiChar[length + 1];
|
||||
memset(fribidiOutput, 0, (length + 1) * sizeof(FriBidiChar));
|
||||
fribidi_boolean result = fribidi_log2vis(fribidiInput,
|
||||
(FriBidiStrIndex)length,
|
||||
&pbase_dir,
|
||||
fribidiOutput,
|
||||
/* gint *position_L_to_V_list */ NULL,
|
||||
/* gint *position_V_to_L_list */ NULL,
|
||||
/* gint8 *embedding_level_list */ NULL
|
||||
);
|
||||
|
||||
freeFribidiChar(fribidiInput);
|
||||
|
||||
if (!result)
|
||||
{
|
||||
delete[] fribidiOutput;
|
||||
Log::error("Translations::fribidize", "Fribidi failed in 'fribidi_log2vis' =(");
|
||||
return core::stringw(str);
|
||||
}
|
||||
|
||||
wchar_t *convertedString = fromFribidiChar(fribidiOutput);
|
||||
core::stringw converted_string(convertedString);
|
||||
freeFribidiChar(convertedString);
|
||||
delete[] fribidiOutput;
|
||||
return converted_string;
|
||||
|
||||
#else
|
||||
return core::stringw(str);
|
||||
#endif // ENABLE_BIDI
|
||||
|
||||
}
|
||||
|
||||
#ifndef SERVER_ONLY
|
||||
std::set<wchar_t> Translations::getCurrentAllChar()
|
||||
{
|
||||
|
@ -31,13 +31,12 @@
|
||||
#include "tinygettext/tinygettext.hpp"
|
||||
#endif
|
||||
|
||||
# define _(String, ...) (translations->fribidize(StringUtils::insertValues(translations->w_gettext(String), ##__VA_ARGS__)))
|
||||
# define _(String, ...) (StringUtils::insertValues(translations->w_gettext(String), ##__VA_ARGS__))
|
||||
#undef _C
|
||||
#undef _P
|
||||
# define _C(Ctx, String, ...) (translations->fribidize(StringUtils::insertValues(translations->w_gettext(String, Ctx), ##__VA_ARGS__)))
|
||||
# define _P(Singular, Plural, Num, ...) (translations->fribidize(StringUtils::insertValues(translations->w_ngettext(Singular, Plural, Num), Num, ##__VA_ARGS__)))
|
||||
# define _CP(Ctx, Singular, Plural, Num, ...) (translations->fribidize(StringUtils::insertValues(translations->w_ngettext(Singular, Plural, Num, Ctx), Num, ##__VA_ARGS__)))
|
||||
# define _LTR(String, ...) (StringUtils::insertValues(translations->w_gettext(String), ##__VA_ARGS__))
|
||||
# define _C(Ctx, String, ...) (StringUtils::insertValues(translations->w_gettext(String, Ctx), ##__VA_ARGS__))
|
||||
# define _P(Singular, Plural, Num, ...) (StringUtils::insertValues(translations->w_ngettext(Singular, Plural, Num), Num, ##__VA_ARGS__))
|
||||
# define _CP(Ctx, Singular, Plural, Num, ...) (StringUtils::insertValues(translations->w_ngettext(Singular, Plural, Num, Ctx), Num, ##__VA_ARGS__))
|
||||
# define gettext_noop(String) (String)
|
||||
# define N_(String) (gettext_noop (String))
|
||||
// libintl defines its own fprintf, which doesn't work properly
|
||||
@ -52,8 +51,6 @@ private:
|
||||
tinygettext::DictionaryManager m_dictionary_manager;
|
||||
tinygettext::Dictionary m_dictionary;
|
||||
|
||||
/** A map that saves all fribidized strings: Original string, fribidized string */
|
||||
std::map<const irr::core::stringw, const irr::core::stringw> m_fribidized_strings;
|
||||
bool m_rtl;
|
||||
|
||||
static std::map<std::string, std::string> m_localized_name;
|
||||
@ -61,7 +58,7 @@ private:
|
||||
std::string m_current_language_name;
|
||||
std::string m_current_language_name_code;
|
||||
std::string m_current_language_tag;
|
||||
std::mutex m_fribidized_mutex, m_gettext_mutex, m_ngettext_mutex;
|
||||
std::mutex m_gettext_mutex, m_ngettext_mutex;
|
||||
#endif
|
||||
|
||||
public:
|
||||
@ -101,9 +98,6 @@ public:
|
||||
|
||||
irr::core::stringw getLocalizedCountryName(const std::string& country_code) const;
|
||||
#endif
|
||||
|
||||
private:
|
||||
irr::core::stringw fribidizeLine(const irr::core::stringw &str);
|
||||
}; // Translations
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user