From 75815fa0227696707d40283ceaebfa635ddde8f3 Mon Sep 17 00:00:00 2001 From: simoleo89 Date: Wed, 20 May 2026 21:02:22 +0200 Subject: [PATCH] i18n(mod-tools): route every label/title/placeholder through LocalizeText MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ModTools template refresh introduced ~80 hardcoded English strings (labels, placeholders, tooltips, empty-state copy, button text). Move every one of them onto the modtools.* namespace and read via LocalizeText so the panels translate alongside the rest of the client. UITexts.example (versioned template) extended with the full set: modtools.window.* Launcher box (toolbar item, tools, selected-user state, ticket count) modtools.userinfo.* User info card — already had the legacy modtools.userinfo.{userName, cfhCount, …} keys from before; added refresh tooltip, presence pill labels (in_room / online / offline with matching .title tooltips), section headings, action button labels, stat card labels modtools.roominfo.* Room info card — title, refresh, loading, owner pill (here/away + tooltips), stat labels, action buttons, moderate panel heading + checkboxes + textarea placeholder + caution/alert CTAs modtools.user.message.* Send-message dialog (recipient label, body label, placeholder, char counter, empty state, send button) modtools.user.modaction.* Mod Action form — header, sanctioning label, 3-step section titles, select placeholders, message label + optional note, message placeholder, preview heading, default/apply buttons, every sendAlert error message modtools.user.visits.* Room visits — title, header strip heading, entry count (singular/plural), empty state, column headers, visit button + tooltip modtools.user.chatlog.* User chatlog — title (with username variant), loading state modtools.room.chatlog.* Room chatlog title modtools.chatlog.* Shared ChatlogView — column headers, empty state, room-separator Visit/Tools buttons modtools.tickets.* Tickets window — title, tab labels (open/mine/picked), column headers, empty states, action buttons (pick/ handle/release), issue resolution window (title, label, details heading, field labels, chatlog toggle, resolve-as heading, resolution buttons, release back to queue), CFH chatlog title The same 130 entries land in Nitro-Files/.../UITexts.json (runtime). Both files validate as JSON. The runtime additions take effect on next client reload; the template additions ship the strings to any fresh deploy. Notes: - The MOD_ACTION_DEFINITIONS sanction names ("Alert", "Mute 1h", "Ban 18h" …) stay hardcoded for now since they're keyed off server-side action IDs that don't have an existing locale key convention. Worth a follow-up if needed. - help.cfh.topic.* keys (CFH topic display names) are already in ExternalTexts.json and were already read via LocalizeText, so they didn't need changes. typecheck + vitest 214/214 + lint:hooks all clean. --- public/configuration/UITexts.example | 138 ++++++++++++++++++ src/components/mod-tools/ModToolsView.tsx | 18 +-- .../mod-tools/views/chatlog/ChatlogView.tsx | 14 +- .../views/room/ModToolsChatlogView.tsx | 3 +- .../mod-tools/views/room/ModToolsRoomView.tsx | 38 ++--- .../views/tickets/CfhChatlogView.tsx | 5 +- .../views/tickets/ModToolsIssueInfoView.tsx | 28 ++-- .../views/tickets/ModToolsMyIssuesTabView.tsx | 14 +- .../tickets/ModToolsOpenIssuesTabView.tsx | 12 +- .../tickets/ModToolsPickedIssuesTabView.tsx | 12 +- .../views/tickets/ModToolsTicketsView.tsx | 9 +- .../views/user/ModToolsUserChatlogView.tsx | 6 +- .../views/user/ModToolsUserModActionView.tsx | 42 +++--- .../views/user/ModToolsUserRoomVisitsView.tsx | 24 +-- .../user/ModToolsUserSendMessageView.tsx | 14 +- .../mod-tools/views/user/ModToolsUserView.tsx | 53 ++++--- 16 files changed, 291 insertions(+), 139 deletions(-) diff --git a/public/configuration/UITexts.example b/public/configuration/UITexts.example index acf246e..63077be 100644 --- a/public/configuration/UITexts.example +++ b/public/configuration/UITexts.example @@ -98,6 +98,144 @@ "catalog.prefix.price.amount": "5 Credits", "catalog.prefix.purchased": "? Purchased!", "catalog.prefix.purchase": "Purchase", + "modtools.userinfo.title": "User Info: %username%", + "modtools.userinfo.userName": "Name", + "modtools.userinfo.cfhCount": "CFHs", + "modtools.userinfo.abusiveCfhCount": "Abusive CFHs", + "modtools.userinfo.cautionCount": "Cautions", + "modtools.userinfo.banCount": "Bans", + "modtools.userinfo.lastSanctionTime": "Last Sanction", + "modtools.userinfo.tradingLockCount": "Trade Locks", + "modtools.userinfo.tradingExpiryDate": "Lock Expires", + "modtools.userinfo.minutesSinceLastLogin": "Last Login", + "modtools.userinfo.lastPurchaseDate": "Last Purchase", + "modtools.userinfo.primaryEmailAddress": "Email", + "modtools.userinfo.identityRelatedBanCount": "Banned Accs", + "modtools.userinfo.registrationAgeInMinutes": "Registered", + "modtools.userinfo.userClassification": "Rank", + "modtools.window.title": "Mod Tools", + "modtools.window.tools.room": "Room Tool", + "modtools.window.tools.chatlog": "Chatlog Tool", + "modtools.window.tools.report": "Report Tool", + "modtools.window.select.user": "Select a user", + "modtools.window.no.room": "Enter a room first", + "modtools.window.user.in_room": "Still in this room", + "modtools.window.user.left_room": "No longer in this room", + "modtools.window.user.clear": "Clear selection", + "modtools.window.tickets.open": "%count% open ticket", + "modtools.window.tickets.open.many": "%count% open tickets", + "modtools.userinfo.refresh": "Refresh user info", + "modtools.userinfo.presence.in_room": "In room", + "modtools.userinfo.presence.in_room.title": "In the room you are observing", + "modtools.userinfo.presence.online": "Online", + "modtools.userinfo.presence.online.title": "Online on the hotel", + "modtools.userinfo.presence.offline": "Offline", + "modtools.userinfo.presence.offline.title": "Offline at panel open", + "modtools.userinfo.section.account": "Account", + "modtools.userinfo.section.activity": "Activity", + "modtools.userinfo.section.sanctions": "Sanctions", + "modtools.userinfo.section.trading": "Trading", + "modtools.userinfo.button.room.chat": "Room Chat", + "modtools.userinfo.button.send.message": "Send Message", + "modtools.userinfo.button.room.visits": "Room Visits", + "modtools.userinfo.button.mod.action": "Mod Action", + "modtools.userinfo.stat.cfh": "CFH", + "modtools.userinfo.stat.cautions": "Cautions", + "modtools.userinfo.stat.bans": "Bans", + "modtools.userinfo.stat.trade.locks": "Trade locks", + "modtools.roominfo.title": "Room Info", + "modtools.roominfo.refresh": "Refresh room info", + "modtools.roominfo.loading": "Loading…", + "modtools.roominfo.owner.here": "Owner here", + "modtools.roominfo.owner.away": "Owner away", + "modtools.roominfo.owner.title.here": "The room owner is currently inside", + "modtools.roominfo.owner.title.away": "The room owner is NOT inside", + "modtools.roominfo.stat.users": "Users", + "modtools.roominfo.stat.owner": "Owner", + "modtools.roominfo.owner.open": "Open %username%'s info", + "modtools.roominfo.button.visit": "Visit Room", + "modtools.roominfo.button.chatlog": "Chatlog", + "modtools.roominfo.moderate.title": "Moderate room", + "modtools.roominfo.moderate.kick": "Kick everyone out", + "modtools.roominfo.moderate.doorbell": "Enable the doorbell", + "modtools.roominfo.moderate.rename": "Change room name", + "modtools.roominfo.moderate.message.placeholder": "Mandatory message to deliver with the action…", + "modtools.roominfo.moderate.send.caution": "Send Caution", + "modtools.roominfo.moderate.send.alert": "Send Alert", + "modtools.user.message.title": "Send Message", + "modtools.user.message.recipient": "Message to", + "modtools.user.message.label": "Message", + "modtools.user.message.placeholder": "Write something useful — the user will see it as a moderator message.", + "modtools.user.message.empty": "Empty", + "modtools.user.message.chars": "%count% chars", + "modtools.user.message.send": "Send Message", + "modtools.user.modaction.title": "Mod Action: %username%", + "modtools.user.modaction.sanctioning": "Sanctioning", + "modtools.user.modaction.step.topic": "1. CFH Topic", + "modtools.user.modaction.step.topic.placeholder": "Select a topic…", + "modtools.user.modaction.step.sanction": "2. Sanction", + "modtools.user.modaction.step.sanction.placeholder": "Select a sanction…", + "modtools.user.modaction.step.message": "3. Custom message", + "modtools.user.modaction.step.message.optional": "(optional — overrides default)", + "modtools.user.modaction.message.placeholder": "Leave empty to use the default topic message", + "modtools.user.modaction.preview": "Preview", + "modtools.user.modaction.button.default": "Default Sanction", + "modtools.user.modaction.button.apply": "Apply Sanction", + "modtools.user.modaction.error.no.topic": "You must select a CFH topic", + "modtools.user.modaction.error.no.action": "You must select a CFH topic and Sanction", + "modtools.user.modaction.error.no.permission": "You do not have permission to do this", + "modtools.user.modaction.error.no.message": "Please write a message to user", + "modtools.user.modaction.error.no.permission.alert": "You have insufficient permissions", + "modtools.user.visits.title": "User Visits", + "modtools.user.visits.recent": "Recent visited rooms", + "modtools.user.visits.entries.one": "%count% entry", + "modtools.user.visits.entries.many": "%count% entries", + "modtools.user.visits.empty": "No recent visits", + "modtools.user.visits.time": "Time", + "modtools.user.visits.room": "Room name", + "modtools.user.visits.action": "Action", + "modtools.user.visits.visit": "Visit", + "modtools.user.visits.visit.title": "Visit room", + "modtools.user.chatlog.title": "User Chatlog", + "modtools.user.chatlog.title.with": "User Chatlog: %username%", + "modtools.user.chatlog.loading": "Loading chatlog…", + "modtools.room.chatlog.title": "Room Chatlog", + "modtools.chatlog.column.time": "Time", + "modtools.chatlog.column.user": "User", + "modtools.chatlog.column.message": "Message", + "modtools.chatlog.empty": "No messages", + "modtools.chatlog.visit": "Visit", + "modtools.chatlog.tools": "Tools", + "modtools.tickets.title": "Tickets", + "modtools.tickets.tab.open": "Open", + "modtools.tickets.tab.mine": "Mine", + "modtools.tickets.tab.picked": "All picked", + "modtools.tickets.column.type": "Type", + "modtools.tickets.column.reported": "Reported", + "modtools.tickets.column.opened": "Opened", + "modtools.tickets.column.picker": "Picker", + "modtools.tickets.empty.open": "No open issues", + "modtools.tickets.empty.mine": "No issues picked by you", + "modtools.tickets.empty.picked": "No picked issues", + "modtools.tickets.action.pick": "Pick", + "modtools.tickets.action.handle": "Handle", + "modtools.tickets.action.release": "Release", + "modtools.tickets.issue.title": "Resolving issue #%issueId%", + "modtools.tickets.issue.label": "Issue #%issueId%", + "modtools.tickets.issue.details": "Details", + "modtools.tickets.issue.field.source": "Source", + "modtools.tickets.issue.field.category": "Category", + "modtools.tickets.issue.field.description": "Description", + "modtools.tickets.issue.field.caller": "Caller", + "modtools.tickets.issue.field.reported": "Reported", + "modtools.tickets.issue.chatlog.view": "View chatlog", + "modtools.tickets.issue.chatlog.close": "Close chatlog", + "modtools.tickets.issue.resolve.heading": "Resolve as", + "modtools.tickets.issue.resolve.resolved": "Resolved", + "modtools.tickets.issue.resolve.useless": "Useless", + "modtools.tickets.issue.resolve.abusive": "Abusive", + "modtools.tickets.issue.release": "Release back to queue", + "modtools.tickets.cfh.chatlog.title": "Issue #%issueId% Chatlog", "groupforum.list.tab.most_active": "Most active threads", "groupforum.list.tab.my_forums": "My group forums", "groupforum.list.no_forums": "There are no forums", diff --git a/src/components/mod-tools/ModToolsView.tsx b/src/components/mod-tools/ModToolsView.tsx index 181eb0c..ac9bd82 100644 --- a/src/components/mod-tools/ModToolsView.tsx +++ b/src/components/mod-tools/ModToolsView.tsx @@ -143,15 +143,15 @@ export const ModToolsView: FC<{}> = props => <> { isVisible && - setIsVisible(false) } /> + setIsVisible(false) } /> diff --git a/src/components/mod-tools/views/chatlog/ChatlogView.tsx b/src/components/mod-tools/views/chatlog/ChatlogView.tsx index 118d9d8..ffd489e 100644 --- a/src/components/mod-tools/views/chatlog/ChatlogView.tsx +++ b/src/components/mod-tools/views/chatlog/ChatlogView.tsx @@ -1,7 +1,7 @@ import { ChatRecordData, CreateLinkEvent } from '@nitrots/nitro-renderer'; import { FC, useMemo } from 'react'; import { FaCommentDots, FaDoorOpen, FaSignInAlt, FaTools } from 'react-icons/fa'; -import { TryVisitRoom } from '../../../../api'; +import { LocalizeText, TryVisitRoom } from '../../../../api'; import { Column, InfiniteScroll } from '../../../../common'; import { useModTools } from '../../../../hooks'; import { ChatlogRecord } from './ChatlogRecord'; @@ -57,12 +57,12 @@ export const ChatlogView: FC = props => @@ -74,14 +74,14 @@ export const ChatlogView: FC = props => {/* Column headers */}
-
Time
-
User
-
Message
+
{ LocalizeText('modtools.chatlog.column.time') }
+
{ LocalizeText('modtools.chatlog.column.user') }
+
{ LocalizeText('modtools.chatlog.column.message') }
{ isEmpty ?
- No messages + { LocalizeText('modtools.chatlog.empty') }
: { diff --git a/src/components/mod-tools/views/room/ModToolsChatlogView.tsx b/src/components/mod-tools/views/room/ModToolsChatlogView.tsx index f668301..bbe21f7 100644 --- a/src/components/mod-tools/views/room/ModToolsChatlogView.tsx +++ b/src/components/mod-tools/views/room/ModToolsChatlogView.tsx @@ -1,5 +1,6 @@ import { ChatRecordData, GetRoomChatlogMessageComposer, RoomChatlogEvent } from '@nitrots/nitro-renderer'; import { FC } from 'react'; +import { LocalizeText } from '../../../../api'; import { useNitroQuery } from '../../../../api/nitro-query'; import { DraggableWindowPosition, NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../common'; import { ChatlogView } from '../chatlog/ChatlogView'; @@ -27,7 +28,7 @@ export const ModToolsChatlogView: FC = props => return ( - + diff --git a/src/components/mod-tools/views/room/ModToolsRoomView.tsx b/src/components/mod-tools/views/room/ModToolsRoomView.tsx index b178141..82ece06 100644 --- a/src/components/mod-tools/views/room/ModToolsRoomView.tsx +++ b/src/components/mod-tools/views/room/ModToolsRoomView.tsx @@ -1,7 +1,7 @@ import { CreateLinkEvent, GetModeratorRoomInfoMessageComposer, ModerateRoomMessageComposer, ModeratorActionMessageComposer, ModeratorRoomInfoEvent } from '@nitrots/nitro-renderer'; import { FC, useEffect, useState } from 'react'; import { FaBullhorn, FaCommentDots, FaDoorOpen, FaExclamationTriangle, FaSignInAlt, FaSync, FaUserShield, FaUsers } from 'react-icons/fa'; -import { SendMessageComposer, TryVisitRoom } from '../../../../api'; +import { LocalizeText, SendMessageComposer, TryVisitRoom } from '../../../../api'; import { Button, DraggableWindowPosition, NitroCardContentView, NitroCardHeaderView, NitroCardView, Text } from '../../../../common'; import { useMessageEvent } from '../../../../hooks'; @@ -80,25 +80,25 @@ export const ModToolsRoomView: FC = props => return ( - onCloseClick() } /> + onCloseClick() } /> {/* Identity header */}
- { name || 'Loading…' } - Room #{ roomId } + { name || LocalizeText('modtools.roominfo.loading') } + #{ roomId }
+ title={ ownerInRoom ? LocalizeText('modtools.roominfo.owner.title.here') : LocalizeText('modtools.roominfo.owner.title.away') }> - { ownerInRoom ? 'Owner here' : 'Owner away' } + { ownerInRoom ? LocalizeText('modtools.roominfo.owner.here') : LocalizeText('modtools.roominfo.owner.away') }
@@ -107,18 +107,18 @@ export const ModToolsRoomView: FC = props =>
- Users + { LocalizeText('modtools.roominfo.stat.users') }
{ usersInRoom }
- Owner + { LocalizeText('modtools.roominfo.stat.owner') }
ownerId && CreateLinkEvent(`mod-tools/open-user-info/${ ownerId }`) } - title={ ownerName ? `Open ${ ownerName }'s info` : '' }> + title={ ownerName ? LocalizeText('modtools.roominfo.owner.open', [ 'username' ], [ ownerName ]) : '' }> { ownerName || '—' }
@@ -127,42 +127,42 @@ export const ModToolsRoomView: FC = props => {/* Quick actions */}
{/* Moderate panel */}
- Moderate room + { LocalizeText('modtools.roominfo.moderate.title') }