Add localized menu options, buttons, and error messages in multiple languages to enhance user experience and accessibility across the application.

This commit is contained in:
Torsten Schulz (local)
2025-11-16 21:24:40 +01:00
parent 25c3d20885
commit a18c09592d
12 changed files with 155 additions and 29 deletions

View File

@@ -10,6 +10,30 @@
<message id="gender_pair">Pair</message>
<message id="gender_trans_mf">Transgender (M-&gt;F)</message>
<message id="gender_trans_fm">Transgender (F-&gt;M)</message>
<message id="menu_leave">Leave</message>
<message id="menu_search">Search</message>
<message id="menu_inbox">Inbox</message>
<message id="menu_history">History</message>
<message id="menu_in_chat_for">In chat for {1}</message>
<message id="menu_timeout_in">Timeout in {1}</message>
<message id="history_title"><![CDATA[<h2>Conversations with already logged in users</h2>]]></message>
<message id="history_empty">No previous conversations available.</message>
<message id="button_block_user">Block user</message>
<message id="button_unblock_user">Unblock user</message>
<message id="button_send">Send</message>
<message id="tooltip_send_image">Send an image</message>
<message id="dialog_send_image_title">Send image to user</message>
<message id="dialog_send_image_text">Please select an image</message>
<message id="dialog_send_image_ok">Send image</message>
<message id="dialog_send_image_cancel">Cancel</message>
<message id="image_uploaded_processed">Uploaded and processed image</message>
<message id="admin_name">Name:</message>
<message id="admin_password">Password:</message>
<message id="admin_login_button">Login</message>
<message id="admin_login_error">Incorrect username or password.</message>
<message id="error_page_not_found">Error 400 - Page not found</message>
<message id="error_opening_file">Error opening file.</message>
<message id="label_name">Name</message>
<message id="welcome">
<main>
<header>

View File

@@ -10,6 +10,30 @@
<message id="gender_pair">Paar</message>
<message id="gender_trans_mf">Transgender (M-&gt;F)</message>
<message id="gender_trans_fm">Transgender (F-&gt;M)</message>
<message id="menu_leave">Verlassen</message>
<message id="menu_search">Suche</message>
<message id="menu_inbox">Posteingang</message>
<message id="menu_history">Verlauf</message>
<message id="menu_in_chat_for">Im Chat seit {1}</message>
<message id="menu_timeout_in">Timeout in {1}</message>
<message id="history_title"><![CDATA[<h2>Unterhaltungen mit bereits eingeloggten Nutzern</h2>]]></message>
<message id="history_empty">Keine bisherigen Unterhaltungen vorhanden.</message>
<message id="button_block_user">Benutzer blockieren</message>
<message id="button_unblock_user">Blockierung aufheben</message>
<message id="button_send">Senden</message>
<message id="tooltip_send_image">Bild senden</message>
<message id="dialog_send_image_title">Bild an Benutzer senden</message>
<message id="dialog_send_image_text">Bitte wähle ein Bild aus</message>
<message id="dialog_send_image_ok">Bild senden</message>
<message id="dialog_send_image_cancel">Abbrechen</message>
<message id="image_uploaded_processed">Hochgeladenes und verarbeitetes Bild</message>
<message id="admin_name">Name:</message>
<message id="admin_password">Passwort:</message>
<message id="admin_login_button">Login</message>
<message id="admin_login_error">Benutzername oder Passwort ist falsch.</message>
<message id="error_page_not_found">Fehler 400 - Seite nicht gefunden</message>
<message id="error_opening_file">Fehler beim Öffnen der Datei.</message>
<message id="label_name">Name</message>
<message id="welcome">
<main>
<header>

View File

