XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

SpaceNinjaServer

A simple server for a small space ninja game

公开
关注 0 Fork 1 Star 0
返回提交历史

XFEstudio/SpaceNinjaServer

feat(webui): "broadcast inbox message" for admins (#3987)

Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/3987 Reviewed-by: Sainan <63328889+sainan@users.noreply.github.com> Co-authored-by: Drake <kuzuriyager@gmail.com> Co-committed-by: Drake <kuzuriyager@gmail.com>

00cece0f
Drake <kuzuriyager@gmail.com>
提交于

代码差异

10 个文件 +347 -3
Modified src/controllers/custom/createMessageController.ts +10 -3
@@ -1,15 +1,22 @@
1 1 import type { IMessageCreationTemplate } from "../../services/inboxService.ts";
2 2 import { createMessage } from "../../services/inboxService.ts";
3 import { getAccountForRequest, isAdministrator } from "../../services/loginService.ts";
3 4 import type { RequestHandler } from "express";
4 5
5 6 export const createMessageController: RequestHandler = async (req, res) => {
6 7 const message = req.body as (IMessageCreationTemplate & { ownerId: string })[] | undefined;
7 8
8 if (!message) {
9 const account = await getAccountForRequest(req);
10 if (!isAdministrator(account)) {
11 res.status(401).end();
12 return;
13 }
14
15 if (!Array.isArray(message) || message.length === 0) {
9 16 res.status(400).send("No message provided");
10 17 return;
11 18 }
12 const savedMessages = await createMessage(message[0].ownerId, message);
19 await createMessage(message[0].ownerId, message);
13 20
14 res.json(savedMessages);
21 res.status(204).end();
15 22 };
Modified static/webui/index.html +47 -0
@@ -1731,6 +1731,53 @@
1731 1731 </table>
1732 1732 </div>
1733 1733 </div>
1734 <div class="card mt-3">
1735 <h5 class="card-header" data-loc="admin_broadcastInbox"></h5>
1736 <div class="card-body">
1737 <div class="row g-2 mb-2">
1738 <div class="col-md-4">
1739 <label class="form-label" for="admin-message-target-mode" data-loc="admin_messageTargetMode"></label>
1740 <select class="form-select" id="admin-message-target-mode" onchange="onAdminMessageTargetModeChange();">
1741 <option value="all" data-loc="admin_messageTargetAll"></option>
1742 <option value="specific" data-loc="admin_messageTargetSpecific"></option>
1743 </select>
1744 </div>
1745 <div class="col-md-8 d-none" id="admin-message-target-value-group">
1746 <label class="form-label" for="admin-message-target-value" data-loc="admin_messageTargetValue"></label>
1747 <input class="form-control" id="admin-message-target-value" />
1748 </div>
1749 </div>
1750 <div class="mb-2">
1751 <label class="form-label" for="admin-message-sender" data-loc="admin_messageSender"></label>
1752 <input class="form-control" id="admin-message-sender" value="/Lotus/Language/Bosses/Ordis" />
1753 </div>
1754 <div class="mb-2">
1755 <label class="form-label" for="admin-message-subject" data-loc="admin_messageSubject"></label>
1756 <input class="form-control" id="admin-message-subject" />
1757 </div>
1758 <div class="mb-2">
1759 <label class="form-label" for="admin-message-body" data-loc="admin_messageBody"></label>
1760 <textarea class="form-control" id="admin-message-body" rows="4"></textarea>
1761 </div>
1762 <div class="mb-2">
1763 <label class="form-label" for="admin-message-icon" data-loc="admin_messageIcon"></label>
1764 <input class="form-control" id="admin-message-icon" placeholder="/Lotus/Interface/Icons/Npcs/Ordis.png" />
1765 </div>
1766 <div class="mb-2">
1767 <label class="form-label" for="admin-message-att" data-loc="admin_messageAtt"></label>
1768 <textarea class="form-control" id="admin-message-att" rows="3" placeholder="/Lotus/Powersuits/Excalibur/ExcaliburPrime&#10;/Lotus/Weapons/Tenno/Melee/LongSword/SkanaPrime&#10;/Lotus/Weapons/Tenno/Pistol/LatoPrime"></textarea>
1769 </div>
1770 <div class="mb-2">
1771 <label class="form-label" for="admin-message-counted-att" data-loc="admin_messageCountedAtt"></label>
1772 <textarea class="form-control" id="admin-message-counted-att" rows="5" placeholder="[&#10; { &quot;ItemType&quot;: &quot;/Lotus/Types/Items/MiscItems/OxiumAlloy&quot;, &quot;ItemCount&quot;: 1200 },&#10; { &quot;ItemType&quot;: &quot;/Lotus/Types/Items/MiscItems/OxiumAlloy&quot;, &quot;ItemCount&quot;: 1200 }&#10;]"></textarea>
1773 </div>
1774 <div class="form-check mb-3">
1775 <input class="form-check-input" type="checkbox" id="admin-message-high-priority" checked />
1776 <label class="form-check-label" for="admin-message-high-priority"><abbr data-loc="admin_messageHighPriority" data-loc-title="admin_messageHighPriorityHelp"></abbr></label>
1777 </div>
1778 <button class="btn btn-primary" id="admin-broadcast-submit" onclick="doAdminBroadcastInbox();" data-loc="admin_sendInboxMessage"></button>
1779 </div>
1780 </div>
1734 1781 </div>
1735 1782 </div>
1736 1783 </div>
Modified static/webui/script.js +136 -0
@@ -5666,6 +5666,7 @@ single.getRoute("/webui/admin").on("beforeload", function () {
5666 5666 window.is_admin = true;
5667 5667 $(".admin-hide").addClass("d-none");
5668 5668 $(".admin-show").removeClass("d-none");
5669 onAdminMessageTargetModeChange();
5669 5670 document.getElementById("registered-losers").innerHTML = "";
5670 5671 for (const user of users) {
5671 5672 const tr = document.createElement("tr");
@@ -5716,3 +5717,138 @@ single.getRoute("/webui/admin").on("beforeload", function () {
5716 5717 });
5717 5718 });
5718 5719 });
5720
5721 function onAdminMessageTargetModeChange() {
5722 const targetMode = document.getElementById("admin-message-target-mode").value;
5723 document.getElementById("admin-message-target-value-group").classList.toggle("d-none", targetMode !== "specific");
5724 }
5725
5726 function resolveAdminBroadcastTargets(users, targetMode, targetValue) {
5727 if (targetMode === "all") {
5728 return users;
5729 }
5730 const normalizedTargetValue = targetValue.toLowerCase();
5731 const idMatches = users.filter(user => user.id === targetValue);
5732 return idMatches.length > 0
5733 ? idMatches
5734 : users.filter(user => user.DisplayName.toLowerCase() === normalizedTargetValue);
5735 }
5736
5737 function buildAdminBroadcastConfirmMessage(targetMode, targetUsers) {
5738 if (targetMode === "all") {
5739 return loc("admin_sendToAllConfirm");
5740 }
5741 if (targetUsers.length === 1) {
5742 return loc("admin_sendToSpecificConfirmOne")
5743 .replaceAll("|NAME|", targetUsers[0].DisplayName)
5744 .replaceAll("|ID|", targetUsers[0].id);
5745 }
5746 return loc("admin_sendToSpecificConfirmMany").replaceAll("|COUNT|", String(targetUsers.length));
5747 }
5748
5749 function buildAdminInboxPayload(user, fields) {
5750 const payload = [
5751 {
5752 ownerId: user.id,
5753 sndr: fields.sender,
5754 sub: fields.subject,
5755 msg: fields.body,
5756 highPriority: fields.highPriority
5757 }
5758 ];
5759 if (fields.icon) {
5760 payload[0].icon = fields.icon;
5761 }
5762 if (fields.attachments.length > 0) {
5763 payload[0].att = fields.attachments;
5764 }
5765 if (fields.countedAttachments && fields.countedAttachments.length > 0) {
5766 payload[0].countedAtt = fields.countedAttachments;
5767 }
5768 return payload;
5769 }
5770
5771 async function sendAdminInboxMessage(payload) {
5772 await $.ajax({
5773 url: "/custom/createMessage?" + window.authz,
5774 method: "POST",
5775 contentType: "application/json",
5776 data: JSON.stringify(payload)
5777 });
5778 }
5779
5780 async function doAdminBroadcastInbox() {
5781 await revalidateAuthz();
5782 const targetMode = document.getElementById("admin-message-target-mode").value;
5783 const targetValue = document.getElementById("admin-message-target-value").value.trim();
5784 const sender = document.getElementById("admin-message-sender").value.trim();
5785 const subject = document.getElementById("admin-message-subject").value.trim();
5786 const body = document.getElementById("admin-message-body").value.trim();
5787 const icon = document.getElementById("admin-message-icon").value.trim();
5788 const attRaw = document.getElementById("admin-message-att").value;
5789 const countedAttRaw = document.getElementById("admin-message-counted-att").value.trim();
5790 const highPriority = document.getElementById("admin-message-high-priority").checked;
5791 const submitButton = document.getElementById("admin-broadcast-submit");
5792
5793 if (!sender || !subject || !body) {
5794 alert(loc("admin_messageRequiredFields"));
5795 return;
5796 }
5797 if (targetMode === "specific" && !targetValue) {
5798 alert(loc("admin_messageTargetRequired"));
5799 return;
5800 }
5801
5802 let countedAttachments;
5803 if (countedAttRaw) {
5804 try {
5805 countedAttachments = JSON.parse(countedAttRaw);
5806 } catch (_error) {
5807 alert(loc("admin_messageCountedAttInvalid"));
5808 return;
5809 }
5810 if (!Array.isArray(countedAttachments)) {
5811 alert(loc("admin_messageCountedAttInvalid"));
5812 return;
5813 }
5814 }
5815
5816 const attachments = attRaw
5817 .split("\n")
5818 .map(x => x.trim())
5819 .filter(x => x);
5820
5821 submitButton.disabled = true;
5822 try {
5823 const users = await $.get("/custom/getRegisteredLosers?" + window.authz);
5824 const targetUsers = resolveAdminBroadcastTargets(users, targetMode, targetValue);
5825 if (targetUsers.length === 0) {
5826 alert(loc("admin_messageTargetNotFound"));
5827 return;
5828 }
5829
5830 const confirmMsg = buildAdminBroadcastConfirmMessage(targetMode, targetUsers);
5831 if (!window.confirm(confirmMsg)) {
5832 return;
5833 }
5834
5835 const payloadFields = {
5836 sender,
5837 subject,
5838 body,
5839 highPriority,
5840 icon,
5841 attachments,
5842 countedAttachments
5843 };
5844 for (const user of targetUsers) {
5845 const payload = buildAdminInboxPayload(user, payloadFields);
5846 await sendAdminInboxMessage(payload);
5847 }
5848 toast(loc("admin_sendToAllSuccess").replaceAll("|COUNT|", targetUsers.length));
5849 } catch (_error) {
5850 alert(loc("settings_changeFailed"));
5851 } finally {
5852 submitButton.disabled = false;
5853 }
5854 }
Modified static/webui/translations/de.js +22 -0
@@ -545,6 +545,28 @@ dict = {
545 545 navbar_admin: `Admin`,
546 546 admin_users: `Benutzer`,
547 547 admin_possess: `Als Benutzer anmelden`,
548 admin_broadcastInbox: `[UNTRANSLATED] Broadcast Inbox Message`,
549 admin_messageTargetMode: `[UNTRANSLATED] Target`,
550 admin_messageTargetAll: `[UNTRANSLATED] All Users`,
551 admin_messageTargetSpecific: `[UNTRANSLATED] Specific User`,
552 admin_messageTargetValue: `[UNTRANSLATED] Username or Account ID`,
553 admin_messageSender: `[UNTRANSLATED] Sender`,
554 admin_messageSubject: `[UNTRANSLATED] Subject`,
555 admin_messageBody: `[UNTRANSLATED] Message`,
556 admin_messageIcon: `[UNTRANSLATED] Icon (optional)`,
557 admin_messageAtt: `[UNTRANSLATED] Attachments (optional, one item type per line)`,
558 admin_messageCountedAtt: `[UNTRANSLATED] Counted Attachments (optional JSON)`,
559 admin_messageHighPriority: `[UNTRANSLATED] High Priority`,
560 admin_messageHighPriorityHelp: `[UNTRANSLATED] High priority messages cause the inbox to open automatically.`,
561 admin_sendInboxMessage: `[UNTRANSLATED] Send Inbox Message`,
562 admin_sendToAllConfirm: `[UNTRANSLATED] Are you sure you want to send this inbox message to all users?`,
563 admin_sendToSpecificConfirmOne: `[UNTRANSLATED] Send this inbox message to "|NAME|" (|ID|)?`,
564 admin_sendToSpecificConfirmMany: `[UNTRANSLATED] Send this inbox message to |COUNT| matching accounts?`,
565 admin_sendToAllSuccess: `[UNTRANSLATED] Successfully sent inbox message to |COUNT| user(s).`,
566 admin_messageRequiredFields: `[UNTRANSLATED] Sender, subject, and message are required.`,
567 admin_messageCountedAttInvalid: `[UNTRANSLATED] Counted attachments must be valid JSON array.`,
568 admin_messageTargetRequired: `[UNTRANSLATED] Username or account id is required for Specific User.`,
569 admin_messageTargetNotFound: `[UNTRANSLATED] No user matched that username or account id.`,
548 570
549 571 AVATAR_ABILITY_DURATION: `Dauer`,
550 572 AVATAR_ABILITY_EFFICIENCY: `Effizienz`,
Modified static/webui/translations/en.js +22 -0
@@ -544,6 +544,28 @@ dict = {
544 544 navbar_admin: `Admin`,
545 545 admin_users: `Users`,
546 546 admin_possess: `Impersonate`,
547 admin_broadcastInbox: `Broadcast Inbox Message`,
548 admin_messageTargetMode: `Target`,
549 admin_messageTargetAll: `All Users`,
550 admin_messageTargetSpecific: `Specific User`,
551 admin_messageTargetValue: `Username or Account ID`,
552 admin_messageSender: `Sender`,
553 admin_messageSubject: `Subject`,
554 admin_messageBody: `Message`,
555 admin_messageIcon: `Icon (optional)`,
556 admin_messageAtt: `Attachments (optional, one item type per line)`,
557 admin_messageCountedAtt: `Counted Attachments (optional JSON)`,
558 admin_messageHighPriority: `High Priority`,
559 admin_messageHighPriorityHelp: `High priority messages cause the inbox to open automatically.`,
560 admin_sendInboxMessage: `Send Inbox Message`,
561 admin_sendToAllConfirm: `Are you sure you want to send this inbox message to all users?`,
562 admin_sendToSpecificConfirmOne: `Send this inbox message to "|NAME|" (|ID|)?`,
563 admin_sendToSpecificConfirmMany: `Send this inbox message to |COUNT| matching accounts?`,
564 admin_sendToAllSuccess: `Successfully sent inbox message to |COUNT| user(s).`,
565 admin_messageRequiredFields: `Sender, subject, and message are required.`,
566 admin_messageCountedAttInvalid: `Counted attachments must be valid JSON array.`,
567 admin_messageTargetRequired: `Username or account id is required for Specific User.`,
568 admin_messageTargetNotFound: `No user matched that username or account id.`,
547 569
548 570 AVATAR_ABILITY_DURATION: `Duration`,
549 571 AVATAR_ABILITY_EFFICIENCY: `Efficiency`,
Modified static/webui/translations/es.js +22 -0
@@ -545,6 +545,28 @@ dict = {
545 545 navbar_admin: `[UNTRANSLATED] Admin`,
546 546 admin_users: `[UNTRANSLATED] Users`,
547 547 admin_possess: `[UNTRANSLATED] Impersonate`,
548 admin_broadcastInbox: `[UNTRANSLATED] Broadcast Inbox Message`,
549 admin_messageTargetMode: `[UNTRANSLATED] Target`,
550 admin_messageTargetAll: `[UNTRANSLATED] All Users`,
551 admin_messageTargetSpecific: `[UNTRANSLATED] Specific User`,
552 admin_messageTargetValue: `[UNTRANSLATED] Username or Account ID`,
553 admin_messageSender: `[UNTRANSLATED] Sender`,
554 admin_messageSubject: `[UNTRANSLATED] Subject`,
555 admin_messageBody: `[UNTRANSLATED] Message`,
556 admin_messageIcon: `[UNTRANSLATED] Icon (optional)`,
557 admin_messageAtt: `[UNTRANSLATED] Attachments (optional, one item type per line)`,
558 admin_messageCountedAtt: `[UNTRANSLATED] Counted Attachments (optional JSON)`,
559 admin_messageHighPriority: `[UNTRANSLATED] High Priority`,
560 admin_messageHighPriorityHelp: `[UNTRANSLATED] High priority messages cause the inbox to open automatically.`,
561 admin_sendInboxMessage: `[UNTRANSLATED] Send Inbox Message`,
562 admin_sendToAllConfirm: `[UNTRANSLATED] Are you sure you want to send this inbox message to all users?`,
563 admin_sendToSpecificConfirmOne: `[UNTRANSLATED] Send this inbox message to "|NAME|" (|ID|)?`,
564 admin_sendToSpecificConfirmMany: `[UNTRANSLATED] Send this inbox message to |COUNT| matching accounts?`,
565 admin_sendToAllSuccess: `[UNTRANSLATED] Successfully sent inbox message to |COUNT| user(s).`,
566 admin_messageRequiredFields: `[UNTRANSLATED] Sender, subject, and message are required.`,
567 admin_messageCountedAttInvalid: `[UNTRANSLATED] Counted attachments must be valid JSON array.`,
568 admin_messageTargetRequired: `[UNTRANSLATED] Username or account id is required for Specific User.`,
569 admin_messageTargetNotFound: `[UNTRANSLATED] No user matched that username or account id.`,
548 570
549 571 AVATAR_ABILITY_DURATION: `Duración`,
550 572 AVATAR_ABILITY_EFFICIENCY: `Eficiencia`,
Modified static/webui/translations/fr.js +22 -0
@@ -545,6 +545,28 @@ dict = {
545 545 navbar_admin: `Administrateur`,
546 546 admin_users: `Utilisateurs`,
547 547 admin_possess: `[UNTRANSLATED] Impersonate`,
548 admin_broadcastInbox: `[UNTRANSLATED] Broadcast Inbox Message`,
549 admin_messageTargetMode: `[UNTRANSLATED] Target`,
550 admin_messageTargetAll: `[UNTRANSLATED] All Users`,
551 admin_messageTargetSpecific: `[UNTRANSLATED] Specific User`,
552 admin_messageTargetValue: `[UNTRANSLATED] Username or Account ID`,
553 admin_messageSender: `[UNTRANSLATED] Sender`,
554 admin_messageSubject: `[UNTRANSLATED] Subject`,
555 admin_messageBody: `[UNTRANSLATED] Message`,
556 admin_messageIcon: `[UNTRANSLATED] Icon (optional)`,
557 admin_messageAtt: `[UNTRANSLATED] Attachments (optional, one item type per line)`,
558 admin_messageCountedAtt: `[UNTRANSLATED] Counted Attachments (optional JSON)`,
559 admin_messageHighPriority: `[UNTRANSLATED] High Priority`,
560 admin_messageHighPriorityHelp: `[UNTRANSLATED] High priority messages cause the inbox to open automatically.`,
561 admin_sendInboxMessage: `[UNTRANSLATED] Send Inbox Message`,
562 admin_sendToAllConfirm: `[UNTRANSLATED] Are you sure you want to send this inbox message to all users?`,
563 admin_sendToSpecificConfirmOne: `[UNTRANSLATED] Send this inbox message to "|NAME|" (|ID|)?`,
564 admin_sendToSpecificConfirmMany: `[UNTRANSLATED] Send this inbox message to |COUNT| matching accounts?`,
565 admin_sendToAllSuccess: `[UNTRANSLATED] Successfully sent inbox message to |COUNT| user(s).`,
566 admin_messageRequiredFields: `[UNTRANSLATED] Sender, subject, and message are required.`,
567 admin_messageCountedAttInvalid: `[UNTRANSLATED] Counted attachments must be valid JSON array.`,
568 admin_messageTargetRequired: `[UNTRANSLATED] Username or account id is required for Specific User.`,
569 admin_messageTargetNotFound: `[UNTRANSLATED] No user matched that username or account id.`,
548 570
549 571 AVATAR_ABILITY_DURATION: `Durée`,
550 572 AVATAR_ABILITY_EFFICIENCY: `Efficacité`,
Modified static/webui/translations/ru.js +22 -0
@@ -545,6 +545,28 @@ dict = {
545 545 navbar_admin: `Админ`,
546 546 admin_users: `Пользователи`,
547 547 admin_possess: `Дейстовать от имени`,
548 admin_broadcastInbox: `[UNTRANSLATED] Broadcast Inbox Message`,
549 admin_messageTargetMode: `[UNTRANSLATED] Target`,
550 admin_messageTargetAll: `[UNTRANSLATED] All Users`,
551 admin_messageTargetSpecific: `[UNTRANSLATED] Specific User`,
552 admin_messageTargetValue: `[UNTRANSLATED] Username or Account ID`,
553 admin_messageSender: `[UNTRANSLATED] Sender`,
554 admin_messageSubject: `[UNTRANSLATED] Subject`,
555 admin_messageBody: `[UNTRANSLATED] Message`,
556 admin_messageIcon: `[UNTRANSLATED] Icon (optional)`,
557 admin_messageAtt: `[UNTRANSLATED] Attachments (optional, one item type per line)`,
558 admin_messageCountedAtt: `[UNTRANSLATED] Counted Attachments (optional JSON)`,
559 admin_messageHighPriority: `[UNTRANSLATED] High Priority`,
560 admin_messageHighPriorityHelp: `[UNTRANSLATED] High priority messages cause the inbox to open automatically.`,
561 admin_sendInboxMessage: `[UNTRANSLATED] Send Inbox Message`,
562 admin_sendToAllConfirm: `[UNTRANSLATED] Are you sure you want to send this inbox message to all users?`,
563 admin_sendToSpecificConfirmOne: `[UNTRANSLATED] Send this inbox message to "|NAME|" (|ID|)?`,
564 admin_sendToSpecificConfirmMany: `[UNTRANSLATED] Send this inbox message to |COUNT| matching accounts?`,
565 admin_sendToAllSuccess: `[UNTRANSLATED] Successfully sent inbox message to |COUNT| user(s).`,
566 admin_messageRequiredFields: `[UNTRANSLATED] Sender, subject, and message are required.`,
567 admin_messageCountedAttInvalid: `[UNTRANSLATED] Counted attachments must be valid JSON array.`,
568 admin_messageTargetRequired: `[UNTRANSLATED] Username or account id is required for Specific User.`,
569 admin_messageTargetNotFound: `[UNTRANSLATED] No user matched that username or account id.`,
548 570
549 571 AVATAR_ABILITY_DURATION: `Длительность`,
550 572 AVATAR_ABILITY_EFFICIENCY: `Эффективность`,
Modified static/webui/translations/uk.js +22 -0
@@ -545,6 +545,28 @@ dict = {
545 545 navbar_admin: `[UNTRANSLATED] Admin`,
546 546 admin_users: `[UNTRANSLATED] Users`,
547 547 admin_possess: `[UNTRANSLATED] Impersonate`,
548 admin_broadcastInbox: `[UNTRANSLATED] Broadcast Inbox Message`,
549 admin_messageTargetMode: `[UNTRANSLATED] Target`,
550 admin_messageTargetAll: `[UNTRANSLATED] All Users`,
551 admin_messageTargetSpecific: `[UNTRANSLATED] Specific User`,
552 admin_messageTargetValue: `[UNTRANSLATED] Username or Account ID`,
553 admin_messageSender: `[UNTRANSLATED] Sender`,
554 admin_messageSubject: `[UNTRANSLATED] Subject`,
555 admin_messageBody: `[UNTRANSLATED] Message`,
556 admin_messageIcon: `[UNTRANSLATED] Icon (optional)`,
557 admin_messageAtt: `[UNTRANSLATED] Attachments (optional, one item type per line)`,
558 admin_messageCountedAtt: `[UNTRANSLATED] Counted Attachments (optional JSON)`,
559 admin_messageHighPriority: `[UNTRANSLATED] High Priority`,
560 admin_messageHighPriorityHelp: `[UNTRANSLATED] High priority messages cause the inbox to open automatically.`,
561 admin_sendInboxMessage: `[UNTRANSLATED] Send Inbox Message`,
562 admin_sendToAllConfirm: `[UNTRANSLATED] Are you sure you want to send this inbox message to all users?`,
563 admin_sendToSpecificConfirmOne: `[UNTRANSLATED] Send this inbox message to "|NAME|" (|ID|)?`,
564 admin_sendToSpecificConfirmMany: `[UNTRANSLATED] Send this inbox message to |COUNT| matching accounts?`,
565 admin_sendToAllSuccess: `[UNTRANSLATED] Successfully sent inbox message to |COUNT| user(s).`,
566 admin_messageRequiredFields: `[UNTRANSLATED] Sender, subject, and message are required.`,
567 admin_messageCountedAttInvalid: `[UNTRANSLATED] Counted attachments must be valid JSON array.`,
568 admin_messageTargetRequired: `[UNTRANSLATED] Username or account id is required for Specific User.`,
569 admin_messageTargetNotFound: `[UNTRANSLATED] No user matched that username or account id.`,
548 570
549 571 AVATAR_ABILITY_DURATION: `Тривалість`,
550 572 AVATAR_ABILITY_EFFICIENCY: `Ощадливість`,
Modified static/webui/translations/zh.js +22 -0
@@ -545,6 +545,28 @@ dict = {
545 545 navbar_admin: `管理员`,
546 546 admin_users: `用户`,
547 547 admin_possess: `管理此账户`,
548 admin_broadcastInbox: `[UNTRANSLATED] Broadcast Inbox Message`,
549 admin_messageTargetMode: `[UNTRANSLATED] Target`,
550 admin_messageTargetAll: `[UNTRANSLATED] All Users`,
551 admin_messageTargetSpecific: `[UNTRANSLATED] Specific User`,
552 admin_messageTargetValue: `[UNTRANSLATED] Username or Account ID`,
553 admin_messageSender: `[UNTRANSLATED] Sender`,
554 admin_messageSubject: `[UNTRANSLATED] Subject`,
555 admin_messageBody: `[UNTRANSLATED] Message`,
556 admin_messageIcon: `[UNTRANSLATED] Icon (optional)`,
557 admin_messageAtt: `[UNTRANSLATED] Attachments (optional, one item type per line)`,
558 admin_messageCountedAtt: `[UNTRANSLATED] Counted Attachments (optional JSON)`,
559 admin_messageHighPriority: `[UNTRANSLATED] High Priority`,
560 admin_messageHighPriorityHelp: `[UNTRANSLATED] High priority messages cause the inbox to open automatically.`,
561 admin_sendInboxMessage: `[UNTRANSLATED] Send Inbox Message`,
562 admin_sendToAllConfirm: `[UNTRANSLATED] Are you sure you want to send this inbox message to all users?`,
563 admin_sendToSpecificConfirmOne: `[UNTRANSLATED] Send this inbox message to "|NAME|" (|ID|)?`,
564 admin_sendToSpecificConfirmMany: `[UNTRANSLATED] Send this inbox message to |COUNT| matching accounts?`,
565 admin_sendToAllSuccess: `[UNTRANSLATED] Successfully sent inbox message to |COUNT| user(s).`,
566 admin_messageRequiredFields: `[UNTRANSLATED] Sender, subject, and message are required.`,
567 admin_messageCountedAttInvalid: `[UNTRANSLATED] Counted attachments must be valid JSON array.`,
568 admin_messageTargetRequired: `[UNTRANSLATED] Username or account id is required for Specific User.`,
569 admin_messageTargetNotFound: `[UNTRANSLATED] No user matched that username or account id.`,
548 570
549 571 AVATAR_ABILITY_DURATION: `持续时间`,
550 572 AVATAR_ABILITY_EFFICIENCY: `效率`,