Files
glchat/web/src/i18n/locales/en.json
T
grendervill 4c8f888b3e feat(web): профиль с аватаром, панель в углу, настройки сервера, скрытые ID
Правки пользователя:

- в «Профиль → Основной» сверху квадратный аватар слева, справа от него
  настройки имени, «О себе», состояния и эмодзи во всю высоту; смена аватара —
  клик по нему, форматы (JPEG, PNG, WebP, GIF до 8 МБ) — в подсказке;
- убраны дубли: часовой пояс только в «Язык и регион», статус — только в
  мини-профиле панели;
- панель пользователя переехала в нижний левый угол под сайдбар, подсказка о
  выходе из сервера — на её прежнее место; панель ужата под 240 px;
- шестерёнка сервера открывает новый пункт настроек «Сервер» (список серверов,
  общее, участники, роли, опасная зона), а «Профиль → Сервер» оставлен только
  для ника и «Применить ко всем серверам»;
- окно настроек получило статический размер 70% рабочей области со скроллом;
- ID пользователей скрыты везде, кроме раздела «Инстанс» у администратора;
- список друзей свёрнут под кнопкой «Друзья (N)» и раскрывается снизу вверх;
- 249 тестов Vitest (было 239), check/lint/test/build зелёные.
2026-09-20 11:24:09 +03:00