@@ -10,6 +10,14 @@
<message id="gender_pair">Pair</message>
<message id="gender_trans_mf">Transgender (M-&gt;F)</message>
<message id="gender_trans_fm">Transgender (F-&gt;M)</message>
<message id="menu_leave">Leave</message>
<message id="menu_search">Search</message>
<message id="menu_inbox">Inbox</message>
<message id="menu_history">History</message>
<message id="menu_in_chat_for">In chat for {1}</message>
<message id="menu_timeout_in">Timeout in {1}</message>
<message id="history_title"><![CDATA[<h2>Conversations with already logged in users</h2>]]></message>
<message id="history_empty">No previous conversations available.</message>
<message id="welcome">
<main>
<header>

View File

@@ -10,6 +10,14 @@
<message id="gender_pair">Pair</message>
<message id="gender_trans_mf">Transgender (M-&gt;F)</message>
<message id="gender_trans_fm">Transgender (F-&gt;M)</message>
<message id="menu_leave">Leave</message>
<message id="menu_search">Search</message>
<message id="menu_inbox">Inbox</message>
<message id="menu_history">History</message>
<message id="menu_in_chat_for">In chat for {1}</message>
<message id="menu_timeout_in">Timeout in {1}</message>
<message id="history_title"><![CDATA[<h2>Conversations with already logged in users</h2>]]></message>
<message id="history_empty">No previous conversations available.</message>
<message id="welcome">
<main>
<header>

View File

@@ -10,6 +10,14 @@
<message id="gender_pair">Pareja</message>
<message id="gender_trans_mf">Transgénero (H-&gt;M)</message>
<message id="gender_trans_fm">Transgénero (M-&gt;H)</message>
<message id="menu_leave">Salir</message>
<message id="menu_search">Buscar</message>
<message id="menu_inbox">Bandeja de entrada</message>
<message id="menu_history">Historial</message>
<message id="menu_in_chat_for">En el chat desde {1}</message>
<message id="menu_timeout_in">Desconexión en {1}</message>
<message id="history_title"><![CDATA[<h2>Conversaciones con usuarios ya conectados</h2>]]></message>
<message id="history_empty">No hay conversaciones anteriores disponibles.</message>
<message id="welcome">
<main>
<header>

View File

@@ -10,6 +10,14 @@
<message id="gender_pair">Couple</message>
<message id="gender_trans_mf">Transgenre (H-&gt;F)</message>
<message id="gender_trans_fm">Transgenre (F-&gt;H)</message>
<message id="menu_leave">Quitter</message>
<message id="menu_search">Recherche</message>
<message id="menu_inbox">Boîte de réception</message>
<message id="menu_history">Historique</message>
<message id="menu_in_chat_for">En chat depuis {1}</message>
<message id="menu_timeout_in">Expiration dans {1}</message>
<message id="history_title"><![CDATA[<h2>Conversations avec des utilisateurs déjà connectés</h2>]]></message>
<message id="history_empty">Aucune conversation précédente disponible.</message>
<message id="welcome">
<main>
<header>

View File

@@ -10,6 +10,14 @@
<message id="gender_pair">Coppia</message>
<message id="gender_trans_mf">Trans (M-&gt;F)</message>
<message id="gender_trans_fm">Trans (F-&gt;M)</message>
<message id="menu_leave">Esci</message>
<message id="menu_search">Cerca</message>
<message id="menu_inbox">Posta in arrivo</message>
<message id="menu_history">Cronologia</message>
<message id="menu_in_chat_for">In chat da {1}</message>
<message id="menu_timeout_in">Timeout tra {1}</message>
<message id="history_title"><![CDATA[<h2>Conversazioni con utenti già collegati</h2>]]></message>
<message id="history_empty">Nessuna conversazione precedente disponibile.</message>
<message id="welcome">
<main>
<header>

View File

@@ -10,6 +10,14 @@
<message id="gender_pair">カップル</message>
<message id="gender_trans_mf">トランスジェンダー (M-&gt;F)</message>
<message id="gender_trans_fm">トランスジェンダー (F-&gt;M)</message>
<message id="menu_leave">退出</message>
<message id="menu_search">検索</message>
<message id="menu_inbox">受信トレイ</message>
<message id="menu_history">履歴</message>
<message id="menu_in_chat_for">チャット中: {1}</message>
<message id="menu_timeout_in">タイムアウトまで {1}</message>
<message id="history_title"><![CDATA[<h2>すでにログインしているユーザーとの会話</h2>]]></message>
<message id="history_empty">過去の会話はありません。</message>
<message id="welcome">
<main>
<header>

