257 lines
16 KiB
TypeScript
257 lines
16 KiB
TypeScript
// THE catalogue of Russian interface strings. The only file in `src/` where interface wording
|
||
// lives, and one of the two the Cyrillic gate lets through (eslint.config.js, and the sweep in
|
||
// `src/i18n/catalogue.test.ts` — the other one is the fixtures).
|
||
//
|
||
// What belongs here: every word the user reads — labels, hints, empty states, accessible names,
|
||
// tooltips. What does NOT: the prose of the fixtures (`src/mock/`), which is DATA standing in for a
|
||
// book, and the phrases the platform sends in `problem+json`, which are the server's to word.
|
||
//
|
||
// Keys read `area.thing`. A key that is not here fails the typecheck at its call site, because
|
||
// `MessageKey` is derived from this object.
|
||
//
|
||
// A second language is a second file of the same shape plus a line in `language.ts` — no component
|
||
// is touched. WHICH languages the product speaks is the owner's decision (BACKLOG Ф-35), so no
|
||
// translation is invented here.
|
||
|
||
export const ru = {
|
||
'action.cancel': 'Отмена',
|
||
// The window is closed by the cross in its corner; this is the word for "I have read it, we are
|
||
// done" — a different act, and a different button.
|
||
'action.done': 'Готово',
|
||
|
||
'shell.appName': 'TextMachine',
|
||
'shell.collapseLeft': 'Свернуть левую панель',
|
||
'shell.collapseRight': 'Свернуть правую панель',
|
||
'shell.documentsPanel': 'Открытые документы',
|
||
'shell.expandLeft': 'Развернуть левую панель',
|
||
'shell.expandRight': 'Развернуть правую панель',
|
||
'shell.gotoAction': 'Перейти к разделу или термину',
|
||
'shell.settingsAction': 'Настройки',
|
||
|
||
'library.addBook': 'Добавить книгу',
|
||
'library.booksTab': 'Книги',
|
||
'library.chapterProgress': 'переведено {done} из {total}',
|
||
'library.chapterRange': 'разделы {from}–{to}',
|
||
'library.chaptersFailed': 'разделы не загрузились',
|
||
'library.chaptersLoading': 'загрузка разделов…',
|
||
'library.emptyCentreDescription': 'Добавьте книгу — её разделы откроются здесь вкладками.',
|
||
'library.emptyCentreTitle': 'Библиотека пуста',
|
||
'library.emptyDescription':
|
||
'Добавьте книгу — она разберётся на разделы и станет доступна к переводу.',
|
||
'library.emptyTitle': 'Ни одной книги',
|
||
'library.failedDescription': 'Список книг не загрузился. Обновите страницу — ничего не потеряно.',
|
||
'library.failedTitle': 'Библиотека недоступна',
|
||
'library.notesFew': 'замечания',
|
||
'library.notesMany': 'замечаний',
|
||
'library.notesOne': 'замечание',
|
||
'library.notesOther': 'замечаний',
|
||
'library.notesTwo': 'замечания',
|
||
'library.notesZero': 'замечаний',
|
||
'library.panel': 'Библиотека',
|
||
'library.treeLabel': 'Книги и разделы',
|
||
|
||
'document.draftNote': 'черновой вариант, может быть перегенерирован',
|
||
'document.draftTooltip':
|
||
'Прогон над книгой ещё идёт: текст, названия разделов и их число могут измениться при следующем проходе',
|
||
'document.nothingOpenDescription': 'Выберите раздел книги слева — он откроется здесь вкладкой.',
|
||
'document.nothingOpenTitle': 'Ничего не открыто',
|
||
|
||
'reader.emptyDescription': 'В этом разделе нет текста для сравнения.',
|
||
'reader.emptyTitle': 'Раздел пуст',
|
||
'reader.missingTarget': 'перевод не получен',
|
||
'reader.waiting': 'Раздел',
|
||
|
||
'bank.awaitingSignature': 'банк ждёт подписи',
|
||
'bank.columnKind': 'Тип',
|
||
'bank.columnSense': 'Смысл',
|
||
'bank.columnTerm': 'Термин',
|
||
'bank.columnTranslation': 'Перевод',
|
||
'bank.empty': 'Ничего не нашлось',
|
||
'bank.emptyDescription': 'Термины книги появятся после первого прохода перевода.',
|
||
'bank.emptyTitle': 'Банк пуст',
|
||
'bank.hideSenses': 'Скрыть смыслы терминов',
|
||
'bank.kindAll': 'все',
|
||
'bank.kindFilter': 'Тип термина',
|
||
'bank.noTranslation': 'не предложен',
|
||
'bank.search': 'Поиск по банку',
|
||
'bank.showSenses': 'Показать смыслы терминов',
|
||
'bank.shown': 'показано {shown} из {total}',
|
||
'bank.tab': 'Банк',
|
||
'bank.tableLabel': 'Термины банка',
|
||
'bank.termsFew': 'термина',
|
||
'bank.termsMany': 'терминов',
|
||
'bank.termsOne': 'термин',
|
||
'bank.termsOther': 'терминов',
|
||
'bank.termsTwo': 'термина',
|
||
'bank.termsZero': 'терминов',
|
||
'bank.waiting': 'Банк памяти',
|
||
'bank.windowSince': 'с {chapter}-го',
|
||
'bank.windowUntil': 'по {chapter}-й',
|
||
|
||
'notes.empty': 'Замечаний нет',
|
||
'notes.emptyDescription': 'В этой книге нет мест, требующих внимания.',
|
||
'notes.emptyTitle': 'Замечаний нет',
|
||
'notes.listLabel': 'Замечания книги',
|
||
'notes.tab': 'Замечания',
|
||
|
||
'about.added': 'Добавлена',
|
||
'about.blocks': 'Блоков',
|
||
'about.ceiling': 'Потолок прогона',
|
||
'about.chaptersFew': 'раздела',
|
||
'about.chaptersMany': 'разделов',
|
||
'about.chaptersOne': 'раздел',
|
||
'about.chaptersOther': 'разделов',
|
||
'about.chaptersTwo': 'раздела',
|
||
'about.chaptersZero': 'разделов',
|
||
'about.chapters': 'Разделов',
|
||
'about.characters': 'Знаков',
|
||
'about.genre': 'Жанр',
|
||
'about.languages': 'Языки',
|
||
'about.no': 'нет',
|
||
'about.noBooksDescription': 'Добавьте книгу — сведения о ней появятся здесь.',
|
||
'about.noBooksTitle': 'Книг пока нет',
|
||
'about.notes': 'Замечаний',
|
||
'about.panel': 'О читаемой книге',
|
||
'about.parsing':
|
||
'Книга разбирается на разделы. Они появятся в дереве слева, когда разбор дойдёт до них.',
|
||
'about.uploading': 'Файл ещё загружается. Разбор начнётся, когда он дойдёт целиком.',
|
||
'about.runFinished': 'Прогон завершён',
|
||
'about.runStarted': 'Прогон начат',
|
||
'about.status': 'Состояние',
|
||
'about.tab': 'О книге',
|
||
'about.title': 'Название',
|
||
'about.translated': 'Переведено',
|
||
'about.verifyBank': 'Остановка на подписи',
|
||
'about.yes': 'да',
|
||
|
||
'goto.chapter': 'раздел',
|
||
'goto.empty': 'Ничего не нашлось',
|
||
'goto.field': 'Название раздела или термин',
|
||
'goto.results': 'Результаты перехода',
|
||
'goto.term': 'термин',
|
||
'goto.termRow': '{src} — {dst}',
|
||
'goto.termWithWindow': '{src} — {dst} · с {chapter}-го',
|
||
'goto.title': 'Перейти',
|
||
'goto.truncated': 'Показаны первые {count} совпадений.',
|
||
|
||
'addBook.acceptedDescription': 'Файл принят целиком. Разбор на разделы идёт сам.',
|
||
'addBook.acceptedTitle': 'Книга загружена',
|
||
'addBook.chooseFile': 'Выбрать файл',
|
||
'addBook.fileLabel': 'Файл книги',
|
||
'addBook.genreLabel': 'Жанр',
|
||
'addBook.genrePlaceholder': 'не обязательно',
|
||
'addBook.sending': 'Файл отправляется',
|
||
'addBook.sendingSize': 'отправлено {sent} из {total}',
|
||
'addBook.sendingUnknown': 'Файл отправляется: {total}',
|
||
'addBook.sent': 'Файл отправлен целиком — ждём ответа сервиса.',
|
||
'addBook.sourceLangLabel': 'Язык оригинала',
|
||
'addBook.submit': 'Добавить',
|
||
'addBook.targetLangLabel': 'Язык перевода',
|
||
'addBook.title': 'Добавить книгу',
|
||
// ⚠ Без «поправить позже»: переименовать книгу нечем — на всей поверхности контракта у книги
|
||
// нет ни одной записи (Ф-62), и обещать правку, которой нет, интерфейс не вправе.
|
||
'addBook.titleHintAuto': 'Поле пустое: название определит разбор файла.',
|
||
'addBook.titleHintManual': 'Название задано вручную: разбор его не перепишет.',
|
||
'addBook.titleLabel': 'Название',
|
||
'addBook.titlePlaceholder': 'по умолчанию — из файла',
|
||
|
||
'upload.badRequest': 'Форма не дошла целиком',
|
||
// Отдельный совет от общего «повторите»: если форма не дошла второй раз, повтор третий раз
|
||
// ничего не изменит — и честно сказать, что это уже наша сторона.
|
||
'upload.badRequestAdvice': 'Попробуйте ещё раз. Если повторится — дело не в файле, а в нас.',
|
||
'upload.failedTitle': 'Книга не загрузилась',
|
||
'upload.notAccepted': 'Этот сервис не принимает книги',
|
||
'upload.notAcceptedAdvice': 'Файл здесь ни при чём — загрузка недоступна на этом сервисе.',
|
||
'upload.refused': 'Сервис не принял файл',
|
||
'upload.refusedAdvice': 'Попробуйте ещё раз позже.',
|
||
'upload.retryAdvice': 'Попробуйте отправить файл ещё раз.',
|
||
'upload.timeout': 'Файл не успел дойти',
|
||
'upload.tooLarge': 'Файл больше, чем сервис принимает',
|
||
'upload.tooLargeAdvice': 'Выберите файл поменьше.',
|
||
|
||
'rejected.notConfigured': 'Сервис пока не готов принять эту книгу',
|
||
'rejected.notConfiguredAdvice':
|
||
'Файл здесь ни при чём: повторная загрузка поможет не раньше, чем мы это наладим.',
|
||
'rejected.parserUnavailable': 'Не удалось обработать файл на нашей стороне',
|
||
'rejected.parserUnavailableAdvice': 'Файл здесь ни при чём: попробуйте добавить книгу позже.',
|
||
'rejected.sourceUnreadable': 'Файл не удалось разобрать на разделы',
|
||
'rejected.sourceUnreadableAdvice':
|
||
'Проверьте файл — возможно, это не текст книги — и добавьте её заново.',
|
||
'rejected.unknown': 'Книгу не удалось принять',
|
||
'rejected.unknownAdvice': 'Причина не названа. Попробуйте добавить книгу заново или позже.',
|
||
|
||
'run.action': 'Перевести',
|
||
'run.ceilingHint': 'Прогон остановится, дойдя до этого числа разделов.',
|
||
// Не называет причину: 409 приходит и на уехавший потолок, и на прогон, который уже идёт, и на
|
||
// книгу, которая ещё не готова — платформа называет причину сама, а это совет на все случаи.
|
||
'run.conflict': 'Запустить не удалось: состояние книги изменилось',
|
||
'run.conflictAdvice': 'Форма и карточка книги обновлены — посмотрите их и попробуйте снова.',
|
||
// Не называет причину: ноль на шкале приходит и от исчерпанного остатка, и от книги, которая
|
||
// переведена целиком (контракт: максимум уже подрезан обоими).
|
||
'run.exhaustedDescription': 'Сейчас доступно ноль разделов — начинать нечего.',
|
||
'run.exhaustedTitle': 'Запустить прогон сейчас нельзя',
|
||
'run.failedTitle': 'Прогон не начался',
|
||
'run.title': 'Перевести книгу',
|
||
'run.unavailable': 'Перевод сейчас запустить нельзя',
|
||
'run.unavailableAdvice': 'Попробуйте позже.',
|
||
'run.verifyBank': 'Остановиться на подписи банка',
|
||
'run.verifyBankHint': 'Перед финальным проходом прогон остановится, чтобы вы подписали термины.',
|
||
'run.waiting': 'Параметры запуска',
|
||
|
||
'settings.defaultsAbout':
|
||
'Что подставлять в форму запуска: пара языков, потолок, остановка на подписи.',
|
||
'settings.defaultsName': 'Перевод по умолчанию',
|
||
'settings.languageAbout': 'Сейчас интерфейс только русский.',
|
||
'settings.languageName': 'Язык интерфейса',
|
||
'settings.note': 'Разделы наполняются отдельным пакетом работ.',
|
||
'settings.profileAbout': 'Учётная запись, вход, завершение сеансов.',
|
||
'settings.profileName': 'Профиль и доступ',
|
||
'settings.themeAbout': 'Сейчас доступна только тёмная.',
|
||
'settings.themeName': 'Светлая тема',
|
||
'settings.title': 'Настройки',
|
||
'settings.usageAbout': 'Сколько израсходовано и что будет при исчерпании лимита.',
|
||
'settings.usageName': 'Использование',
|
||
|
||
'status.awaitingBank': 'нужна подпись',
|
||
'status.failed': 'ошибка',
|
||
'status.finalizing': 'финал',
|
||
'status.liveProgressLost': 'живой прогресс недоступен',
|
||
'status.notStarted': 'в очереди',
|
||
'status.parsing': 'разбор',
|
||
'status.paused': 'остановлена: лимиты',
|
||
'status.ready': 'готова',
|
||
'status.rejected': 'не разобрана',
|
||
'status.remaining': 'осталось {time}',
|
||
'status.stopped': 'остановлена',
|
||
'status.translated': 'переведено {percent}%',
|
||
'status.translating': 'перевод',
|
||
'status.unknown': 'неизвестное состояние',
|
||
'status.uploading': 'загрузка',
|
||
|
||
'paused.creditExhausted': 'перевод остановлен: лимиты исчерпаны',
|
||
'paused.unknown': 'перевод остановлен',
|
||
|
||
'kind.name': 'имя',
|
||
'kind.nickname': 'прозвище',
|
||
'kind.place': 'место',
|
||
'kind.term': 'термин',
|
||
'kind.title': 'титул',
|
||
'kind.undecided': 'тип не определён',
|
||
|
||
'loaded.failedTitle': 'Не удалось загрузить',
|
||
'loaded.noBookDescription': 'Выберите книгу слева — сведения о ней появятся здесь.',
|
||
'loaded.noBookTitle': 'Книга не выбрана',
|
||
'loaded.serverRefused': 'Сервер ответил отказом.',
|
||
'loaded.serverUnreachable': 'Сервер недоступен. Попробуйте ещё раз.',
|
||
'loaded.unknownError': 'Неизвестная ошибка.',
|
||
|
||
'blank.loading': 'Идёт загрузка.',
|
||
|
||
'modal.close': 'Закрыть',
|
||
|
||
'time.hours': '{count} ч',
|
||
'time.minutes': '{count} мин',
|
||
'time.underMinute': 'меньше минуты',
|
||
} as const;
|
||
|
||
export type MessageKey = keyof typeof ru;
|