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>
205 lines
7.1 KiB
TypeScript
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;
|