View File

@@ -10,6 +10,14 @@
<message id="gender_pair">คู่รัก</message>
<message id="gender_trans_mf">ทรานส์เจนเดอร์ (ช-&gt;ญ)</message>
<message id="gender_trans_fm">ทรานส์เจนเดอร์ (ญ-&gt;ช)</message>
<message id="menu_leave">ออกจากห้อง</message>
<message id="menu_search">ค้นหา</message>
<message id="menu_inbox">กล่องจดหมาย</message>
<message id="menu_history">ประวัติ</message>
<message id="menu_in_chat_for">อยู่ในห้องแชทมาแล้ว {1}</message>
<message id="menu_timeout_in">หมดเวลาในอีก {1}</message>
<message id="history_title"><![CDATA[<h2>การสนทนากับผู้ใช้ที่ล็อกอินอยู่แล้ว</h2>]]></message>
<message id="history_empty">ยังไม่มีกิจกรรมการสนทนาก่อนหน้านี้</message>
<message id="welcome">
<main>
<header>

View File

@@ -10,6 +10,14 @@
<message id="gender_pair">Mag-partner</message>
<message id="gender_trans_mf">Transgender (M-&gt;F)</message>
<message id="gender_trans_fm">Transgender (F-&gt;M)</message>
<message id="menu_leave">Umalis</message>
<message id="menu_search">Maghanap</message>
<message id="menu_inbox">Inbox</message>
<message id="menu_history">Kasaysayan</message>
<message id="menu_in_chat_for">Nasa chat nang {1}</message>
<message id="menu_timeout_in">Mawawala sa {1}</message>
<message id="history_title"><![CDATA[<h2>Mga pag-uusap sa mga naka-log in na user</h2>]]></message>
<message id="history_empty">Walang mga naunang pag-uusap.</message>
<message id="welcome">
<main>
<header>

View File

@@ -10,6 +10,14 @@
<message id="gender_pair">情侣</message>
<message id="gender_trans_mf">跨性别 (男-&gt;女)</message>
<message id="gender_trans_fm">跨性别 (女-&gt;男)</message>
<message id="menu_leave">离开</message>
<message id="menu_search">搜索</message>
<message id="menu_inbox">收件箱</message>
<message id="menu_history">历史</message>
<message id="menu_in_chat_for">已在线 {1}</message>
<message id="menu_timeout_in">将在 {1} 后断开</message>
<message id="history_title"><![CDATA[<h2>与已登录用户的会话</h2>]]></message>
<message id="history_empty">暂无历史会话。</message>
<message id="welcome">
<main>
<header>

View File

