Files
Randify.pro/src/i18n/dm-translations.ts
T
emilandClaude Opus 4.7 701398f627 feat(dm-dashboard): Wave 7 — FREE→PRO data import flow (Task 22)
Adds an opt-in modal that prompts a PRO user with local data to migrate
their localStorage notes and sessionStorage initiative into the cloud.

- src/lib/client/import.ts: pure helpers (hasLocalData, shouldShowImport)
- src/components/dm/ImportModal.astro: modal UI + import orchestration
  with conflict handling for existing "DM Notes" record
- src/i18n/dm-translations.ts: 14 new keys for the import flow
- Wired into both EN and RU dm/index.astro
- tests/import-flow.test.ts: 18 unit tests on the helpers

Local storage is preserved as backup; only a "dm-import-asked" flag is
set after the user makes a decision (import or skip).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-15 23:33:39 +03:00

205 lines
7.1 KiB
TypeScript

export const dmTranslations = {
// Header / navigation
title: "DM Dashboard",
subtitle: "Инструменты для мастера подземелий",
backToRandify: "← Назад к Randify",
footer: "Часть Randify — генераторов случайных значений",
// Legacy anchor labels (kept for backwards compatibility)
dice: "Кубики",
initiative: "Инициатива",
reference: "Справочник",
notes: "Заметки",
ai: "ИИ",
anchorDice: "Кубики",
anchorInitiative: "Инициатива",
anchorReference: "Справочник",
anchorNotes: "Заметки",
anchorAi: "ИИ",
// Tab labels
tabDice: "Кубики",
tabInitiative: "Инициатива",
tabReference: "Справочник",
tabNotes: "Заметки",
tabAi: "✦ ИИ",
// Sidebar sections
sidebarTools: "ИНСТРУМЕНТЫ",
sidebarReference: "СПРАВОЧНИК",
sidebarCampaigns: "Кампании",
sidebarCharacters: "Персонажи",
// Action labels
actionRoll: "Бросить",
actionNextTurn: "Следующий ход",
actionClear: "Очистить",
actionAdd: "+ Добавить",
actionSaved: "Сохранено",
actionCopy: "Скопировать",
actionSearch: "Поиск",
actionClose: "Закрыть",
actionRetry: "Повторить",
// Empty states
emptyDiceHistory: "Нет истории бросков",
emptyCombatants: "Нет участников боя",
emptySearchResults: "Ничего не найдено",
emptyNotesPlaceholder: "Начните писать заметки...",
// Loading states
loading: "Загрузка...",
searching: "Поиск...",
// Translation
translate: "Перевести",
translating: "Перевод...",
translated: "Переведено",
translateError: "Ошибка перевода",
// Open5e tabs
monsters: "Монстры",
spells: "Заклинания",
// Initiative
turnBadge: "Ход",
modifier: "Модификатор",
name: "Имя",
hp: "ХП",
// Dice
customFormula: "Своя формула",
rollHistory: "История бросков",
criticalHit: "Критический успех!",
criticalFail: "Критический провал!",
resultLabel: "Результат",
rollsLabel: "Броски",
invalidNotation: "Неверная нотация",
ariaQuickDice: "Быстрый выбор кубика",
ariaRollHistory: "История бросков",
// Initiative
turnOrder: "Порядок хода",
initiativeTotal: "Итого",
initiativeHelp: "Бросок d20 + модификатор, или введите итог вручную",
ariaCombatants: "Участники боя",
// AI
aiTitle: "Генератор ИИ",
aiSignInCta: "Войдите, чтобы использовать ИИ",
aiPlaceholder: "Генератор ИИ появится здесь",
// AI Form
aiFormRace: "Раса",
aiFormRole: "Класс / Роль",
aiFormLevel: "Уровень",
aiFormTone: "Тон",
aiFormUseReference: "Использовать справочник Open5e",
aiFormSubmit: "Сгенерировать NPC",
aiFormSelectOption: "Выберите...",
// Races
raceHuman: "Человек",
raceElf: "Эльф",
raceDwarf: "Дварф",
raceHalfling: "Полурослик",
raceOrc: "Орк",
raceTiefling: "Тифлинг",
raceDragonborn: "Драконорождённый",
raceGnome: "Гном",
raceHalfElf: "Полуэльф",
raceHalfOrc: "Полуорк",
// Roles
roleWarrior: "Воин",
roleMage: "Маг",
roleRogue: "Плут",
roleCleric: "Жрец",
roleRanger: "Следопыт",
rolePaladin: "Паладин",
roleBard: "Бард",
roleBarbarian: "Варвар",
roleDruid: "Друид",
roleWarlock: "Колдун",
// Tones
toneSerious: "Серьёзный",
toneHumorous: "Юмористический",
toneDark: "Тёмный",
toneHeroic: "Героический",
toneMysterious: "Загадочный",
// AI NPC Form
npcRace: "Раса",
npcRole: "Класс / Роль",
npcLevel: "Уровень",
npcTone: "Тон",
npcUseOpen5e: "Использовать справочник Open5e",
npcGenerate: "Сгенерировать NPC",
npcGenerating: "Генерация...",
npcErrorGeneric: "Ошибка генерации. Попробуйте снова.",
npcErrorRateLimit: "Превышен лимит генераций. Попробуйте через {minutes} мин.",
npcErrorValidation: "Проверьте введённые данные.",
// AI History
historyTitle: "История генераций",
historyEmptyPro: "Нет сохранённых NPC",
historyEmptyFree: "История сохраняется только для PRO",
historyUpgradeCta: "Перейти на PRO",
// NPC result card
npcName: "Имя",
npcHp: "ХП",
npcAc: "КЗ",
npcCr: "ОП",
npcSpeed: "Скорость",
npcAppearance: "Внешность",
npcTrait: "Черта",
npcMotivation: "Мотивация",
npcSecret: "Тайна",
npcHistory: "История",
npcCopyJson: "Копировать JSON",
npcCopied: "Скопировано",
npcRegenerate: "Перегенерировать",
saveSession: "Сохранить сессию",
newSession: "Новая сессия",
sessionNamePlaceholder: "Название сессии",
noSavedSessions: "Нет сохранённых сессий",
sessionSaved: "Сессия сохранена",
saveError: "Ошибка сохранения",
loadSessionError: "Ошибка загрузки сессии",
deleteSessionConfirm: "Удалить сессию?",
noteSaveError: "Ошибка сохранения заметок",
noteLoadError: "Ошибка загрузки заметок",
// Auth
loginVk: "Войти через VK",
loginYandex: "Войти через Яндекс",
logout: "Выйти",
badgeFree: "FREE",
badgePro: "PRO",
// FREE → PRO import flow
importTitle: "Импортировать локальные данные?",
importPrompt:
"Вы получили доступ PRO. Хотите перенести существующие заметки и сессии инициативы в облако?",
importBtn: "Импортировать",
importSkip: "Пропустить",
importItemNotes: "Заметки",
importItemInitiative: "Участников боя",
importChars: "симв.",
importNotesProgress: "Перенос заметок…",
importInitiativeProgress: "Перенос инициативы…",
importInitiativeName: "Импорт",
importDone: "Готово",
importError: "Ошибка импорта. Локальные данные сохранены.",
importNotesConflict:
"В облаке уже есть заметки. Что сделать с локальной копией?",
importConflictKeepBoth: "Сохранить обе",
importConflictReplace: "Заменить",
importConflictSkip: "Пропустить заметки",
} as const;
export type DmT = typeof dmTranslations;