667 lines
24 KiB
JSON
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{
"app": {
"name": "glchat",
"tagline": "Self-hosted communication: text, voice, video",
"skipToContent": "Skip to content"
},
"status": {
"title": "Foundation deployed",
"description": "The server responds, the database runs in WAL mode, migrations are applied. Chat features arrive in the next phases.",
"connecting": "Checking server status…",
"instance": "Instance",
"version": "Version",
"apiVersion": "API version",
"schemaReady": "Database",
"schemaOk": "ready",
"maxUpload": "Maximum upload size",
"checks": "Checks",
"retry": "Retry",
"back": "Back",
"users": "Users",
"guilds": "Servers",
"registration": "Registration"
},
"health": {
"online": "Server is reachable",
"offline": "Server is unreachable"
},
"errors": {
"network.unreachable": "The server is not responding. Check your connection and try again.",
"network.aborted": "The request was aborted.",
"instance.not_ready": "The instance is still starting. Try again in a few seconds.",
"internal.error": "Internal server error.",
"not_found": "The requested resource was not found.",
"unknown": "Unknown error ({{code}}).",
"auth.2fa_required": "Enter the two-factor code from your authenticator app.",
"auth.totp_invalid": "The two-factor code is incorrect.",
"auth.invalid_credentials": "Wrong email or password.",
"auth.step_up_required": "Confirm your identity: enter your password again.",
"auth.guild_limit_reached": "You have reached the server limit on this instance.",
"auth.session_invalid": "Your session has expired. Sign in again.",
"auth.unauthorized": "Sign-in is required.",
"auth.registration_disabled": "Registration is disabled on this instance.",
"auth.username_taken": "This username is already taken.",
"auth.email_taken": "This email is already registered.",
"auth.weak_password": "The password is too weak. Use at least 8 characters.",
"auth.too_many_attempts": "Too many attempts. Try again later.",
"permissions.denied": "You do not have permission for this action.",
"instance.admin_required": "This action is available to the instance admin only.",
"guild.not_found": "Server not found.",
"guild.member_limit_reached": "This server has reached its member limit.",
"channel.not_found": "Channel not found.",
"validation.failed": "Check the fields you filled in.",
"rate.limited": "Too many requests. Please wait a moment.",
"perm.denied": "You do not have permission to do that.",
"rate_limited": "Too many requests. Please wait a moment.",
"message.edit_window_expired": "This message can no longer be edited: more than 24 hours passed.",
"file.too_large": "The file exceeds the allowed size.",
"request.bad": "Malformed request.",
"file.not_found": "File not found.",
"invite.expired": "This invite has expired.",
"invite.exhausted": "This invite has no uses left.",
"user.not_found": "No user with that username was found."
},
"theme": {
"switchToLight": "Light theme",
"switchToDark": "Dark theme",
"label": "Theme",
"dark": "Dark",
"light": "Light"
},
"language": {
"label": "Language",
"ru": "Русский",
"en": "English"
},
"common": {
"loading": "Loading…",
"retry": "Retry",
"cancel": "Cancel",
"close": "Close",
"save": "Save",
"saving": "Saving…",
"create": "Create",
"creating": "Creating…",
"join": "Join",
"leave": "Leave",
"back": "Back",
"copy": "Copy",
"copied": "Copied",
"yes": "Yes",
"no": "No",
"optional": "optional",
"dismiss": "Dismiss"
},
"footer": {
"source": "Source code",
"license": "AGPL-3.0"
},
"auth": {
"login": {
"title": "Sign in",
"subtitle": "Sign in to keep talking",
"email": "Email",
"emailPlaceholder": "you@example.com",
"password": "Password",
"totp": "2FA or recovery code",
"totpHint": "If 2FA is enabled; a recovery code like xxxx-xxxx-xxxx also works.",
"submit": "Sign in",
"submitting": "Signing in…",
"noAccount": "No account yet?",
"registerLink": "Create one",
"forgot": "Forgot your password? Ask the instance admin.",
"instanceStatus": "Instance status",
"registrationDisabled": "Registration on this instance is disabled by the admin.",
"totpRequired": "Enter the 2FA or recovery code — sign-in needs it."
},
"register": {
"title": "Create account",
"subtitle": "Create an account on {{instance}}",
"username": "Username",
"usernameHint": "3–32 characters: latin letters, digits, “_” and “-”.",
"displayName": "Display name",
"email": "Email",
"password": "Password",
"passwordHint": "At least 8 characters.",
"requirements": "Password requirements: {{list}}",
"requirementLength": "at least 8 characters",
"requirementLetter": "at least one letter",
"requirementDigit": "at least one digit",
"submit": "Create account",
"submitting": "Creating account…",
"haveAccount": "Already have an account?",
"loginLink": "Sign in",
"disabledTitle": "Registration is closed",
"disabledBody": "The instance admin disabled self-service registration. Ask for an invite or contact the admin."
},
"validation": {
"usernameFormat": "Username: 3–32 characters, latin letters, digits, “_” or “-”.",
"usernameRequired": "Enter a username.",
"displayNameRequired": "Enter a display name.",
"emailInvalid": "Enter a valid email address.",
"passwordShort": "The password must be at least 8 characters long.",
"passwordLetter": "Add at least one letter to the password.",
"passwordDigit": "Add at least one digit to the password.",
"passwordMismatch": "The passwords do not match."
}
},
"onboarding": {
"title": "Welcome to glchat",
"greeting": "Hi, {{name}}!",
"subtitle": "A couple of steps and you are ready.",
"displayName": "How should we show you?",
"displayNameHint": "Other members see this name.",
"bio": "Tell us about yourself",
"bioPlaceholder": "What you do, what you like…",
"language": "Interface language",
"theme": "Theme",
"start": "Get started",
"starting": "Preparing your workspace…",
"skip": "Skip and start",
"note": "You can change all of this later in settings."
},
"guilds": {
"railLabel": "Servers",
"listLabel": "Server list",
"add": "Create a server",
"addShort": "Create a server",
"create": {
"title": "Create a server",
"name": "Server name",
"namePlaceholder": "For example, “Friends”",
"hint": "You can rename it later in the server settings.",
"submit": "Create",
"limit": "You can create at most {{count}} servers on this instance.",
"limitReached": "You have reached the server limit — remove one of your servers first."
},
"empty": {
"title": "You have no servers yet",
"body": "Create your own server or join one with an invite.",
"create": "Create your own server"
},
"leave": "Leave server",
"leaveConfirm": "Leave the server “{{name}}”?",
"switchTo": "Open server {{name}}"
},
"channels": {
"title": "Channels",
"text": "Text channels",
"voice": "Voice channels",
"category": "Category",
"empty": "This server has no visible channels yet.",
"select": "Open channel {{name}}",
"add": "Create a channel",
"settings": "Server settings",
"create": {
"title": "New channel",
"name": "Channel name",
"namePlaceholder": "for example, general",
"type": "Channel type",
"typeText": "Text",
"typeVoice": "Voice",
"parent": "Category",
"noParent": "No category",
"submit": "Create"
},
"chatPlaceholder": {
"title": "Chat arrives in Phase 2",
"body": "The channel “{{name}}” is ready. Messages and voice arrive in the next phase."
},
"voicePlaceholder": {
"title": "Voice channel",
"body": "Connecting to voice arrives in the next phases."
},
"noSelection": {
"title": "Pick a channel",
"body": "The server and channel lists are on the left. Pick a channel to open it."
},
"notInGuild": {
"title": "Server unavailable",
"body": "Looks like you are not a member of this server."
},
"selectUnread": "Open channel {{name}}, {{count}} unread",
"selectMentions": "Open channel {{name}}, {{count}} mentions",
"slowmode": "slowmode {{seconds}}s",
"leaveHint": "You can leave the server in server settings → “Danger zone”."
},
"friends": {
"rail": "Friends",
"title": "Friends",
"sidebarLabel": "Friends and direct messages",
"sidebarHint": "Direct messages live here — they are not in the server rail.",
"dmSection": "Direct messages",
"dmEmpty": "No direct messages yet.",
"friendsSection": "Friends",
"friendsEmpty": "Your friend list is empty.",
"open": "Open a conversation with {{name}}",
"empty": {
"title": "Add friends to start talking",
"body": "Find someone by username and send a friend request — a direct conversation appears once it is accepted.",
"search": "Find friends"
},
"search": {
"title": "Friend search",
"close": "Close search",
"label": "Search by username",
"placeholder": "Enter a username",
"hint": "Type at least 2 characters.",
"empty": "Nobody found.",
"add": "Add friend",
"adding": "Sending…",
"requested": "Request sent",
"friend": "Already friends",
"message": "Message",
"open": "Search friends"
},
"requests": {
"incoming": "Incoming requests",
"outgoing": "Outgoing requests",
"accept": "Accept",
"decline": "Decline",
"cancel": "Cancel"
},
"list": {
"label": "Friend list",
"message": "Message",
"more": "Actions: {{name}}",
"menu": "Actions for {{name}}",
"remove": "Remove friend",
"block": "Block",
"toggle": "Friends ({{count}})"
},
"lastSeen": {
"label": "Last seen",
"online": "Online now",
"unknown": "Offline for a while",
"at": "Last seen: {{time}}"
},
"dm": {
"unknown": "Recipient",
"notFound": {
"title": "Conversation unavailable",
"body": "This direct conversation was not found: it may be deleted or closed to you."
}
}
},
"invites": {
"title": "Join with an invite",
"hint": "Paste a code or a link like https://<domain>/invite/<code>.",
"label": "Invite code or link",
"placeholder": "e.g. ab12cd or https://example.com/invite/ab12cd",
"invalid": "Could not recognise the invite code.",
"join": "Join",
"joining": "Joining…",
"members": "Members: {{count}}",
"alreadyMember": "You are already on this server"
},
"chat": {
"log": "Message log of {{name}}",
"loadMore": "Load more",
"loadingMore": "Loading…",
"today": "Today",
"yesterday": "Yesterday",
"edited": "(edited)",
"pending": "sending…",
"newMessages": "New messages",
"adminBadge": "admin",
"unknownAuthor": "unknown",
"start": {
"title": "This is the start of #{{name}}",
"body": "There are no messages here yet. Say something — everyone in the channel will see it.",
"directTitle": "This is the beginning of your conversation with {{name}}",
"directBody": "No messages here yet. Say hello first."
},
"message": {
"by": "Message from {{name}} in {{channel}}",
"sentAt": "Sent {{time}}"
},
"reply": {
"to": "reply to {{name}}",
"missing": "deleted message",
"composer": "Replying to {{name}}",
"cancel": "Cancel reply"
},
"actions": {
"menu": "Message actions",
"reply": "Reply",
"react": "Add reaction",
"pin": "Pin",
"unpin": "Unpin",
"edit": "Edit",
"delete": "Delete",
"deleteConfirm": "Delete this message?",
"copy": "Copy text"
},
"reactions": {
"title": "Reactions",
"add": "React with {{emoji}}",
"toggle": "Reaction {{emoji}}: {{count}}"
},
"emoji": {
"title": "Emoji picker",
"quick": "Quick reactions",
"popular": "Popular emoji",
"pick": "React with {{emoji}}"
},
"edit": {
"label": "Edit message",
"hint": "Enter to save, Escape to cancel",
"save": "Save",
"cancel": "Cancel"
},
"composer": {
"label": "Message to {{name}}",
"placeholder": "Message #{{name}}",
"send": "Send",
"hint": "Enter to send, Shift+Enter for a new line",
"attach": "Attach a file",
"fileInput": "Choose files",
"uploading": "Uploading attachments…",
"attachments": "Message attachments",
"removeAttachment": "Remove attachment {{name}}",
"counter": "{{count}}/{{max}}",
"tooLarge": "File “{{name}}” exceeds the {{limit}} limit",
"rateLimited": "Too many messages. You can send again in {{seconds}} s.",
"denied": "You are not allowed to send messages in this channel.",
"readOnly": "This channel is read-only for you.",
"directLabel": "Message to {{name}}",
"directPlaceholder": "Message {{name}}"
},
"typing_one": "{{names}} is typing…",
"typing_few": "{{names}} are typing…",
"typing_many": "{{names}} are typing…",
"typing_other": "{{names}} are typing…",
"pins": {
"open": "Pinned messages",
"title": "Pinned in #{{name}}",
"empty": "No pinned messages in this channel yet.",
"jump": "Jump"
},
"search": {
"open": "Search this channel",
"title": "Message search",
"label": "Search field",
"placeholder": "Search messages",
"hint": "Type at least two characters.",
"empty": "Nothing found."
},
"unread": "Unread messages: {{count}}",
"mentions": "Mentions: {{count}}",
"spoiler": {
"show": "Reveal spoiler",
"hide": "Hide spoiler"
},
"logDirect": "Direct conversation with {{name}}"
},
"user": {
"panelLabel": "User panel",
"settings": "User settings",
"menu": {
"label": "User menu",
"open": "Open the user menu",
"account": "Account settings",
"guilds": "Server settings",
"status": "Status",
"noBio": "No bio yet."
},
"logout": "Sign out",
"loggingOut": "Signing out…",
"statusLabel": "Status: {{status}}",
"status": {
"online": "Online",
"idle": "Idle",
"dnd": "Do not disturb",
"invisible": "Invisible",
"offline": "Offline"
},
"voice": {
"input": "Input device",
"output": "Output device",
"camera": "Camera",
"micVolume": "Microphone volume",
"outputVolume": "Sound volume",
"micOn": "Unmute microphone",
"micOff": "Mute microphone",
"cameraOn": "Turn camera on",
"cameraOff": "Turn camera off",
"soundOn": "Undeafen",
"soundOff": "Deafen",
"micSettings": "Microphone settings",
"cameraSettings": "Camera settings",
"soundSettings": "Sound settings",
"audioSettings": "Audio & video settings"
},
"devices": {
"default": "Default device",
"unavailable": "Devices are unavailable",
"empty": "No devices found",
"unnamed": "Device {{index}}"
}
},
"gateway": {
"label": "Connection",
"status": {
"idle": "Not connected",
"connecting": "Connecting…",
"connected": "Connected",
"reconnecting": "Reconnecting…",
"disconnected": "Connection lost"
},
"invalidated": "The server closed the session. Sign in again."
},
"settings": {
"title": "Settings",
"back": "Back to app",
"switcher": {
"label": "Settings sections",
"account": "Server settings",
"servers": "My servers"
},
"tabs": {
"label": "Settings sections",
"profile": "Profile",
"security": "Security",
"appearance": "Appearance",
"notifications": "Notifications",
"server": "Server",
"voice": "Audio & video",
"language": "Language & region",
"instance": "Instance"
},
"profile": {
"avatar.change": "Change avatar",
"avatar.uploading": "Uploading…",
"title": "Profile",
"description": "How other members see you.",
"displayName": "Display name",
"bio": "About me",
"bioPlaceholder": "A few words about you",
"customStatus": "Custom status",
"customStatusPlaceholder": "For example, “Writing code”",
"customStatusEmoji": "Status emoji",
"customStatusEmojiPlaceholder": "🚀",
"saved": "Profile saved.",
"username": "Username",
"badges": "Badges",
"noBadges": "none",
"tabsLabel": "Profile tabs",
"tabs": {
"main": "General",
"server": "Server"
},
"timezoneDefault": "default (MSK)",
"avatar": {
"change": "Change avatar",
"choose": "Choose avatar file",
"remove": "Remove avatar",
"formats": "JPEG, PNG, WebP, GIF",
"limit": "{{formats}} up to {{limit}}",
"tooLarge": "The file is larger than {{limit}} — pick a smaller image.",
"uploading": "Uploading…"
},
"decorations": {
"title": "Decorations",
"hint": "Profile badges and frames.",
"empty": "No decorations yet.",
"stub": "Badges, frames and profile effects are coming later."
}
},
"security": {
"title": "Security",
"description": "Password, active sessions and two-factor authentication.",
"passwordTitle": "Change password",
"currentPassword": "Current password",
"newPassword": "New password",
"confirmPassword": "Repeat the new password",
"submitPassword": "Change password",
"passwordChanged": "Password changed.",
"stepUpTitle": "Confirm your identity",
"stepUpBody": "The server requires your password again for this action{{totp}}.",
"stepUpTotp": " and a 2FA code",
"stepUpSubmit": "Confirm",
"stepUpSuccess": "Identity confirmed.",
"stepUpExpired": "The confirmation expired, enter your password again.",
"stepUpPassword": "Your password",
"sessionsTitle": "Active sessions",
"sessionsEmpty": "No active sessions.",
"sessionCurrent": "current",
"sessionCreated": "Created",
"sessionSeen": "Last seen",
"sessionIp": "IP",
"sessionAgent": "Device",
"unknownAgent": "Unknown device",
"logoutAll": "Sign out everywhere",
"logoutAllConfirm": "End all sessions, including this one?",
"logoutAllDone": "All sessions have been ended.",
"twoFactorTitle": "Two-factor authentication",
"twoFactorEnabled": "2FA is on",
"twoFactorDisabled": "2FA is off",
"twoFactorEnable": "Enable 2FA",
"twoFactorSetupHint": "Add the secret to your authenticator app, then enter the six-digit code.",
"twoFactorSecret": "Secret",
"twoFactorUri": "otpauth link",
"twoFactorQrAlt": "QR code for 2FA setup",
"twoFactorQrUnavailable": "The QR code is unavailable — add the secret manually.",
"twoFactorCode": "Code from the app",
"twoFactorConfirm": "Enable",
"twoFactorEnabledDone": "2FA is enabled. Save your recovery codes.",
"recoveryTitle": "Recovery codes",
"recoveryHint": "Every code works once. They are shown only once.",
"recoveryCopyAll": "Copy all codes"
},
"appearance": {
"title": "Appearance",
"description": "Interface theme and language. Stored locally in your browser.",
"theme": "Theme",
"themeHint": "The dark theme is on by default.",
"language": "Language",
"languageHint": "Russian is the primary interface language."
},
"instance": {
"title": "Instance",
"description": "Instance admin only. Read-only data.",
"notAdmin": "This section is available to the instance admin only.",
"settings": "Instance settings",
"settingsEmpty": "No settings configured.",
"guilds": "Servers ({{count}})",
"guildsEmpty": "No servers.",
"userId": "User ID",
"users": "Users ({{count}})",
"usersEmpty": "No users.",
"audit": "Audit log (last {{count}})",
"auditEmpty": "No entries.",
"memberCount": "{{count}} members",
"adminBadge": "admin",
"mainBadge": "main",
"usersIdHint": "User IDs are visible to the instance administrator only."
},
"servers": {
"pickerLabel": "My servers",
"empty": "You have no servers yet.",
"emptyTitle": "No servers yet",
"emptyHint": "Join the instance main server or create your own — its settings will show up here.",
"select": "Open settings of the server {{name}}",
"notFound": "The server was not found among the ones you can access.",
"readOnlyHint": "Only the owner and members with ADMINISTRATOR or MANAGE_GUILD can edit this.",
"general": {
"title": "General",
"description": "Every member sees the server name and description.",
"name": "Server name",
"guildDescription": "Description",
"descriptionPlaceholder": "What this server is about",
"saved": "Server settings saved."
},
"nickname": {
"title": "My profile on this server",
"description": "The nickname is visible on this server only.",
"label": "Nickname",
"placeholder": "Leave empty to reset the nickname",
"current": "Current nickname:",
"none": "not set",
"saved": "Nickname saved.",
"applyAll": "Apply to all servers",
"applyAllHint": "One nickname for every server you are in.",
"applyAllPending": "Applying…",
"applyAllProgress": "Servers updated: {{done}} of {{total}}",
"applyAllDone": "Nickname applied on all servers ({{total}}).",
"applyAllFailed": "Failed to update servers: {{failed}}."
},
"members": {
"title": "Members",
"description": "The first {{limit}} members of the server.",
"empty": "No members found.",
"roles": "Roles: {{roles}}",
"more": "The full member list with roles arrives in the next phases."
},
"roles": {
"title": "Roles",
"description": "Role colour and position. Role management arrives in the next phases.",
"empty": "This server has no roles yet.",
"position": "Position {{position}}",
"default": "default"
},
"danger": {
"title": "Danger zone",
"description": "These actions cannot be undone.",
"leaveOwnerHint": "The owner cannot leave their own server: transfer ownership or delete the server first.",
"leaveHint": "Leave the server and lose access to its channels.",
"leave": "Leave server",
"leaveConfirmTitle": "Leave the server?",
"leaveConfirmBody": "You will leave “{{name}}”. You can come back with an invite.",
"leaveConfirm": "Leave",
"deleteHint": "Delete the server together with its channels, roles and members.",
"delete": "Delete server",
"deleteConfirmTitle": "Delete the server?",
"deleteConfirmBody": "“{{name}}” will be deleted permanently.",
"deleteConfirm": "Delete"
},
"selectLabel": "Choose a server"
},
"navLabel": "Settings sections",
"notifications": {
"title": "Notifications",
"description": "Sounds, mentions and web push.",
"stub": "Notification settings are coming later."
},
"voice": {
"title": "Audio & video",
"description": "Input and output devices and volume.",
"input": "Microphone",
"camera": "Camera",
"output": "Sound",
"micVolume": "Microphone volume",
"outputVolume": "Sound volume",
"stub": "Voice channels arrive in the next phase — for now these settings are only stored."
},
"language": {
"title": "Language & region",
"description": "Time zone and interface language.",
"timezone": "Time zone",
"timezoneHint": "Used for message times.",
"locale": "Interface language",
"localeHint": "Applies immediately.",
"saved": "Region settings saved."
}
}
}