@@ -532,7 +532,10 @@ std::unique_ptr<Wt::WText> App::createInfoText(Wt::Json::Object userData) {
}
std::unique_ptr<Wt::WPushButton> App::createBlockButton(Wt::Json::Object userData) {
auto blockButton = std::make_unique<Wt::WPushButton>((bool)userData["blocked"] ? "Unblock user" : "Block user");
auto blockButton = std::make_unique<Wt::WPushButton>(
(bool)userData["blocked"]
? Wt::WString::tr("button_unblock_user")
: Wt::WString::tr("button_block_user"));
blockButton->clicked().connect([=, this]() mutable {
server_.toggleBlockUser(userName, (std::string)userData["name"], sessionId());
});
@@ -566,15 +569,15 @@ Wt::WLineEdit* App::createInputLine(Wt::WHBoxLayout* inputLayout) {
Wt::WImage* App::createSendImageButton(Wt::WHBoxLayout* inputLayout) {
auto sendImageButton = inputLayout->addWidget(std::make_unique<Wt::WImage>(Wt::WLink("/image.png")));
sendImageButton->setToolTip("Send an image");
sendImageButton->setToolTip(Wt::WString::tr("tooltip_send_image"));
sendImageButton->clicked().connect(this, &App::sendImage);
return sendImageButton;
}
void App::sendImage() {
auto fileDialog = root()->addNew<Wt::WDialog>("Send Image to User");
auto fileDialog = root()->addNew<Wt::WDialog>(Wt::WString::tr("dialog_send_image_title"));
auto layout = fileDialog->contents()->setLayout(std::make_unique<Wt::WVBoxLayout>());
layout->addWidget(std::make_unique<Wt::WText>("Please select an immage"));
layout->addWidget(std::make_unique<Wt::WText>(Wt::WString::tr("dialog_send_image_text")));
auto fileWidget = layout->addWidget(std::make_unique<Wt::WFileUpload>());
fileWidget->setFilters("image/*");
auto image = layout->addWidget(std::make_unique<Wt::WImage>());
@@ -582,18 +585,20 @@ void App::sendImage() {
image->setHeight(Wt::WLength::Auto);
auto localImage = std::make_shared<Magick::Blob>();
auto buttonsContainer = layout->addWidget(std::make_unique<Wt::WContainerWidget>());
auto okButton = buttonsContainer->addNew<Wt::WPushButton>("Send image");
auto okButton = buttonsContainer->addNew<Wt::WPushButton>(Wt::WString::tr("dialog_send_image_ok"));
fileWidget->uploaded().connect([=, this]() mutable {
imageUploaded(fileWidget, localImage, image, okButton);
});
fileWidget->changed().connect([=]() { fileWidget->upload(); });
fileWidget->fileTooLarge().connect([](){ std::cout << "file too big" << std::endl; });
fileWidget->fileTooLarge().connect([](){
std::cout << "file too big" << std::endl;
});
okButton->setDisabled(true);
okButton->clicked().connect([=, this]() {
server_.addImage(sessionId(), currentConversationWith_, localImage);
fileDialog->accept();
});
auto cancelButton = buttonsContainer->addNew<Wt::WPushButton>("Cancel");
auto cancelButton = buttonsContainer->addNew<Wt::WPushButton>(Wt::WString::tr("dialog_send_image_cancel"));
cancelButton->clicked().connect([=](){ fileDialog->reject(); });
fileDialog->setClosable(true);
fileDialog->setModal(true);
@@ -617,7 +622,7 @@ void App::imageUploaded(Wt::WFileUpload *fileWidget, std::shared_ptr<Magick::Blo
auto memoryResource = std::make_shared<Wt::WMemoryResource>(mimeType);
memoryResource->setData(static_cast<const unsigned char*>(displayBlob.data()), displayBlob.length());
image->setImageLink(Wt::WLink(memoryResource));
image->setAlternateText("Hochgeladenes und verarbeitetes Bild");
image->setAlternateText(Wt::WString::tr("image_uploaded_processed"));
okButton->setEnabled(true);
triggerUpdate();
} catch (const std::exception& e) {
@@ -673,14 +678,14 @@ void App::showAdminPage(std::string page) {
void App::showAdminLogin(std::string page) {
contentContainer_->clear();
auto loginContainer = contentContainer_->addNew<Wt::WContainerWidget>();
loginContainer->addNew<Wt::WText>("Name:");
loginContainer->addNew<Wt::WText>(Wt::WString::tr("admin_name"));
auto nameEdit = loginContainer->addNew<Wt::WLineEdit>();
loginContainer->addNew<Wt::WBreak>();
loginContainer->addNew<Wt::WText>("Password:");
loginContainer->addNew<Wt::WText>(Wt::WString::tr("admin_password"));
auto passwordEdit = loginContainer->addNew<Wt::WLineEdit>();
passwordEdit->setEchoMode(Wt::EchoMode::Password);
loginContainer->addNew<Wt::WBreak>();
auto loginButton = loginContainer->addNew<Wt::WPushButton>("Login");
auto loginButton = loginContainer->addNew<Wt::WPushButton>(Wt::WString::tr("admin_login_button"));
auto messageLabel = loginContainer->addNew<Wt::WText>();
auto loginAction = [=, this] {
if (nameEdit->text().toUTF8() == adminName && passwordEdit->text().toUTF8() == adminPassword) {
@@ -689,7 +694,7 @@ void App::showAdminLogin(std::string page) {
showAdminPage(page);
} else {
isLoggedInAsAdmin = false;
messageLabel->setText("Incorrect username or password.");
messageLabel->setText(Wt::WString::tr("admin_login_error"));
messageLabel->decorationStyle().setForegroundColor(Wt::WColor("red"));
}
};
@@ -699,7 +704,7 @@ void App::showAdminLogin(std::string page) {
void App::showPageNotExists() {
contentContainer_->clear();
auto errorMessageLabel = contentContainer_->addNew<Wt::WText>("Error 400 - Page not found");
auto errorMessageLabel = contentContainer_->addNew<Wt::WText>(Wt::WString::tr("error_page_not_found"));
errorMessageLabel->decorationStyle().setForegroundColor(Wt::WColor("red"));
}
@@ -708,7 +713,7 @@ void App::showAdminLogins() {
contentContainer_->addNew<Wt::WText>("<h2>Logins</h2>", Wt::TextFormat::UnsafeXHTML);
std::ifstream file("../logs/logins.log");
if (!file.is_open()) {
contentContainer_->addNew<Wt::WText>("Error opening file.");
contentContainer_->addNew<Wt::WText>(Wt::WString::tr("error_opening_file"));
return;
}
std::stringstream buffer;
@@ -718,10 +723,10 @@ void App::showAdminLogins() {
Wt::Json::parse(fileContent, jsonArray);
auto table = contentContainer_->addNew<Wt::WTable>();
table->setHeaderCount(1);
table->elementAt(0, 0)->addNew<Wt::WText>("Name");
table->elementAt(0, 1)->addNew<Wt::WText>("Country");
table->elementAt(0, 2)->addNew<Wt::WText>("Gender");
table->elementAt(0, 3)->addNew<Wt::WText>("Age");
table->elementAt(0, 0)->addNew<Wt::WText>(Wt::WString::tr("label_name"));
table->elementAt(0, 1)->addNew<Wt::WText>(Wt::WString::tr("label_country"));
table->elementAt(0, 2)->addNew<Wt::WText>(Wt::WString::tr("label_gender"));
table->elementAt(0, 3)->addNew<Wt::WText>(Wt::WString::tr("label_age"));
table->elementAt(0, 4)->addNew<Wt::WText>("Datum");
table->elementAt(0, 5)->addNew<Wt::WText>("Uhrzeit");
int row = 1;
@@ -827,7 +832,7 @@ Wt::WContainerWidget* App::createSmileyBar(Wt::WContainerWidget* parent, Wt::WLi
}
Wt::WPushButton* App::createSendButton(Wt::WHBoxLayout* inputLayout, Wt::WLineEdit* inputLine) {
auto sendButton = inputLayout->addWidget(std::make_unique<Wt::WPushButton>("Send"));
auto sendButton = inputLayout->addWidget(std::make_unique<Wt::WPushButton>(Wt::WString::tr("button_send")));
auto sendMessageFunction = [=, this]() {
sendMessage(inputLine);
};
@@ -1002,7 +1007,8 @@ std::string App::replaceSmileys(std::string outputText) {
}
void App::showUnreadMessages(Wt::Json::Object data) {
Wt::WString buttonText = (int)data["data"] == 0 ? "Inbox" : Wt::WString("Inbox ({1})").arg((int)data["data"]);
Wt::WString base = Wt::WString::tr("menu_inbox");
Wt::WString buttonText = (int)data["data"] == 0 ? base : Wt::WString("{1} ({2})").arg(base).arg((int)data["data"]);
auto currentText = inbox_->text();
inbox_->setText(buttonText);
std::string pattern{"Inbox\\(\\s*(\\d+)\\)"};
@@ -1016,7 +1022,7 @@ void App::showUnreadMessages(Wt::Json::Object data) {
if (oldValue < (int)data["data"] && (int)data["data"] > 0) {
doPlay = true;
}
} else if (text == "Inbox" && buttonText != "Inbox") {
} else if (text == Wt::WString::tr("menu_inbox") && buttonText != Wt::WString::tr("menu_inbox")) {
doPlay = true;
}
if (doPlay) {
@@ -1138,7 +1144,7 @@ void App::createMenu() {
}
void App::addLeaveButton() {
auto leaveButton = menuContainer_->addNew<Wt::WPushButton>("Leave");
auto leaveButton = menuContainer_->addNew<Wt::WPushButton>(Wt::WString::tr("menu_leave"));
leaveButton->clicked().connect(this, &App::logout);
}
@@ -1153,7 +1159,7 @@ void App::logout() {
}
void App::addHistoryButton() {
auto history = menuContainer_->addNew<Wt::WPushButton>("History");
auto history = menuContainer_->addNew<Wt::WPushButton>(Wt::WString::tr("menu_history"));
history->clicked().connect(this, &App::requestHistory);
}
@@ -1173,12 +1179,12 @@ void App::addIdentifier() {
}
void App::addSearchButton() {
auto searchButton = menuContainer_->addNew<Wt::WPushButton>("Search");
auto searchButton = menuContainer_->addNew<Wt::WPushButton>(Wt::WString::tr("menu_search"));
searchButton->clicked().connect(this, &App::showSearchWindow);
}
void App::addInboxButton() {
inbox_ = menuContainer_->addNew<Wt::WPushButton>("Inbox");
inbox_ = menuContainer_->addNew<Wt::WPushButton>(Wt::WString::tr("menu_inbox"));
inbox_->clicked().connect(this, &App::openInbox);
}
@@ -1330,14 +1336,14 @@ void App::requestHistory() {
void App::showHistory(Wt::Json::Object broadcast) {
try {
contentContainer_->clear();
auto headerWidget = contentContainer_->addNew<Wt::WText>("<h2>Conversations with already logged in users</h2>");
auto headerWidget = contentContainer_->addNew<Wt::WText>(Wt::WString::tr("history_title"), Wt::TextFormat::UnsafeXHTML);
headerWidget->setInline(false);
auto listWidget = contentContainer_->addNew<Wt::WTable>();
auto dataArray = (Wt::Json::Array)broadcast["data"];
if (dataArray.empty()) {
// Keine bisherigen Unterhaltungen vorhanden
contentContainer_->addNew<Wt::WText>("No previous conversations available.");
contentContainer_->addNew<Wt::WText>(Wt::WString::tr("history_empty"));
} else {
for (Wt::Json::Object user: dataArray) {
auto userName = std::make_shared<std::string>((std::string)user["name"]);
@@ -1378,7 +1384,7 @@ void App::addLoginTimeView() {
elapsedTimeStream << std::setw(2) << std::setfill('0') << hours << ":"
<< std::setw(2) << std::setfill('0') << minutes << " h";
std::string elapsedTimeString = elapsedTimeStream.str();
loggedinTimeWidget->setText(Wt::WString("In chat for {1}").arg(elapsedTimeString));
loggedinTimeWidget->setText(Wt::WString::tr("menu_in_chat_for").arg(elapsedTimeString));
};
loginTimer_->timeout().connect(loggedInRefresh);
loggedInRefresh();
@@ -1398,7 +1404,7 @@ void App::addTimeoutView() {
remainingTimeStream << std::setw(2) << std::setfill('0') << minutes << ":"
<< std::setw(2) << std::setfill('0') << seconds << " m";
std::string elapsedTimeString = remainingTimeStream.str();
timeoutRemainingWidget->setText(Wt::WString("Timeout in {1}").arg(elapsedTimeString));
timeoutRemainingWidget->setText(Wt::WString::tr("menu_timeout_in").arg(elapsedTimeString));
};
timeoutRemainingTimer_->timeout().connect(timeoutRemainingRefresh);
timeoutRemainingRefresh();