mirror of
https://github.com/duckietm/Nitro-V3.git
synced 2026-06-19 15:06:20 +00:00
🆙 Fix texts
This commit is contained in:
@@ -1,258 +1,268 @@
|
||||
{
|
||||
"notification.badge.received": "Nuovo Distintivo!",
|
||||
"wiredfurni.badgereceived.title": "Distintivo ricevuto!",
|
||||
"wiredfurni.badgereceived.body": "Hai appena ricevuto un nuovo Distintivo! Controlla nel tuo Inventario!",
|
||||
"friendlist.search": "Search friends",
|
||||
"purse.seasonal.currency.101": "cash",
|
||||
"widget.chooser.checkall": "Select furniture",
|
||||
"widget.chooser.btn.pickall": "pick up selected items!",
|
||||
"wiredfurni.params.requireall.2": "If one of the selected furni has an avatar",
|
||||
"wiredfurni.params.requireall.3": "If all selected furni have avatars on them",
|
||||
"widget.settings.general": "General",
|
||||
"widget.settings.general.title": "Adjust the default Nitro settings",
|
||||
"widget.settings.volume": "Volume",
|
||||
"widget.settings.interface": "Interface",
|
||||
"widget.settings.interface.title": "Adjust the interface settings",
|
||||
"widget.settings.interface.fps.automatic": "Set FPS to unlimited",
|
||||
"widget.settings.interface.fps.warning": "Setting FPS to unlimited may cause performance issues!",
|
||||
"widget.settings.interface.secondary": "Change the window header color",
|
||||
"widget.settings.interface.reset": "Reset header color to default",
|
||||
"widget.room.chat.hide_pets": "Hide pets",
|
||||
"widget.room.chat.hide_avatars": "Hide avatars",
|
||||
"widget.room.chat.hide_balloon": "Hide speech bubble",
|
||||
"widget.room.chat.show_balloon": "Speech bubble",
|
||||
"widget.room.chat.clear_history": "clear history",
|
||||
"widget.room.youtube.shared": "YouTube is being shared",
|
||||
"widget.room.youtube.open_video": "Open the video",
|
||||
"wiredfurni.tooltip.select.tile": "Select tile",
|
||||
"wiredfurni.tooltip.remove.tile": "Deselect tile",
|
||||
"wiredfurni.tooltip.remove.5x5_tile": "select 5x5 tiles",
|
||||
"wiredfurni.tooltip.remove.clear_tile": "Clear all selections",
|
||||
"wiredfurni.params.furni_neighborhood.group.user": "Players",
|
||||
"wiredfurni.params.furni_neighborhood.group.furni": "Furniture",
|
||||
"wiredfurni.params.selector_option.bot": "No bots",
|
||||
"wiredfurni.params.selector_option.pet": "No pets",
|
||||
"catalog.title": "Catalog",
|
||||
"catalog.favorites": "Favorites",
|
||||
"catalog.favorites.pages": "Pages",
|
||||
"catalog.favorites.furni": "Furni",
|
||||
"catalog.favorites.empty": "No favorites",
|
||||
"catalog.favorites.empty.hint": "Click the heart on furni or the star on pages to add them.",
|
||||
"catalog.admin": "Admin",
|
||||
"catalog.admin.new": "New",
|
||||
"catalog.admin.root": "Root",
|
||||
"catalog.admin.new.root.category": "New root category",
|
||||
"catalog.admin.edit.root": "Edit Root",
|
||||
"catalog.admin.edit": "Edit:",
|
||||
"catalog.admin.edit.page": "Edit Page",
|
||||
"catalog.admin.hidden": "hidden",
|
||||
"catalog.admin.edit.title": "Edit \"%name%\"",
|
||||
"catalog.admin.show": "Show",
|
||||
"catalog.admin.hide": "Hide",
|
||||
"catalog.admin.delete": "Delete",
|
||||
"catalog.admin.delete.title": "Delete \"%name%\"",
|
||||
"catalog.admin.delete.category.confirm": "Delete category \"%name%\" and all its content?",
|
||||
"catalog.admin.delete.page": "Delete page",
|
||||
"catalog.admin.delete.page.confirm": "Delete page \"%name%\"?",
|
||||
"catalog.admin.delete.offer.confirm": "Are you sure you want to delete this offer?",
|
||||
"catalog.admin.create": "Create",
|
||||
"catalog.admin.save": "Save",
|
||||
"catalog.admin.create.subpage": "Create sub-page",
|
||||
"catalog.admin.order": "Order",
|
||||
"catalog.admin.visible": "Visible",
|
||||
"catalog.admin.enabled": "Enabled",
|
||||
"catalog.admin.offer.new": "New Offer",
|
||||
"catalog.admin.offer.edit": "Edit Offer",
|
||||
"catalog.admin.offer.name": "Catalog Name",
|
||||
"catalog.admin.offer.general": "General",
|
||||
"catalog.admin.offer.quantity": "Quantity",
|
||||
"catalog.admin.offer.prices": "Prices",
|
||||
"catalog.admin.offer.credits": "Credits",
|
||||
"catalog.admin.offer.points": "Points",
|
||||
"catalog.admin.offer.points.type": "Points Type",
|
||||
"catalog.admin.offer.options": "Options",
|
||||
"catalog.admin.offer.club.only": "Club Only",
|
||||
"catalog.admin.offer.extradata": "Extra Data (optional)....",
|
||||
"catalog.admin.offer.have.offer": "Multi-discount (have_offer)",
|
||||
"catalog.trophies.title": "Trophies",
|
||||
"catalog.trophies.write.hint": "Write a text for the trophy before purchasing",
|
||||
"catalog.trophies.inscription": "Trophy Inscription",
|
||||
"catalog.trophies.inscription.placeholder": "Write the text that will appear on the trophy...",
|
||||
"catalog.pets.show.colors": "Show colors",
|
||||
"catalog.pets.choose.color": "Choose color",
|
||||
"catalog.pets.choose.breed": "Choose breed",
|
||||
"catalog.pets.back.breeds": "? Breeds",
|
||||
"catalog.prefix.text": "Text",
|
||||
"catalog.prefix.text.placeholder": "Enter text...",
|
||||
"catalog.prefix.icon": "Icon",
|
||||
"catalog.prefix.icon.remove": "Remove icon",
|
||||
"catalog.prefix.effect": "Effect",
|
||||
"catalog.prefix.color": "Color",
|
||||
"catalog.prefix.color.single": "?? Single",
|
||||
"catalog.prefix.color.per.letter": "?? Per Letter",
|
||||
"catalog.prefix.color.hint": "Select a letter, then choose the color. Auto-advances.",
|
||||
"catalog.prefix.color.apply.all.title": "Apply current color to all letters",
|
||||
"catalog.prefix.color.apply.all": "Apply to all",
|
||||
"catalog.prefix.color.selected": "Selected letter:",
|
||||
"catalog.prefix.price": "Price:",
|
||||
"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.window.section.room": "Room",
|
||||
"modtools.window.section.user": "User",
|
||||
"modtools.window.section.reports": "Reports",
|
||||
"modtools.window.user.open_info": "Open Info",
|
||||
"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",
|
||||
"groupforum.view.threads": "Number of threads",
|
||||
"groupforum.thread.pin": "Pin thread",
|
||||
"groupforum.thread.unpin": "Unpin thread",
|
||||
"groupforum.thread.lock": "Lock thread",
|
||||
"groupforum.thread.unlock": "Unlock thread",
|
||||
"groupforum.thread.hide": "Hide thread",
|
||||
"groupforum.thread.restore": "Restore thread",
|
||||
"groupforum.thread.delete": "Delete thread + posts",
|
||||
"groupforum.message.hide": "Hide message",
|
||||
"group.forum.enable.caption": "Enable / Disable group forum",
|
||||
"group.forum.enable.help": "If you disable the group forum, all posts will also be deleted!",
|
||||
"groupforum.view.no_threads": "There are currently no active threads"
|
||||
"notification.badge.received": "Nuovo Distintivo!",
|
||||
"wiredfurni.badgereceived.title": "Distintivo ricevuto!",
|
||||
"wiredfurni.badgereceived.body": "Hai appena ricevuto un nuovo Distintivo! Controlla nel tuo Inventario!",
|
||||
"friendlist.search": "Search friends",
|
||||
"purse.seasonal.currency.101": "cash",
|
||||
"widget.chooser.checkall": "Select furniture",
|
||||
"widget.chooser.btn.pickall": "pick up selected items!",
|
||||
"wiredfurni.params.requireall.2": "If one of the selected furni has an avatar",
|
||||
"wiredfurni.params.requireall.3": "If all selected furni have avatars on them",
|
||||
"widget.settings.general": "General",
|
||||
"widget.settings.general.title": "Adjust the default Nitro settings",
|
||||
"widget.settings.volume": "Volume",
|
||||
"widget.settings.interface": "Interface",
|
||||
"widget.settings.interface.title": "Adjust the interface settings",
|
||||
"widget.settings.interface.fps.automatic": "Set FPS to unlimited",
|
||||
"widget.settings.interface.fps.warning": "Setting FPS to unlimited may cause performance issues!",
|
||||
"widget.settings.interface.secondary": "Change the window header color",
|
||||
"widget.settings.interface.reset": "Reset header color to default",
|
||||
"widget.room.chat.hide_pets": "Hide pets",
|
||||
"widget.room.chat.hide_avatars": "Hide avatars",
|
||||
"widget.room.chat.hide_balloon": "Hide speech bubble",
|
||||
"widget.room.chat.show_balloon": "Speech bubble",
|
||||
"widget.room.chat.clear_history": "clear history",
|
||||
"widget.room.youtube.shared": "YouTube is being shared",
|
||||
"widget.room.youtube.open_video": "Open the video",
|
||||
"wiredfurni.tooltip.select.tile": "Select tile",
|
||||
"wiredfurni.tooltip.remove.tile": "Deselect tile",
|
||||
"wiredfurni.tooltip.remove.5x5_tile": "select 5x5 tiles",
|
||||
"wiredfurni.tooltip.remove.clear_tile": "Clear all selections",
|
||||
"wiredfurni.params.furni_neighborhood.group.user": "Players",
|
||||
"wiredfurni.params.furni_neighborhood.group.furni": "Furniture",
|
||||
"wiredfurni.params.selector_option.bot": "No bots",
|
||||
"wiredfurni.params.selector_option.pet": "No pets",
|
||||
"catalog.title": "Catalog",
|
||||
"catalog.favorites": "Favorites",
|
||||
"catalog.favorites.pages": "Pages",
|
||||
"catalog.favorites.furni": "Furni",
|
||||
"catalog.favorites.empty": "No favorites",
|
||||
"catalog.favorites.empty.hint": "Click the heart on furni or the star on pages to add them.",
|
||||
"catalog.admin": "Admin",
|
||||
"catalog.admin.new": "New",
|
||||
"catalog.admin.root": "Root",
|
||||
"catalog.admin.new.root.category": "New root category",
|
||||
"catalog.admin.edit.root": "Edit Root",
|
||||
"catalog.admin.edit": "Edit:",
|
||||
"catalog.admin.edit.page": "Edit Page",
|
||||
"catalog.admin.hidden": "hidden",
|
||||
"catalog.admin.edit.title": "Edit \"%name%\"",
|
||||
"catalog.admin.show": "Show",
|
||||
"catalog.admin.hide": "Hide",
|
||||
"catalog.admin.delete": "Delete",
|
||||
"catalog.admin.delete.title": "Delete \"%name%\"",
|
||||
"catalog.admin.delete.category.confirm": "Delete category \"%name%\" and all its content?",
|
||||
"catalog.admin.delete.page": "Delete page",
|
||||
"catalog.admin.delete.page.confirm": "Delete page \"%name%\"?",
|
||||
"catalog.admin.delete.offer.confirm": "Are you sure you want to delete this offer?",
|
||||
"catalog.admin.create": "Create",
|
||||
"catalog.admin.save": "Save",
|
||||
"catalog.admin.create.subpage": "Create sub-page",
|
||||
"catalog.admin.order": "Order",
|
||||
"catalog.admin.visible": "Visible",
|
||||
"catalog.admin.enabled": "Enabled",
|
||||
"catalog.admin.offer.new": "New Offer",
|
||||
"catalog.admin.offer.edit": "Edit Offer",
|
||||
"catalog.admin.offer.name": "Catalog Name",
|
||||
"catalog.admin.offer.general": "General",
|
||||
"catalog.admin.offer.quantity": "Quantity",
|
||||
"catalog.admin.offer.prices": "Prices",
|
||||
"catalog.admin.offer.credits": "Credits",
|
||||
"catalog.admin.offer.points": "Points",
|
||||
"catalog.admin.offer.points.type": "Points Type",
|
||||
"catalog.admin.offer.options": "Options",
|
||||
"catalog.admin.offer.club.only": "Club Only",
|
||||
"catalog.admin.offer.extradata": "Extra Data (optional)....",
|
||||
"catalog.admin.offer.have.offer": "Multi-discount (have_offer)",
|
||||
"catalog.trophies.title": "Trophies",
|
||||
"catalog.trophies.write.hint": "Write a text for the trophy before purchasing",
|
||||
"catalog.trophies.inscription": "Trophy Inscription",
|
||||
"catalog.trophies.inscription.placeholder": "Write the text that will appear on the trophy...",
|
||||
"catalog.pets.show.colors": "Show colors",
|
||||
"catalog.pets.choose.color": "Choose color",
|
||||
"catalog.pets.choose.breed": "Choose breed",
|
||||
"catalog.pets.back.breeds": "? Breeds",
|
||||
"catalog.prefix.text": "Text",
|
||||
"catalog.prefix.text.placeholder": "Enter text...",
|
||||
"catalog.prefix.icon": "Icon",
|
||||
"catalog.prefix.icon.remove": "Remove icon",
|
||||
"catalog.prefix.effect": "Effect",
|
||||
"catalog.prefix.color": "Color",
|
||||
"catalog.prefix.color.single": "?? Single",
|
||||
"catalog.prefix.color.per.letter": "?? Per Letter",
|
||||
"catalog.prefix.color.hint": "Select a letter, then choose the color. Auto-advances.",
|
||||
"catalog.prefix.color.apply.all.title": "Apply current color to all letters",
|
||||
"catalog.prefix.color.apply.all": "Apply to all",
|
||||
"catalog.prefix.color.selected": "Selected letter:",
|
||||
"catalog.prefix.price": "Price:",
|
||||
"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.window.section.room": "Room",
|
||||
"modtools.window.section.user": "User",
|
||||
"modtools.window.section.reports": "Reports",
|
||||
"modtools.window.user.open_info": "Open Info",
|
||||
"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",
|
||||
"groupforum.view.threads": "Number of threads",
|
||||
"groupforum.thread.pin": "Pin thread",
|
||||
"groupforum.thread.unpin": "Unpin thread",
|
||||
"groupforum.thread.lock": "Lock thread",
|
||||
"groupforum.thread.unlock": "Unlock thread",
|
||||
"groupforum.thread.hide": "Hide thread",
|
||||
"groupforum.thread.restore": "Restore thread",
|
||||
"groupforum.thread.delete": "Delete thread + posts",
|
||||
"groupforum.message.hide": "Hide message",
|
||||
"group.forum.enable.caption": "Enable / Disable group forum",
|
||||
"group.forum.enable.help": "If you disable the group forum, all posts will also be deleted!",
|
||||
"groupforum.view.no_threads": "There are currently no active threads",
|
||||
"loading.task.session": "Verifying session...",
|
||||
"loading.task.renderer": "Initializing renderer...",
|
||||
"loading.task.assets": "loading game assets...",
|
||||
"loading.task.localization": "loading translations...",
|
||||
"loading.task.avatar": "loading wardrobe...",
|
||||
"loading.task.sounds": "loading sounds...",
|
||||
"loading.task.startsession": "Starting session...",
|
||||
"loading.task.userdata": "loading user data...",
|
||||
"loading.task.rooms": "loading rooms...",
|
||||
"loading.task.engine": "loading graphics engine...",
|
||||
}
|
||||
|
||||
@@ -48,26 +48,9 @@
|
||||
"timezone.settings": "Europe/Amsterdam",
|
||||
"youtube.publish.disabled": false,
|
||||
"user.badges.group.slot.enabled": true,
|
||||
|
||||
"_comment_loading_screen": "Schermata di caricamento — sostituibili per traduzione/branding. Logo, sfondo e colore della barra usano lo standard CSS (URL, gradient, colore esadecimale). Le label compaiono sotto la barra di progresso man mano che ogni fase del boot completa.",
|
||||
"loading.logo.url": "",
|
||||
"loading.background": "",
|
||||
"loading.progress.color": "linear-gradient(90deg,#4f8cff,#2563eb)",
|
||||
"loading.task.boot": "Avvio in corso...",
|
||||
"loading.task.session": "Verifica sessione",
|
||||
"loading.task.renderer": "Inizializzazione renderer",
|
||||
"loading.task.warmup": "Caricamento contenuti...",
|
||||
"loading.task.assets": "Sto caricando gli asset di gioco",
|
||||
"loading.task.localization": "Sto caricando le traduzioni",
|
||||
"loading.task.avatar": "Sto caricando il guardaroba",
|
||||
"loading.task.sounds": "Sto caricando i suoni",
|
||||
"loading.task.startsession": "Avvio sessione",
|
||||
"loading.task.userdata": "Caricamento dati utente",
|
||||
"loading.task.rooms": "Caricamento stanze",
|
||||
"loading.task.engine": "Caricamento engine grafico",
|
||||
"loading.task.connect": "Connessione al server",
|
||||
"loading.task.ready": "Pronto!",
|
||||
|
||||
"login.screen.enabled": true,
|
||||
"login.endpoint": "${api.url}/api/auth/login",
|
||||
"login.register.endpoint": "${api.url}/api/auth/register",
|
||||
|
||||
+30
-99
@@ -74,21 +74,30 @@ export const App: FC<{}> = props =>
|
||||
const [ prepareTrigger, setPrepareTrigger ] = useState(0);
|
||||
const [ loadingProgress, setLoadingProgress ] = useState(0);
|
||||
const [ loadingTask, setLoadingTask ] = useState('');
|
||||
// Look up a loader-stage label from renderer-config so the strings the user
|
||||
// sees during the boot ("Sto caricando il guardaroba", "Connessione…") can
|
||||
// be translated by editing the JSON/JSON5 config — fallback keeps the
|
||||
// Italian baseline shipped with the client.
|
||||
const taskLabel = useCallback((key: string, fallback: string): string =>
|
||||
{
|
||||
try
|
||||
{
|
||||
const raw = GetConfiguration().getValue<string>(key, '');
|
||||
return (typeof raw === 'string' && raw.length) ? raw : fallback;
|
||||
const locManager = GetLocalizationManager();
|
||||
if(locManager && typeof locManager.getValue === 'function')
|
||||
{
|
||||
const fromLoc = locManager.getValue(key, false);
|
||||
|
||||
if(typeof fromLoc === 'string' && fromLoc.length && fromLoc !== key) return fromLoc;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{ }
|
||||
|
||||
try
|
||||
{
|
||||
return fallback;
|
||||
const fromConfig = GetConfiguration().getValue<string>(key, '');
|
||||
if(typeof fromConfig === 'string' && fromConfig.length) return fromConfig;
|
||||
}
|
||||
catch
|
||||
{ }
|
||||
|
||||
return fallback;
|
||||
}, []);
|
||||
const bumpProgress = useCallback((value: number, task?: string) =>
|
||||
{
|
||||
@@ -111,9 +120,6 @@ export const App: FC<{}> = props =>
|
||||
ClearRememberLogin();
|
||||
try { delete (window as any).NitroConfig?.['sso.ticket']; } catch {}
|
||||
try { GetConfiguration().setValue('sso.ticket', ''); } catch {}
|
||||
// Drop `?sso=` from the URL too — otherwise the next reload re-applies
|
||||
// the same already-consumed ticket via bootstrap.ts and we loop right
|
||||
// back into "Session expired" without ever showing the login form.
|
||||
try
|
||||
{
|
||||
const url = new URL(window.location.href);
|
||||
@@ -142,11 +148,6 @@ export const App: FC<{}> = props =>
|
||||
|
||||
const fallbackToLogin = useCallback(() =>
|
||||
{
|
||||
// When login.screen.enabled is false this hotel uses SSO-only auth
|
||||
// (CMS issues the ticket and redirects here). Surfacing a login form
|
||||
// on init failure would just dump an empty/broken placeholder, since
|
||||
// the form's backgrounds and Turnstile aren't even configured. Send
|
||||
// the user back to the hotel home page instead.
|
||||
const rawLoginEnabled = GetConfiguration().getValue<unknown>('login.screen.enabled', false);
|
||||
const loginScreenEnabled = rawLoginEnabled === true || rawLoginEnabled === 'true' || rawLoginEnabled === 1;
|
||||
|
||||
@@ -156,14 +157,7 @@ export const App: FC<{}> = props =>
|
||||
showSessionExpired();
|
||||
return;
|
||||
}
|
||||
|
||||
// Using console.warn (not NitroLogger.log) on purpose: NitroLogger
|
||||
// is gated on LOG_DEBUG, which only flips to true once startWarmup's
|
||||
// GetConfiguration().init() completes. Auth-failure paths fire before
|
||||
// that, so NitroLogger swallows their messages silently.
|
||||
console.warn('[App] fallbackToLogin — surfacing login form, credentials cleared');
|
||||
// Wipe whatever credential the server just rejected so the form is
|
||||
// pristine and the next attempt isn't sabotaged by the same stale data.
|
||||
clearStoredCredentials();
|
||||
setHomeUrl('');
|
||||
setErrorMessage('');
|
||||
@@ -200,8 +194,6 @@ export const App: FC<{}> = props =>
|
||||
|
||||
if(!remembered?.token?.length)
|
||||
{
|
||||
// No remember token means we'd be reusing a one-shot ssoTicket that
|
||||
// the server already consumed. Force the login screen instead.
|
||||
if(remembered) ClearRememberLogin();
|
||||
console.warn('[App] tryRememberLogin → no token, returning empty');
|
||||
return '';
|
||||
@@ -250,9 +242,6 @@ export const App: FC<{}> = props =>
|
||||
console.warn('[App] tryRememberLogin → fetch threw', error);
|
||||
}
|
||||
|
||||
// Any failure (rejected token, bad payload, network error) — drop the
|
||||
// stored credentials. Never fall back to the cached ssoTicket: it's
|
||||
// one-shot and reusing it leads straight to "Session expired".
|
||||
ClearRememberLogin();
|
||||
console.warn('[App] tryRememberLogin → cleared remember, returning empty');
|
||||
|
||||
@@ -303,35 +292,12 @@ export const App: FC<{}> = props =>
|
||||
}
|
||||
}, []);
|
||||
|
||||
// Mirror isReady into a ref so the socket handlers below can read the
|
||||
// freshest value without needing to re-subscribe on every state change.
|
||||
useEffect(() => { isReadyRef.current = isReady; }, [ isReady ]);
|
||||
|
||||
// Track whether a reconnect cycle is active. The renderer dispatches
|
||||
// SOCKET_RECONNECTING when it starts retrying after an abnormal close
|
||||
// (code != 1000/1001). On exhausted retries it fires SOCKET_RECONNECT_FAILED
|
||||
// *and* a final SOCKET_CLOSED — we keep the flag set through that pair
|
||||
// so ReconnectView's own overlay owns the UX and we don't double-render.
|
||||
useNitroEvent(NitroEventType.SOCKET_RECONNECTING, () => { reconnectInProgressRef.current = true; });
|
||||
useNitroEvent(NitroEventType.SOCKET_REAUTHENTICATED, () => { reconnectInProgressRef.current = false; });
|
||||
|
||||
useNitroEvent(NitroEventType.SOCKET_CLOSED, () =>
|
||||
{
|
||||
// Three distinct close scenarios converge here:
|
||||
//
|
||||
// 1. !isReady — initial handshake just failed (server replied
|
||||
// with "Bye" / code 1000 to a bad SSO ticket). The user never
|
||||
// had a session. Surface the login form instead of the
|
||||
// misleading "Session expired" diagnostic.
|
||||
//
|
||||
// 2. isReady && reconnect in progress — ReconnectView already
|
||||
// owns the UX (its overlay shows attempts and the "Session
|
||||
// expired" message on RECONNECT_FAILED). Stay out of its way.
|
||||
//
|
||||
// 3. isReady && no reconnect — instant server kick mid-game
|
||||
// (code 1000 from the server side). No reconnect path will
|
||||
// run. Show the legacy session-expired diagnostic so the
|
||||
// user knows to reload.
|
||||
console.warn('[App] SOCKET_CLOSED fired', {
|
||||
isReady: isReadyRef.current,
|
||||
reconnectInProgress: reconnectInProgressRef.current
|
||||
@@ -390,7 +356,7 @@ export const App: FC<{}> = props =>
|
||||
warmupPromiseRef.current = (async () =>
|
||||
{
|
||||
await GetConfiguration().init();
|
||||
bumpProgress(25, taskLabel('loading.task.warmup', 'Caricamento contenuti...'));
|
||||
bumpProgress(25, taskLabel('loader.waiting', 'Loading content...'));
|
||||
|
||||
GetTicker().maxFPS = GetConfiguration().getValue<number>('system.fps.max', 24);
|
||||
NitroLogger.LOG_DEBUG = GetConfiguration().getValue<boolean>('system.log.debug', true);
|
||||
@@ -427,15 +393,11 @@ export const App: FC<{}> = props =>
|
||||
loginImageUrls.forEach(preloadImage);
|
||||
gamedataUrls.forEach(url => preloadUrl(url));
|
||||
|
||||
// Wire each warmup task to a progress bump so the bar reflects
|
||||
// real subsystem-init completion, not a fake timer. Range 25→70.
|
||||
// Each task carries a friendly label so the user sees what is
|
||||
// currently being prepared instead of raw file names.
|
||||
const warmupTasks: { promise: Promise<any>; label: string }[] = [
|
||||
{ promise: GetAssetManager().downloadAssets(assetUrls), label: taskLabel('loading.task.assets', 'Sto caricando gli asset di gioco') },
|
||||
{ promise: GetLocalizationManager().init(), label: taskLabel('loading.task.localization', 'Sto caricando le traduzioni') },
|
||||
{ promise: GetAvatarRenderManager().init(), label: taskLabel('loading.task.avatar', 'Sto caricando il guardaroba') },
|
||||
{ promise: GetSoundManager().init(), label: taskLabel('loading.task.sounds', 'Sto caricando i suoni') }
|
||||
{ promise: GetAssetManager().downloadAssets(assetUrls), label: taskLabel('loading.task.assets', 'Loading game assets...') },
|
||||
{ promise: GetLocalizationManager().init(), label: taskLabel('loading.task.localization', 'Loading translations...') },
|
||||
{ promise: GetAvatarRenderManager().init(), label: taskLabel('loading.task.avatar', 'Loading wardrobe...') },
|
||||
{ promise: GetSoundManager().init(), label: taskLabel('loading.task.sounds', 'Loading sounds...') }
|
||||
];
|
||||
let warmupDone = 0;
|
||||
const warmupStart = 25;
|
||||
@@ -477,11 +439,6 @@ export const App: FC<{}> = props =>
|
||||
{
|
||||
const prepare = async (width: number, height: number) =>
|
||||
{
|
||||
// Don't dump the actual SSO ticket — it's a one-shot bearer
|
||||
// credential that grants access to the user's session, so
|
||||
// logging it in console.warn would leak it via copied logs
|
||||
// / screen shares / browser extension hooks. Boolean flag is
|
||||
// enough for the diagnostic.
|
||||
console.warn('[App] prepare() start', {
|
||||
hasNitroConfig: !!window.NitroConfig,
|
||||
ssoTicketInConfig: !!window.NitroConfig?.['sso.ticket'],
|
||||
@@ -489,7 +446,7 @@ export const App: FC<{}> = props =>
|
||||
hasUrlSso: !!new URLSearchParams(window.location.search).get('sso')
|
||||
});
|
||||
|
||||
const bootLabel = taskLabel('loading.task.boot', 'Avvio in corso...');
|
||||
const bootLabel = taskLabel('loader', 'Booting...');
|
||||
setLoadingProgress(0);
|
||||
setLoadingTask(bootLabel);
|
||||
bumpProgress(5, bootLabel);
|
||||
@@ -501,11 +458,6 @@ export const App: FC<{}> = props =>
|
||||
let ssoTicket = window.NitroConfig['sso.ticket'];
|
||||
if(ssoTicket) GetConfiguration().setValue('sso.ticket', ssoTicket);
|
||||
|
||||
// Cattura il remember-token passato via URL (?token=&token_exp=)
|
||||
// dal CMS Inertia /client e salvalo in localStorage. Serve a
|
||||
// tryRememberLogin() in reconnect: chiama POST /api/auth/remember
|
||||
// col token UUID, riceve un nuovo SSO ticket fresco invece di
|
||||
// riusare quello cleared da Arcturus dopo il primo consume.
|
||||
try
|
||||
{
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
@@ -525,12 +477,10 @@ export const App: FC<{}> = props =>
|
||||
console.warn('[App] failed to persist remember token from URL', e);
|
||||
}
|
||||
|
||||
bumpProgress(10, taskLabel('loading.task.session', 'Verifica sessione'));
|
||||
bumpProgress(10, taskLabel('loading.task.session', 'Verifying session...'));
|
||||
|
||||
if(!ssoTicket || ssoTicket === '')
|
||||
{
|
||||
// Configuration is loaded lazily — fetch it up-front so the login
|
||||
// screen toggle and Turnstile keys are available before we decide.
|
||||
let configInitError: unknown = null;
|
||||
try
|
||||
{
|
||||
@@ -592,23 +542,23 @@ export const App: FC<{}> = props =>
|
||||
}
|
||||
|
||||
const renderer = await startRenderer(width, height);
|
||||
bumpProgress(20, taskLabel('loading.task.renderer', 'Inizializzazione renderer'));
|
||||
bumpProgress(20, taskLabel('loading.task.renderer', 'Initializing renderer...'));
|
||||
|
||||
await startWarmup(width, height);
|
||||
bumpProgress(70, taskLabel('loading.task.startsession', 'Avvio sessione'));
|
||||
bumpProgress(70, taskLabel('loading.task.startsession', 'Starting session...'));
|
||||
|
||||
if(!gameInitPromiseRef.current)
|
||||
{
|
||||
gameInitPromiseRef.current = (async () =>
|
||||
{
|
||||
await GetSessionDataManager().init();
|
||||
bumpProgress(78, taskLabel('loading.task.userdata', 'Caricamento dati utente'));
|
||||
bumpProgress(78, taskLabel('loading.task.userdata', 'Loading user data...'));
|
||||
await GetRoomSessionManager().init();
|
||||
bumpProgress(85, taskLabel('loading.task.rooms', 'Caricamento stanze'));
|
||||
bumpProgress(85, taskLabel('loading.task.rooms', 'Loading rooms...'));
|
||||
await GetRoomEngine().init();
|
||||
bumpProgress(92, taskLabel('loading.task.engine', 'Caricamento engine grafico'));
|
||||
bumpProgress(92, taskLabel('loading.task.engine', 'Loading graphics engine...'));
|
||||
await GetCommunication().init();
|
||||
bumpProgress(98, taskLabel('loading.task.connect', 'Connessione al server'));
|
||||
bumpProgress(98, taskLabel('generic.reconnecting', 'Connecting to server...'));
|
||||
})();
|
||||
}
|
||||
|
||||
@@ -637,7 +587,7 @@ export const App: FC<{}> = props =>
|
||||
GetTicker().add(ticker => GetTexturePool().run());
|
||||
}
|
||||
|
||||
bumpProgress(100, taskLabel('loading.task.ready', 'Pronto!'));
|
||||
bumpProgress(100, taskLabel('onboarding.button.ready', 'Ready!'));
|
||||
setIsReady(true);
|
||||
setShowLogin(false);
|
||||
setIsEnteringHotel(false);
|
||||
@@ -645,23 +595,10 @@ export const App: FC<{}> = props =>
|
||||
catch(err)
|
||||
{
|
||||
NitroLogger.error('[App] Initialization failed — falling back to login', err);
|
||||
// Anything thrown out of the post-auth chain (renderer init,
|
||||
// asset download, GetCommunication().init()) is an init/connect
|
||||
// failure, not session expiration. The credential we used is
|
||||
// suspect — drop it and present the login form so the user
|
||||
// can retry instead of getting stuck on a stale "Session expired".
|
||||
onInitFailure();
|
||||
}
|
||||
};
|
||||
|
||||
// React Strict Mode in dev runs every effect twice (mount → cleanup → mount).
|
||||
// `prepare()` is full of one-shot side effects (renderer init, websocket
|
||||
// connect, NitroConfig mutation) — calling it twice with the same trigger
|
||||
// value causes the second pass to race with the first and clobber state
|
||||
// (e.g. the second pass falls through to onSessionExpired while the first
|
||||
// had just set showLogin=true). Guard by trigger value: skip duplicate
|
||||
// runs at the same trigger, but still re-run when handleAuthenticated
|
||||
// bumps prepareTrigger after a successful login.
|
||||
if(lastPrepareTriggerRef.current === prepareTrigger) return;
|
||||
lastPrepareTriggerRef.current = prepareTrigger;
|
||||
|
||||
@@ -682,12 +619,6 @@ export const App: FC<{}> = props =>
|
||||
<LoadingView isError={ errorMessage.length > 0 } message={ errorMessage } homeUrl={ homeUrl } progress={ loadingProgress } currentTask={ loadingTask } /> }
|
||||
{ !isReady && showLogin && <LoginView onAuthenticated={ handleAuthenticated } isEntering={ isEnteringHotel } /> }
|
||||
{ isReady && <MainView /> }
|
||||
{ /* Reconnect overlay must NOT render before we've actually entered
|
||||
the hotel — otherwise the renderer's auto-retry on an initial
|
||||
handshake failure (e.g. emulator unreachable) would cover the
|
||||
login form with "Reconnecting..." → "Session expired" and the
|
||||
user wouldn't be able to interact with the form we just put up
|
||||
via fallbackToLogin. */ }
|
||||
{ isReady && <ReconnectView /> }
|
||||
<Base id="draggable-windows-container" />
|
||||
</Base>
|
||||
|
||||
Reference in New Issue
Block a user