382 lines
24 KiB
Go
382 lines
24 KiB
Go
export default {
|
||
route: {
|
||
dashboard: "Дашборд",
|
||
peer: "Пиры",
|
||
peerList: "Управление пирами",
|
||
hysteria: "Hysteria",
|
||
hysteriaList: "Управление Hysteria",
|
||
config: "Система",
|
||
configList: "Настройки системы",
|
||
monitor: "Мониторинг",
|
||
monitorSystem: "Системный мониторинг",
|
||
log: "Логи",
|
||
logSystem: "Системные логи",
|
||
logHysteria: "Логи Hysteria",
|
||
},
|
||
login: {
|
||
title: "HY2XS admin",
|
||
username: "Логин",
|
||
password: "Пароль",
|
||
login: "Войти",
|
||
capsLockOn: "Caps Lock включён",
|
||
},
|
||
// Требования к учётным данным администратора. Фразы общие для формы входа и
|
||
// формы смены пароля: требование одно, и второй его формулировки быть не
|
||
// должно — расхождение здесь означало бы, что оператору обещают разное про
|
||
// одно и то же поле.
|
||
//
|
||
// Обе фразы НАЗЫВАЮТ требование, а не сообщают о его нарушении. Прежние
|
||
// «Неверный формат логина» и «Некорректное значение» не давали оператору ни
|
||
// одного способа узнать, что именно от него хотят: набор символов логина
|
||
// приходит из hy2xs.env, и посмотреть его в панели негде.
|
||
credentials: {
|
||
usernameFormat: "Логин: от {min} до {max} символов из набора {charset}",
|
||
// Фраза называет ОБЕ границы, потому что их две и они в разных единицах.
|
||
// Пароль из 40 эмодзи укладывается в 64 символа и не укладывается в 72
|
||
// байта; сообщение «не длиннее {max} символов» отправило бы оператора
|
||
// сокращать пароль, отвергнутый не за это.
|
||
passwordFormat:
|
||
"Пароль: от {min} до {max} символов и не более {maxBytes} байт в UTF-8, без управляющих символов и U+FEFF",
|
||
},
|
||
dashboard: {
|
||
stale:
|
||
"Данные дашборда устарели. Выполняется автоматическая повторная попытка...",
|
||
topPeers24h: "Топ пиров (24ч)",
|
||
topPeersRange: "Топ пиров ({range})",
|
||
refreshFailed: "Не удалось обновить данные дашборда",
|
||
cpu: "CPU",
|
||
ram: "RAM",
|
||
disk: "Диск",
|
||
peers: "Пиры",
|
||
onlinePeers: "Пиры онлайн",
|
||
onlineDevices: "Устройства онлайн",
|
||
todayDownload: "Скачано за сегодня",
|
||
todayUpload: "Отдано за сегодня",
|
||
trafficChart: "Трафик и системные метрики",
|
||
trafficSeriesChart: "Трафик: download/upload",
|
||
noTrafficData: "Нет данных трафика за выбранный период",
|
||
systemSeriesChart: "Система: CPU/RAM",
|
||
download: "Скачано",
|
||
upload: "Отдано",
|
||
total: "Всего",
|
||
serviceStateLabel: "Служба Hysteria",
|
||
// Три состояния, а не два: «спросить systemd не удалось» — это не
|
||
// «служба остановлена», и действия оператора у них разные.
|
||
serviceState: {
|
||
active: "Работает",
|
||
inactive: "Остановлена",
|
||
unknown: "Состояние неизвестно",
|
||
},
|
||
trafficApiLabel: "Traffic Stats API",
|
||
trafficApiReachable: "Доступен",
|
||
trafficApiUnreachable: "Недоступен",
|
||
security: {
|
||
hysteriaStopped: "Hysteria2 остановлена",
|
||
hysteriaStateUnknown:
|
||
"Состояние службы Hysteria2 неизвестно: systemd не ответил",
|
||
trafficApiUnavailable: "Traffic API недоступен",
|
||
},
|
||
error: {
|
||
trafficApiUnavailable: "Traffic API недоступен",
|
||
collectorStale: "Данные коллектора устарели",
|
||
},
|
||
},
|
||
admin: {
|
||
changePasswordTitle: "Смена пароля",
|
||
oldPassword: "Старый пароль",
|
||
newPassword: "Новый пароль",
|
||
forcePasswordChangeNotice: "Перед продолжением необходимо сменить пароль.",
|
||
changedSuccess: "Пароль обновлён",
|
||
},
|
||
navbar: {
|
||
logout: "Выйти",
|
||
},
|
||
common: {
|
||
id: "ID",
|
||
createTime: "Создано",
|
||
operate: "Действия",
|
||
edit: "Изменить",
|
||
delete: "Удалить",
|
||
deleted: "Статус",
|
||
all: "Все",
|
||
enable: "Включено",
|
||
disable: "Отключено",
|
||
search: "Поиск",
|
||
reset: "Сброс",
|
||
add: "Добавить",
|
||
confirm: "Подтвердить",
|
||
cancel: "Отмена",
|
||
close: "Закрыть",
|
||
copySuccess: "Скопировано",
|
||
nodeUrl: "URL узла",
|
||
nodeQrCode: "QR узла",
|
||
resetTraffic: "Сбросить трафик",
|
||
import: "Импорт",
|
||
export: "Экспорт",
|
||
save: "Сохранить",
|
||
update: "Обновить",
|
||
downloadSuccess: "Загрузка завершена",
|
||
// Фразы `wait`, `enableSuccess` и `disableSuccess` удалены вместе с
|
||
// операциями, которых у панели нет: запуском, остановкой и сменой версии
|
||
// Hysteria. Жизненный цикл принадлежит systemd и оркестратору.
|
||
success: "Готово",
|
||
refresh: "Обновить",
|
||
yes: "Да",
|
||
no: "Нет",
|
||
securityRisk: "Риски безопасности",
|
||
required: "Обязательное поле",
|
||
warning: "Внимание",
|
||
fileFormatUnsupported: "Формат файла не поддерживается",
|
||
fileTooLarge: "Файл слишком большой, не более 2 МБ",
|
||
weekLater: "Через неделю",
|
||
monthLater: "Через месяц",
|
||
yearLater: "Через год",
|
||
hourLater: "Через час",
|
||
dayLater: "Через день",
|
||
deleteConfirm: "Удалить пир «{username}»?",
|
||
resetTrafficConfirm: "Сбросить трафик для пира?",
|
||
invalid: "Некорректное значение",
|
||
switchLanguageSuccess: "Язык переключён",
|
||
logoutConfirm: "Выйти из системы?",
|
||
sessionExpired: "Сессия истекла. Войдите снова, чтобы продолжить.",
|
||
signInRequired: "Требуется вход в панель.",
|
||
signIn: "Войти",
|
||
systemError: "Системная ошибка",
|
||
networkError: "Сервер не отвечает. Проверьте соединение с панелью.",
|
||
},
|
||
// Причины отказа API.
|
||
//
|
||
// Ключи строятся из КОДА ответа, а не из его текста: панель не разбирает
|
||
// человеческие сообщения сервера. Числа правил приходят в параметрах, поэтому
|
||
// второй копии границ длины здесь нет — она неизбежно разошлась бы с
|
||
// серверной.
|
||
error: {
|
||
field: {
|
||
name: "Имя пира",
|
||
secret: "Секрет",
|
||
remark: "Комментарий",
|
||
quotaBytes: "Квота",
|
||
expiresAt: "Срок действия",
|
||
maxDevices: "Лимит устройств",
|
||
disabled: "Состояние",
|
||
bannedUntil: "Блокировка до",
|
||
file: "Файл",
|
||
id: "Идентификатор",
|
||
username: "Логин",
|
||
pass: "Пароль",
|
||
oldPassword: "Старый пароль",
|
||
newPassword: "Новый пароль",
|
||
key: "Ключ настройки",
|
||
value: "Значение настройки",
|
||
numLine: "Число строк",
|
||
pageNum: "Номер страницы",
|
||
pageSize: "Размер страницы",
|
||
},
|
||
code: {
|
||
required: "«{field}»: поле обязательно",
|
||
min: "«{field}»: значение не может быть меньше {min}",
|
||
max: "«{field}»: значение не может быть больше {max}",
|
||
min_length: "«{field}»: не короче {min} символов",
|
||
max_length: "«{field}»: не длиннее {max} символов",
|
||
len: "«{field}»: длина должна быть ровно {len}",
|
||
oneof: "«{field}»: допустимые значения — {values}",
|
||
gt: "«{field}»: значение должно быть больше {gt}",
|
||
peer_name:
|
||
"«{field}»: от {min} до {max} символов из набора {charset}. Пробелы, кириллица и знаки / : ; . недопустимы",
|
||
// Сервер присылает границы и набор в params — фраза называет требование
|
||
// целиком. Прежнее «недопустимые символы» вдобавок описывало этими же
|
||
// словами отказ по ДЛИНЕ: правило одно, и оно проверяет и то, и другое.
|
||
credential_format:
|
||
"«{field}»: от {min} до {max} символов из набора {charset}",
|
||
admin_password_format:
|
||
"«{field}»: от {min} до {max} символов и не более {maxBytes} байт в UTF-8, без управляющих символов и U+FEFF",
|
||
rule_violated: "«{field}»: значение не подходит",
|
||
validation_failed: "Проверка данных не пройдена",
|
||
body_invalid: "Запрос не разобран: проверьте формат и типы полей",
|
||
peer_name_taken: "Пир с таким именем уже существует",
|
||
peer_name_reserved: "Это имя зарезервировано за пиром установщика",
|
||
peer_bootstrap_identity_locked:
|
||
"Имя и секрет пира установщика продублированы в файле на сервере и не меняются через панель. Ненужный bootstrap-пир следует удалить целиком.",
|
||
invalid_credentials: "Неверный логин или пароль",
|
||
// Фраза обязана начинаться с того, что УЖЕ СДЕЛАНО: иначе оператор
|
||
// прочитает её как «операция не выполнена» и повторит действие, которое
|
||
// на самом деле применилось.
|
||
//
|
||
// И она НЕ называет конкретную операцию. Этим кодом отчитываются
|
||
// отключение пира, временная блокировка, смена секрета, урезание квоты и
|
||
// срока, снижение лимита устройств, импорт партии и удаление пира;
|
||
// прежнее «новые подключения пира запрещены» было верно ровно для
|
||
// первого случая, а для удалённого пира — просто бессмысленно.
|
||
peer_disconnect_failed:
|
||
"Изменения сохранены, но завершить связанные активные сессии не удалось: Traffic Stats API Hysteria недоступен. Установленные соединения могут работать до переподключения клиента. Проверьте состояние службы hysteria-server и повторите действие.",
|
||
import_file_extension: "Импорт принимает только файлы .json",
|
||
unauthorized: "Требуется вход в панель",
|
||
session_expired: "Сессия истекла",
|
||
token_invalid: "Сессия недействительна",
|
||
account_disabled: "Учётная запись отключена",
|
||
},
|
||
},
|
||
sidebar: {
|
||
// {brand} подставляется ссылкой, поэтому фраза обязана остаться одной
|
||
// строкой с одним подстановочным местом.
|
||
developedBy: "Разработано во {brand}",
|
||
},
|
||
info: {
|
||
expireTime: "г-М-д Ч:м:с",
|
||
greeting1: "Доброе утро,",
|
||
greeting2: "Доброе утро,",
|
||
greeting3: "Добрый день,",
|
||
greeting4: "Добрый вечер,",
|
||
greeting5: "Доброй ночи,",
|
||
},
|
||
peer: {
|
||
name: "Пир",
|
||
remark: "Комментарий",
|
||
secret: "Секрет",
|
||
form: {
|
||
namePlaceholder: "client-01",
|
||
// Набор символов назван так, как его понимает service.IsValidPeerName.
|
||
// Прежняя формулировка «латиница, цифры и дефис» осталась от правила,
|
||
// действовавшего до EX-03: подсказка обещала более узкий набор, чем
|
||
// сервер принимает, и оператор не имел причин пробовать остальные.
|
||
nameHint:
|
||
"Идентификатор пира: от {min} до {max} символов — латиница, цифры и знаки {punctuation}. Имя попадает в автогенерируемый секрет и показывается клиенту как название профиля.",
|
||
remarkPlaceholder: "ноутбук",
|
||
remarkHint: "Необязательная пометка для оператора. Клиент её не видит.",
|
||
secretPlaceholder: "оставьте пустым — сгенерируем",
|
||
secretHint:
|
||
"Пароль подключения клиента. Если оставить поле пустым, секрет будет сгенерирован автоматически. При ручном вводе: от 6 до 128 символов.",
|
||
quotaHint: "Лимит трафика в байтах. Укажите -1 для безлимита.",
|
||
},
|
||
maxDevices: "Лимит устройств",
|
||
disabled: "Отключён",
|
||
status: "Статус",
|
||
traffic: "Трафик",
|
||
devices: "Устройства",
|
||
lastConnectionAt: "Последнее подключение",
|
||
overview: "Обзор",
|
||
authId: "Auth ID",
|
||
clientUri: "URI клиента",
|
||
clientQr: "QR клиента",
|
||
unlimited: "Безлимит",
|
||
secretRotateConfirm:
|
||
"Сменить секрет пира? Текущие клиентские конфиги перестанут работать до обновления.",
|
||
exportSettings: "Экспорт настроек",
|
||
exportBackup: "Резервная копия",
|
||
exportSettingsHint:
|
||
"Список пиров без секретов. Безопасно хранить и передавать, но после импорта на другой сервер пирам будут выданы новые секреты, и прежние клиентские ссылки работать не будут.",
|
||
exportBackupConfirm:
|
||
"Резервная копия содержит ДЕЙСТВУЮЩИЕ секреты подключения всех пиров в открытом виде: любой, кто получит этот файл, получит доступ к VPN. Храните его как пароль и удалите, когда перенос завершён. Только такая копия сохраняет работоспособность существующих клиентских ссылок после переноса на другой сервер.",
|
||
exportBackupConfirmButton: "Понимаю, скачать копию с секретами",
|
||
quota: "Квота",
|
||
download: "Скачано",
|
||
upload: "Отдано",
|
||
expireTime: "Срок действия",
|
||
kickUtilTimeLast: "Осталось офлайн",
|
||
kickUtilTime: "Отключить до",
|
||
deviceNo: "Лимит устройств",
|
||
onlineStatus: "Онлайн",
|
||
online: "Онлайн",
|
||
offline: "Офлайн",
|
||
onlineUnknown: "Онлайн неизвестен",
|
||
onlineUnavailable: "Картина подключений сейчас недоступна",
|
||
onlineUnavailableHint:
|
||
"Traffic Stats API Hysteria не ответил, поэтому онлайн и число устройств неизвестны. Сохранённое состояние пиров в таблице верно.",
|
||
device: "Устройства",
|
||
createdAt: "Создан",
|
||
bannedUntil: "Блокировка до",
|
||
totalTraffic: "Суммарный трафик",
|
||
copyUri: "Копировать URI",
|
||
more: "Ещё",
|
||
loginAt: "Последний вход",
|
||
conAt: "Последнее подключение",
|
||
createTime: "Создано",
|
||
releaseSuccess: "Ограничение снято",
|
||
kick: "Временно заблокировать",
|
||
kickTip: "Прервать соединение и не пускать до истечения срока",
|
||
kickConfirm:
|
||
"Заблокировать пир «{name}» до {until}? Текущее соединение будет разорвано, новые подключения до этого времени приниматься не будут.",
|
||
kickSuccess: "Пир временно заблокирован",
|
||
releaseKick: "Снять блокировку",
|
||
releaseKickTip: "Снять временную блокировку досрочно",
|
||
// Отключение и временная блокировка — разные механизмы: у блокировки есть
|
||
// срок, который истекает сам, отключение снимается только руками.
|
||
enablePeer: "Включить пир",
|
||
disablePeer: "Отключить пир",
|
||
disableConfirm:
|
||
"Отключить пир «{name}»? Текущее соединение будет разорвано, а новые подключения запрещены, пока пир не будет включён обратно.",
|
||
enableSuccess: "Пир включён",
|
||
disableSuccess: "Пир отключён",
|
||
},
|
||
config: {
|
||
orchestratorManaged: "Управляется hy2xs-orchestrator reconfigure",
|
||
resetTrafficCron: "Расписание сброса трафика",
|
||
resetTrafficCronTip:
|
||
"Cron-выражение для планового сброса трафика. Пустое значение отключает автоматический сброс",
|
||
resetTrafficMonth: "Раз в месяц, в полночь первого дня",
|
||
resetTrafficWeek: "Раз в неделю, в полночь между субботой и воскресеньем",
|
||
},
|
||
// Раздел `monitor` удалён вместе со своим единственным потребителем —
|
||
// плашкой «Статус Hysteria2» на странице конфигурации. Состояние службы
|
||
// имеет три значения, а не два, и его фразы живут в `dashboard.serviceState`:
|
||
// «остановлена» и «неизвестно» — разные ответы оператору.
|
||
log: {
|
||
numLine: "Количество строк",
|
||
level: "Уровень",
|
||
message: "Сообщение",
|
||
time: "Время",
|
||
exportFailed: "Не удалось выгрузить журнал",
|
||
},
|
||
errorPage: {
|
||
back: "Назад",
|
||
oops: "Упс!",
|
||
forbiddenTitle: "У вас нет прав для доступа к этой странице",
|
||
forbiddenGo: "Или вы можете перейти:",
|
||
backHome: "На главную",
|
||
forbiddenImageAlt: "Девочка уронила своё мороженое.",
|
||
notFoundHeadline: "Вебмастер сообщил, что вам нельзя на эту страницу...",
|
||
notFoundInfo:
|
||
"Проверьте правильность URL или нажмите кнопку ниже, чтобы вернуться на главную страницу.",
|
||
notFoundBackHome: "На главную",
|
||
},
|
||
hysteria: {
|
||
hysteria2Version: "Версия Hysteria2",
|
||
ownedByOrchestrator: "Конфигурацией Hysteria владеет установщик",
|
||
ownedByOrchestratorHint:
|
||
"Панель показывает файл /etc/hysteria/config.yaml только на чтение. Изменения вносит `hy2xs-orchestrator reconfigure`.",
|
||
// Разделы production-профиля. Экран показывает то, что записано в файле,
|
||
// и отдельно называет секции сверх профиля: универсального редактора всех
|
||
// возможностей Hysteria здесь нет намеренно — конфиг создаёт оркестратор.
|
||
listen: "Адрес прослушивания",
|
||
auth: "Авторизация пиров",
|
||
tls: "TLS",
|
||
obfs: "Маскировка",
|
||
quic: "Параметры QUIC",
|
||
bandwidth: "Полоса",
|
||
congestion: "Congestion control",
|
||
trafficStats: "Traffic Stats API",
|
||
notSet: "не задано",
|
||
sectionMissing: "Секция в конфигурации отсутствует",
|
||
tlsMissing: "Ни tls, ни acme в конфигурации не заданы",
|
||
valuesHidden: "значения не показываются",
|
||
secretSet: "задан",
|
||
secretMissing: "не задан",
|
||
obfsPasswordHint: "выдаётся в клиентской ссылке пира",
|
||
driftTitle: "Расхождение конфигурации",
|
||
driftHint:
|
||
"В файле есть секции вне production-профиля HY2XS. Оркестратор их не создаёт и не поддерживает: скорее всего, конфигурацию правили вручную.",
|
||
trafficStatsMissing: "Traffic Stats API не настроен",
|
||
trafficStatsMissingHint:
|
||
"Без секции trafficStats не работают лимит устройств, учёт трафика и принудительное отключение: панель обращается к Hysteria только через этот API.",
|
||
// Две разные новости об одном поле, и объединять их нельзя: первая
|
||
// означает, что доступ пиров уже не работает, вторая — что API работает, но
|
||
// опубликован шире необходимого. Прочие адреса loopback (127.0.0.5 и
|
||
// подобные) относятся к ПЕРВОЙ: слушатель на конкретном адресе соединения
|
||
// на 127.0.0.1 не принимает.
|
||
trafficStatsUnreachable:
|
||
"панель не может обратиться по этому адресу: Traffic Stats API запрашивается строго через 127.0.0.1. Пока адреса расходятся, лимит устройств, учёт трафика и принудительное отключение не работают",
|
||
trafficStatsWildcard:
|
||
"API доступен, но слушает все интерфейсы. Production-профиль HY2XS использует 127.0.0.1: выполните hy2xs-orchestrator reconfigure",
|
||
},
|
||
};
|