Newer
Older
gnexus-tasks / frontend / src / locales / ru.ts
// Русская локаль — источник правды ключей; en.ts/uk.ts типизируются как typeof ru.
// Namespaces по областям UI (см. план i18n): common, nav, stack, tree, list,
// options, projects, settings, taskui.

export default {
  common: {
    all: 'Все',
    noProject: '— без проекта —',
    none: '— нет —',
    choose: '— выберите —',
    notSet: '— не указано —',
    error: 'Ошибка запроса',
    save: 'Сохранить',
    cancel: 'Отмена',
    edit: 'Редактировать',
    preview: 'Предпросмотр',
    confirmTitle: 'Подтверждение',
    delete: 'Удалить',
    open: 'Открыть',
    move: 'Переместить',
    actions: 'Действия',
    expand: 'Развернуть',
    collapse: 'Свернуть',
    deleteConfirmTask: 'Удалить задачу «{title}»? Действие необратимо.',
    deleteConfirmProject: 'Удалить проект «{name}»? Задачи останутся, но без проекта.',
    archive: 'В архив',
    archiveTitle: 'Отправить в архив',
    saved: 'Сохранено',
    created: 'Создано',
    create: 'Создать',
    taskDeleted: 'Задача удалена',
    loading: 'Загрузка…',
    projectDeleted: 'Проект удалён',
    taskApproved: 'Задача утверждена',
    taskTaken: 'Задача взята в работу',
    taskFinished: 'Задача завершена',
    yes: 'Да',
    no: 'Нет',
    back: 'Назад',
  },
  nav: {
    sections: 'Разделы',
    subtitle: 'GNexus Tasks — личные задачи',
    signIn: 'Войти',
    account: 'Аккаунт',
    signOut: 'Выйти',
    task: 'Задача',
    home: 'Главная',
    stack: 'Стек входящих',
    list: 'Список задач',
    achievements: 'Достижения',
    stats: 'Статистика',
    projects: 'Проекты',
    archive: 'Архив',
    journal: 'Журнал',
    options: 'Выдача задачи',
    settings: 'Настройки',
    extension: 'Расширение',
  },
  // Прогресс: общий для страницы «Достижения» и сада (сад отключён в 0.58,
  // вернётся позже — тексты нейтральные, без растений и «садовника»)
  progress: {
    title: 'Достижения',
    level: 'Уровень {n}',
    xpTotal: '{n} XP',
    levelProgress: 'До уровня: {xp} / {span} XP',
    aboutOpen: 'Как это работает',
    aboutTitle: 'Как это работает',
    levelsTitle: 'Дерево званий',
    levelsHint:
      'Пороги XP и звания каждого уровня. Уровень растёт из опыта за задачи — ничего не сгорает и не отнимается.',
    levelCurrent: 'текущий',
    achievements: 'Достижения',
    coins: 'монет: {n}',
    coinsHint: 'Монеты за закрытые задачи, создание задач и проектов, новые уровни — копятся',
    achDone: 'Все ступени пройдены (высшая — {r})',
    achStep: 'Ступень: римская — номер, дробь — прогресс к следующей',
    about: [
      'Каждая закрытая задача приносит опыт и монеты — прогресс только растёт и никогда не уменьшается.',
      'За закрытие начисляется XP: база 10 + бонус за приоритет задачи (до 15) + бонус за объём работы по оценке времени (до 15) + 10 за «ментально сложную» — честная награда за силу воли. Крупные и срочные дела ценнее.',
      'Накопленный XP повышает уровень — от «Ростка» до «Легенды сада». Уровень не падает: XP не сгорает и не отнимается, даже если задачу удалить.',
      'Монеты приходят за закрытые задачи (столько же, сколько XP), за создание задач и проектов и за новые уровни. Сейчас они копятся — пригодятся, когда сад вернётся.',
      'Достижения отмечают вехи: закрытые задачи, уровни, разные проекты, часы работы, строгие дедлайны, «ментально сложные» задачи. У каждой ступени I, II, III — прогресс виден всегда.',
      'Задача, закрытая из режима «3 вариантов», отмечается меткой «выбрал и сделал». Закрытие «не хочется делать» празднуется золотом — сила воли того стоила. Ничего не сгорает, серий и наказаний нет — только приятные награды.',
    ],
    levels: [
      'Росток',
      'Сеянцев',
      'Садовник',
      'Огородник',
      'Дендролог',
      'Лесничий',
      'Садовый мастер',
      'Хранитель сада',
      'Королевский садовник',
      'Магистр садоводства',
      'Ландшафтный архитектор',
      'Хранитель легенд',
      'Легенда сада',
    ],
    ach: {
      firstDone: 'Первый росток',
      done10: 'Десяток',
      level5: 'Высоты',
      sprinter: 'Спринтер',
      explorer: 'Разносторонний',
      marathon: 'Марафонец',
      deadlineBoss: 'Дедлайн-босс',
      chooser: 'Выбрал и сделал',
      willpower: 'Преодоление',
      recurring: 'Ритм жизни',
      projectDone: 'Проект под ключ',
    },
    achHint: {
      firstDone: 'Закройте первую задачу — веха открыта.',
      done10: 'Закройте 10, 50 и 100 задач — по ступени за каждую веху.',
      level5: 'Достигните 5, 10 и 15 уровня.',
      sprinter: 'Закройте 3, 10 и 25 задач за один день.',
      explorer: 'Имейте закрытые задачи в 3, 5 и 8 разных проектах.',
      marathon: 'Накопите 10, 50 и 100 часов работы над задачами — по факту или оценке.',
      deadlineBoss: 'Закройте 5, 15 и 30 задач со строгим дедлайном-датой.',
      chooser: 'Закройте 5, 25 и 50 задач, взятых из режима «3 вариантов».',
      willpower: 'Закройте 5, 25 и 50 задач с меткой «не хочется делать».',
      recurring: 'Закройте регулярную задачу.',
      projectDone: 'Завершите проект целиком: все его задачи (от трёх) закрыты.',
    },
  },
  garden: {
    title: 'Сад',
    plants: 'растений: {n}',
    levelsHint:
      'Пороги XP и награды каждого уровня: новые виды растений (цена семени) и расширения карты. Уровень растёт из опыта за задачи — ничего не сгорает.',
    rewardCreateTask: 'создание задачи',
    rewardCreateProject: 'создание проекта',
    lastReward: 'Последняя награда за: {title} — {date}',
    emptyTitle: 'Сад пока пуст',
    emptyText: 'Закройте первую задачу — на грядке появится растение.',
    coins: 'монет: {n}',
    coinsHint: 'Валюта сада: тратится на рост растений и декорации',
    shop: 'Маркет',
    shopTitle: 'Маркет сада',
    buy: 'Купить',
    notEnoughCoins: 'Не хватает {n} монет',
    lockedUntil: 'Откроется на уровне {n}',
    expansion: 'Расширение сада',
    expansionHint: 'Больше земли — {n} клеток к периметру карты',
    expansionCurrent: 'Текущая карта: {cols}×{rows}',
    expansionMax: 'Вся земля открыта',
    inventory: 'Инвентарь',
    inventoryHint: 'Перетащите декорацию или семя на карту; декорацию можно вернуть обратно',
    inventoryEmpty: 'Пока пусто: купленные декорации ждут здесь — перетащите их на карту',
    zoomIn: 'Приблизить',
    zoomOut: 'Отдалить',
    zoomReset: 'Сбросить вид',
    fullscreen: 'Во весь экран',
    fullscreenExit: 'Выйти из полного экрана',
    boughtHint: 'Куплено: {name} — перетащите её из инвентаря под картой на сад',
    decorations: 'Декорации',
    decorationsHint: 'Украсьте сад — декорации не дают бонусов, только настроение',
    unique: 'уникальная',
    rareOnly: 'только редкие растения',
    seeds: 'Семена растений',
    seedsHint: 'Открытые уровнем виды можно купить: семя попадает в инвентарь — перетащите его на свободную клетку. Редкие/эпик рождаются только из задач.',
    seedBought: 'Семя куплено — перетащите его из инвентаря на грядку',
    speciesHint:
      'Опыт открывает новые виды и землю, монеты покупают семена, рост и украшения. Вид фиксируется за растением в момент рождения.',
    upgrade: 'Вырастить — {n} монет',
    maxStage: 'Полностью выросло',
    stage: { sprout: 'Росток', bush: 'Куст', bloom: 'Цветение' },
    speciesNames: {
      'ph-flower': 'Цветок',
      'ph-leaf': 'Зелень',
      'ph-tree-evergreen': 'Ель',
      'ph-flower-lotus': 'Лотос',
      'ph-cactus': 'Кактус',
      'ph-tree': 'Дуб',
      'ph-drop': 'Роса',
      'ph-sun': 'Подсолнух',
      'ph-tree-structure': 'Бонсай',
      'ph-butterfly': 'Бабочий куст',
      'ph-campfire': 'Рябина',
      'ph-sparkle': 'Звездоцвет',
      'ph-fire': 'Огнецвет',
    },
    decorNames: {
      fence: 'Изгородь',
      bush: 'Куст',
      flowerbed: 'Клумба',
      lantern: 'Фонарь',
      bench: 'Лавочка',
      birdbath: 'Поилка для птиц',
      flag: 'Флюгер',
      birdhouse: 'Скворечник',
      gem: 'Садовый самоцвет',
      pond: 'Пруд',
      greenhouse: 'Теплица',
      gazebo: 'Беседка',
    },
  },
  gamify: {
    praise: [
      'Отлично сделано!',
      'Готово — полдела!',
      'Ещё один шаг впереди.',
      'Красота!',
      'Так держать!',
      'Минус одна задача, плюс настроение.',
    ],
    chosen: 'выбрал и сделал',
    willpower: 'сила воли',
    willpowerText: 'Сила воли! Это того стоило.',
    coins: 'монет',
    createdReward: 'Создано — капля опыта уже ваша',
    daily: 'Ежедневная награда за визит',
    // Мандат ИИ-агента (ТЗ 3.20): события приходят по SSE из чужой сессии —
    // агент взял задачу или закрыл её и ждёт приёмки
    claimed: 'Агент взял задачу в работу',
    claimedText: '{name} взялась за дело — задачу не трогайте, пока она работает',
    review: 'Работа ждёт приёмки',
    reviewText: '«{title}» — посмотрите, что сделано, и примите или верните',
  },
  stats: {
    title: 'Статистика',
    modeDay: 'День',
    modeWeek: 'Неделя',
    modeMonth: 'Месяц',
    today: 'Сегодня, {date}',
    prevPeriod: 'Предыдущий период',
    nextPeriod: 'Следующий период',
    ofDays: 'из {n} дн.',
    totalVs: 'За период закрыто: {n} · в предыдущий раз: {m}',
    chartTitle: 'Закрытые задачи',
    legendNow: 'Сейчас',
    legendPrev: 'Предыдущий период',
    heatmapHalf: 'Активность за полгода',
    heatmapYear: 'Активность за год',
    heatTasks: 'Задачи',
    heatXp: 'XP',
    heatLess: 'меньше',
    heatMore: 'больше',
    heatHalf: 'Полгода',
    heatYear: 'Год',
    emptyTitle: 'Пока нет данных',
    emptyText: 'Закройте пару задач — и здесь появится динамика со сравнением.',
    metric: {
      closed: 'Закрыто задач',
      xp: 'XP получено',
      created: 'Создано задач',
      hours: 'Часы работы',
      activeDays: 'Дни с результатом',
    },
  },
  home: {
    title: 'Главное',
    stackCount: 'в стеке: {n}',
    activeCount: 'активных: {n}',
    inProgress: 'В работе',
    overdue: 'Просрочено',
    deadlines: 'Дедлайны на неделю',
    next: 'Следующие',
    overview: 'Обзор',
    projects: 'Активные проекты',
    totalTasks: 'Всего задач',
    doneMonth: 'Выполнено за месяц',
    doneAll: 'Выполнено всего',
    clearTitle: 'Всё спокойно',
    clearText: 'Нет активных задач — самое время закрыть что-то из стека.',
  },
  stack: {
    title: 'Стек входящих',
    count: 'Задач в стеке: {n}',
    quickPlaceholder: 'Закинуть задачу — только текст, остальное потом…',
    quickAdd: 'Закинуть',
    newTask: 'Новая задача',
    added: 'Задача закинута в стек',
    detailTitle: 'Детализация задачи',
    emptyTitle: 'Стек пуст',
    emptyText: 'Закиньте первую задачу — детализация подберётся автоматически.',
    inStack: 'в стеке',
    uploading: 'загрузка…',
    proposal: 'Предложение ИИ:',
    proposalPending: 'Детализация подбирается…',
    proposalNewProject: '+ проект «{name}»',
    approveProposal: 'Да, всё верно',
    detail: 'Детализировать',
    redetail: 'Переспросить ИИ',
    deleteTask: 'Удалить задачу',
    deleteAttachment: 'Удалить вложение',
    promptProject: 'Название нового проекта:',
    promptTag: 'Название нового тега:',
    newProject: 'Новый проект',
    newTag: 'Новый тег',
    approve: 'Утвердить',
    form: {
      title: 'Заголовок',
      description: 'Описание (Markdown, Ctrl+V — картинка)',
      preview: 'Предпросмотр Markdown',
      project: 'Проект',
      tagsPlaceholder: 'Добавить тег…',
      tags: 'Теги',
      priority: 'Приоритет',
      estimate: 'Оценка времени',
      budget: 'Бюджет (в валюте настроек)',
      cost: 'Оценка затрат (в валюте настроек)',
      estimateLegend: 'Оценка',
      extra: 'Дополнительно',
    },
    deadline: {
      legend: 'Дедлайн',
      date: 'Строгий — дата',
      period: 'Нестрогий — период',
    },
    recur: {
      legend: 'Тип задачи',
      oneTime: 'Разовая',
      recurring: 'Регулярная (повторяется)',
      kind: 'Правило повторения',
      interval: 'Интервал, дней',
      weekdays: 'Дни недели',
      monthlyDay: 'День месяца (1–31, без дня — последний)',
    },
  },
  tree: {
    addSubtask: 'Добавить подзадачу',
    promptSubtask: 'Подзадача:',
  },
  task: {
    notFoundTitle: 'Задача не найдена',
    notFoundText: 'Возможно, задача удалена или ссылка устарела.',
    proposalNewTitle: 'Новый заголовок',
    proposalNewDescription: 'Описание с шагами',
    proposalTitle: 'Предложение ИИ',
    proposalHint: 'Проверьте детали и утвердите — задача попадёт в список.',
    proposalNotRight: 'Не то',
    description: 'Описание',
    editTitle: 'Изменить название',
    editDescription: 'Редактировать описание',
    deadlineConflict: 'Дедлайн: либо дата, либо период — не оба',
    descriptionEmpty: 'Описание пусто — детализируйте задачу.',
    readmeFrom: 'README.md из репозитория',
    attachments: 'Вложения',
    fields: 'Параметры',
    dates: 'Даты',
    field: {
      project: 'Проект',
      taskType: 'Тип задачи',
      priority: 'Приоритет',
      estimate: 'Оценка времени',
      actual: 'Фактически',
      money: 'Деньги',
      deadline: 'Дедлайн',
      recurrence: 'Повторение',
      created: 'Создана',
      approved: 'Утверждена',
      done: 'Завершена',
    },
    subtasks: 'Подзадачи',
    noSubtasks: 'Подзадач нет',
    statusTitle: 'Статус',
    changeStatus: 'Изменить статус',
    takeWork: 'Взять в работу',
    finishWork: 'Завершено',
    // Закрытие с комментарием (ТЗ 3.20): у агента он обязателен, у владельца —
    // по желанию; из формы страницы задачи комментарий уходит в журнал
    finishTitle: 'Завершить задачу?',
    finishComment: 'Комментарий к закрытию (необязательно)',
    mentallyHard: {
      set: 'Не хочется делать',
      unset: 'Снять «ментально сложная»',
      badge: 'ментально сложная',
    },
    // Мандат ИИ-агента (ТЗ 3.20): пометки задачи и плашка аренды
    mandate: {
      eligible: 'Доступно для ИИ агента',
      eligibleHint: 'Задачу сможет взять Нави — ИИ-агент. Без пометки она её не трогает.',
      shortBadge: 'ИИ',
      createdBadge: 'создано агентом',
      createdBy: 'Задачу создал агент «{name}»',
      agent: 'агент',
      claimedUntil: 'Взято {name} · до {time}',
    },
    // Приёмка работы агента (ТЗ 3.20): работа закрыта, но не принята
    accept: {
      title: 'Приёмка работы',
      pendingBadge: 'ждёт приёмки',
      pendingHint: 'Задачу закрыл агент — работу нужно принять или вернуть',
      hint: 'Задачу закрыл {name}. Посмотрите, что сделано, и примите работу или верните её.',
      report: 'Отчёт агента',
      accept: 'Принять',
      reject: 'Вернуть в работу',
      accepted: 'Работа принята',
      rejected: 'Задача вернулась в работу',
      rejectTitle: 'Вернуть задачу в работу?',
      rejectComment: 'Что не так (необязательно)',
    },
    subtaskCreated: 'Подзадача создана — попала в стек на детализацию',
    createdRaw: 'Задача попала в стек — детализируйте её там',
    // Промпт для ИИ-агента (0.87): текст задачи, который владелец копирует и
    // передаёт своему агенту. Только факты о задаче — что с ней делать, решает
    // владелец, а не кнопка
    ai: {
      menu: 'Промпт для ИИ',
      title: 'Промпт для ИИ-агента',
      hint: 'Текст задачи для передачи ИИ-агенту. При необходимости поправьте и скопируйте.',
      copy: 'Скопировать промпт',
      close: 'Закрыть',
      intro: 'Задача из GNexus Tasks.',
      taskSection: 'Задача',
      descriptionSection: 'Описание',
      proposalSection: 'Детализация (предложение ИИ, не утверждено)',
      subtasksSection: 'Подзадачи',
      linkSection: 'Ссылка',
      id: 'ID',
      titleField: 'Заголовок',
      status: 'Статус',
      tags: 'Теги',
      parentTask: 'Родительская задача',
      eligible: 'Доступно для ИИ-агента',
      eligibleYes: 'да',
      eligibleNo: 'нет',
      claimed: 'Взято в работу',
      descriptionEmpty: 'Описание пусто.',
    },
    actions: 'Действия',
    addTag: 'Добавить тег…',
    // Проект задачи в меню карточки (0.82): перейти к проекту и перенести
    // в другой — соседние пункты, это один вопрос «в каком проекте задача»
    goToProject: 'Перейти к проекту',
    moveToProject: 'Переместить в проект',
    // Пункт меню карточки (0.83): «Переместить в проект» в китовом меню (220px)
    // рвалось на две строки, а в самом меню вопрос звучит как «в какой проект»
    moveToOther: 'В другой проект',
    moveHint: 'Задача «{title}» уедет в выбранный проект',
    moved: 'Задача перенесена в «{project}»',
    movedOut: 'Задача вынута из проекта',
  },
  projectPage: {
    notFoundTitle: 'Проект не найден',
    notFoundText: 'Возможно, проект удалён или ссылка устарела.',
    note: 'Заметка',
    editNote: 'Редактировать заметку',
    noteEmpty: 'Заметки пока нет — добавьте её через «Редактировать».',
    // README репозитория (0.67) — второе описание, отдельной карточкой
    readmeTitle: 'README из репозитория',
    readmeMissing: 'README в репозитории не найден — проверьте ссылку в параметрах проекта.',
    readmeError: 'Не получилось прочитать README — репозиторий не ответил.',
    noteCollapsedHint: 'Заметка большая — показано начало',
    noteExpand: 'Развернуть',
    noteCollapse: 'Свернуть',
    progress: 'Задачи проекта: {done}/{total}',
    newTask: 'Новая задача',
    taskCreated: 'Задача создана — попала в стек на детализацию',
    promptTask: 'Новая задача проекта:',
    emptyTitle: 'Задач нет',
    emptyText: 'Создайте первую задачу проекта или ослабьте фильтры.',
    tree: 'Дерево проекта',
    stats: 'Статистика',
    total: 'Всего задач',
    doneN: 'Завершено',
    inProgress: 'В работе',
    toDo: 'К выполнению',
    overdue: 'Просрочено',
    taskCount: '{n} задач',
    openSite: 'Открыть сайт',
    // Активность проекта (0.83): та же сетка «как в GitHub», что в статистике,
    // но по задачам одного проекта; полгода, карточка в сайдбаре страницы проекта
    activity: 'Активность',
    heatCell: '{date} — закрыто {done}, создано {created}',
    // Облако тегов (0.83): клик по тегу ставит подстрочный фильтр по его имени
    tagShow: 'Показать задачи с тегом «{name}»',
    tagHide: 'Снять фильтр по тегу «{name}»',
    tagCount: 'Задач с этим тегом: {n}',
  },
  list: {
    title: 'Список задач',
    count: 'Найдено: {n}',
    emptyTitle: 'Ничего не найдено',
    emptyText: 'Попробуйте ослабить фильтры или закиньте новую задачу в стек.',
    filterStatus: 'Статус',
    filterTag: 'Тег',
    filterTagSearch: 'Поиск по тегу',
    filterTagHint: 'Начните вводить название тега',
    filterTagClear: 'Сбросить фильтр по тегу',
    // Переключатель (0.74) вместо табов приоритета: фильтр остался один —
    // «выше среднего» (high и urgent), поэтому подпись читается по-человечески
    filterPrioritized: 'Приоритетные',
    // Второй переключатель (0.91, ТЗ 3.5): оставить в списке только регулярные.
    // Рядом с «Приоритетными» — два вопроса об одном списке читаются парой
    filterRecurring: 'Регулярные',
    noTagsFound: 'Теги не найдены',
    // Приёмка (0.85, ТЗ 3.20): не статус, а отдельная вкладка-плоскость
    tabReview: 'Ждёт приёмки',
    filterCreated: 'Кто создал',
    createdAll: 'Все задачи',
    createdMe: 'Созданные мной',
    createdAgent: 'Созданные агентом',
  },
  // Журнал действий (ТЗ 3.20): кто, что и когда делал с задачами
  journal: {
    title: 'Журнал',
    count: 'Записей: {n}',
    empty: 'Записей нет — тут появятся действия по задачам',
    filterKind: 'Тип события',
    filterKindAll: 'Все события',
    filterActor: 'Актор',
    filterActorAll: 'Все акторы',
    filterProject: 'Проект',
    filterProjectAll: 'Все проекты',
    actorUser: 'Я',
    actorAgent: 'Агент',
    col: {
      when: 'Когда',
      event: 'Событие',
      task: 'Задача',
      project: 'Проект',
      actor: 'Актор',
      comment: 'Комментарий',
    },
    // Виды записей — значения из tasklog.py, читаются человеческими словами
    kind: {
      created: 'Задача создана',
      eligible_changed: 'Доступность агенту',
      claimed: 'Взята агентом',
      released: 'Возвращена агентом',
      status_changed: 'Смена статуса',
      completed: 'Задача закрыта',
      accepted: 'Работа принята',
      rejected: 'Работа возвращена',
      deleted: 'Задача удалена',
    },
    // Машинные коды комментария у смены флага (on/off) и удалённый проект
    eligibleOn: 'Открыта для агента',
    eligibleOff: 'Закрыта для агента',
    projectGone: 'Проект удалён',
    taskDeleted: 'Задача удалена — заголовок сохранён в записи',
    via: {
      ui: 'из интерфейса',
      api: 'по API',
      mcp: 'через MCP',
    },
  },
  options: {
    title: 'Выдача задачи',
    done: 'Готово',
    notNow: 'Не сейчас — другие варианты',
    availableHours: 'Доступное время, часов',
    suggest: 'Предложить',
    choose: 'Делаем сейчас',
    emptyTitle: 'Вариантов нет',
    emptyText:
      'Свободных задач под это время не нашлось — закиньте что-нибудь в стек или уменьшите время.',
  },
  projects: {
    title: 'Проекты',
    count: 'Проектов: {n}',
    new: 'Новый проект',
    emptyTitle: 'Проектов нет',
    emptyText:
      'Создайте проект — задачи можно будет группировать и добавлять заметки с ресурсами.',
    prompt: 'Название нового проекта:',
    promptLabel: 'Название проекта',
    taskCounts: 'Задач закрыто {done}/{total}',
    noTasksYet: 'Задач в проекте пока нет',
    progressLabel: 'Закрыто {done} из {total}',
    inProgress: '{n} в работе',
    overdue: 'просрочено {n}',
    nextDeadline: 'Ближайший дедлайн: {date}',
    lastActivity: 'Последняя активность по задачам: {date}',
    noActivity: 'без активности',
    colorNone: 'Без цвета',
    sitePlaceholder: 'https://example.com',
    repositoryPlaceholder: 'https://git.example.com/owner/repo',
    withTasks: 'С задачами',
    withoutTasks: 'Без задач',
    pinned: 'Закреплённые',
    pinnedLabel: 'Закреплён',
    pin: 'Закрепить',
    unpin: 'Открепить',
    archived: 'Проект отправлен в архив',
    archiveConfirm:
      'Отправить проект «{name}» и его задачи ({n}) в архив? Всё можно будет восстановить из архива.',
    edit: 'Редактировать',
    delete: 'Удалить проект',
    form: {
      name: 'Название',
      relevance: 'Актуальность',
      priority: 'Приоритет',
      note: 'Заметка (Markdown: ссылки, контекст)',
      preview: 'Предпросмотр',
      color: 'Цвет',
      siteUrl: 'Сайт',
      repositoryUrl: 'Репозиторий',
    },
  },
  pagination: {
    prev: 'Назад',
    next: 'Вперёд',
    pageOf: 'Страница {n} из {m}',
    aria: 'Постраничная навигация',
  },
  archive: {
    title: 'Архив',
    count: 'Проектов: {n}',
    emptyTitle: 'Архив пуст',
    emptyText: 'Сюда попадают проекты, отправленные в архив, — вместе со всеми задачами и историей.',
    restore: 'Восстановить',
    restored: '«{name}» восстановлен из архива',
    deleteForever: 'Удалить навсегда',
    deleteConfirm:
      'Удалить «{name}» навсегда? Проект и все его задачи будут потеряны безвозвратно.',
    banner: 'Проект в архиве — история доступна только для просмотра. Восстановите его, чтобы продолжить работу.',
  },
  settings: {
    title: 'Настройки',
    currencyTitle: 'Валюта бюджетов',
    currencyHint:
      'Единица выбирается один раз и применяется во всех суммах: бюджет задачи, оценка затрат.',
    currencyUnit: 'Единица измерения',
    saved: 'Сохранено — применяется во всех видах.',
    languageTitle: 'Язык интерфейса',
    languageHint:
      'Выбранный язык применяется сразу. «Как в аккаунте» — язык берётся из gnexus auth.',
    languageUnit: 'Язык',
    languageAuto: 'Как в аккаунте (SSO)',
    langRu: 'Русский',
    langEn: 'English',
    langUk: 'Українська',
    mcpTokenTitle: 'Токены MCP',
    mcpTokenHint:
      'Токен для ИИ-агента (например, Claude): агент действует от вашего имени и видит только ваши данные. Значение показывается один раз при создании — сразу скопируйте и вставьте в конфиг агента.',
    mcpTokenCreated: 'Токен создан. Больше он показан не будет — скопируйте сейчас.',
    mcpTokenShown: 'Я сохранил токен',
    mcpTokenCopyFailed: 'Не удалось скопировать — выделите и скопируйте вручную',
    mcpTokenUnnamed: 'Без названия',
    mcpTokenDelete: 'Отозвать',
    mcpTokenNone: 'Токенов пока нет — создайте первый, чтобы подключить агента.',
    mcpTokenLabel: 'Название (например, «ноутбук»)',
    mcpTokenLabelPlaceholder: 'для чего этот агент',
    mcpTokenCreate: 'Сгенерировать',
    mcpOpen: 'Как подключить',
    // Системные уведомления (ТЗ 3.21)
    pushTitle: 'Уведомления',
    pushHint:
      'Системные уведомления на устройство — они приходят, даже когда приложение закрыто: агент взял задачу, работа ждёт приёмки, подошёл срок или пора по ритму.',
    pushSwitch: 'Присылать уведомления на это устройство',
    pushDevices: 'Подключённых устройств: {n}',
    pushOn: 'Уведомления включены на этом устройстве.',
    pushOff: 'Уведомления выключены на этом устройстве.',
    pushDenied:
      'Браузер запретил уведомления для этого сайта. Разрешение возвращают в настройках браузера, здесь его не спрашивают.',
    pushUnsupported:
      'Этот браузер не умеет системные уведомления или страница открыта без HTTPS. Установленное на телефон приложение подходит: на iPhone — с iOS 16.4.',
    pushUnconfigured:
      'Сервер не настроен для отправки уведомлений — нужны ключи VAPID в его окружении.',
    pushRequestDenied:
      'Браузер не показал запрос. Включите уведомления для сайта в настройках браузера и попробуйте снова.',
    pushFailed: 'Не удалось включить уведомления',
    quietSwitch: 'Не беспокоить с 22:00 до 09:00',
    quietHint:
      'В это окно напоминания молчат и в очередь не встают: как только окно кончится, придёт напоминание по сегодняшнему состоянию дел. О работе агента сообщаем и в тихие часы — она ждёт вашего решения.',
  },
  ext: {
    title: 'Расширение быстрого захвата',
    whatTitle: 'Что это такое',
    whatText:
      'Клик по иконке расширения в трее браузера — и задача в стеке, не открывая сервис. В попапе две вкладки: «Добавить» (первая строка — название, остальное — описание; можно выбрать проект) и «Активные» — только просмотр, клик по задаче открывает её в сервисе.',
    tokenTitle: 'Шаг 1. Токен доступа',
    tokenText:
      'Расширение подключается персональным MCP-токеном (как ИИ-агенты): создайте его в «Настройках → Токены MCP» — значение показывается один раз.',
    tokenButton: 'Открыть Настройки',
    downloadTitle: 'Шаг 2. Скачать и распаковать',
    downloadButton: 'Скачать ZIP',
    downloadHint: 'Распакуйте архив в любую папку.',
    installTitle: 'Шаг 3. Загрузить расширение в браузер',
    chromeText:
      'Chrome/Chromium: откройте chrome://extensions, включите «Developer mode» → «Load unpacked» → выберите распакованную папку.',
    firefoxText:
      'Firefox: откройте about:debugging#/runtime/this-firefox → «Load Temporary Add-on…» → файл manifest.json из архива.',
    connectTitle: 'Шаг 4. Подключить',
    connectText:
      'Кликните по иконке расширения, вставьте токен из шага 1 и нажмите «Подключить». Отзыв токена в «Настройках» отключает расширение.',
    pwaTitle: 'Доступно из веб-версии',
    pwaNote:
      'Страница скрыта в установленном приложении (PWA) — откройте сервис в обычной вкладке браузера.',
  },
  mcp: {
    title: 'MCP для ИИ-агентов',
    whatTitle: 'Что это такое',
    whatText:
      'В приложение встроен MCP-сервер (Model Context Protocol): ИИ-агенты подключаются к нему и работают с вашими задачами от вашего имени — создают, ищут, обновляют и закрывают их. Закрытие задачи агентом даёт те же награды, что и в приложении: XP, монеты, растение в саду; у регулярной задачи следующий экземпляр создаётся автоматически.',
    toolsTitle: 'Инструменты',
    toolsHint:
      'Сервер сам объясняет агенту порядок работы: начинать с проектов, привязывать задачи к проекту, не придумывать идентификаторы и следовать подсказкам в ошибках.',
    toolListProjects: 'список проектов: заметки, статус, число открытых задач',
    toolGetProject: 'контекст проекта: заметка и открытые задачи',
    toolCreateTask: 'создать задачу (достаточно заголовка, желательно с проектом)',
    toolUpdateTask: 'обновить поля задачи; закрытие — status="done"',
    toolCompleteTask: 'завершить задачу (можно указать фактическое время)',
    toolListTasks: 'поиск и фильтры: проект, тег, статус, подстрока',
    toolGetTask: 'полные данные задачи, включая вложения',
    toolListTags: 'справочник тегов',
    connectTitle: 'Как подключить агента',
    connectText:
      'Транспорт — Streamable HTTP. Адрес совпадает с адресом этого приложения. Для подключения понадобится токен доступа.',
    connectUrlLabel: 'Адрес сервера',
    connectTokenLabel: 'Токен доступа',
    connectTokenText:
      'Агент действует от вашего имени. Создайте персональный токен в Настройках — раздел «Токены MCP» — и вставьте его сюда.',

    connectClaudeLabel: 'Claude Code — одна команда',
    connectJsonLabel: 'Универсальный JSON (Claude Desktop и другие клиенты)',
    copy: 'Скопировать',
    copied: 'Адрес скопирован',
    copyFailed: 'Не удалось скопировать',
    projectTitle: 'Контекст проекта',
    projectText:
      'Агент видит ваши проекты с заметками и их открытые задачи. Сервер инструктирует агента начинать работу с проектов (list_projects → get_project), привязывать создаваемые задачи к проекту и перечитывать get_project, возвращаясь к разговору после перерыва, — так задачи не теряются вне контекста своего проекта.',
  },
  md: {
    bold: 'Жирный',
    boldText: 'жирный текст',
    italic: 'Курсив',
    italicText: 'курсивный текст',
    heading: 'Заголовок',
    list: 'Список',
    checklist: 'Чек-лист',
    link: 'Ссылка',
    linkText: 'текст ссылки',
    code: 'Код',
  },
  login: {
    signIn: 'Войти через GNEXUS',
    subtitle: 'Ваши задачи, проекты и сад — в одном месте',
  },
  duration: {
    hours: 'Часы',
    minutes: 'Минуты',
    h: 'ч',
    min: 'мин',
  },
  taskui: {
    // Подсказка бейджа-ссылки проекта в карточке задачи (0.75)
    openProject: 'Открыть проект',
    priority: {
      very_low: 'Очень низкий',
      low: 'Низкий',
      medium: 'Средний',
      high: 'Высокий',
      urgent: 'Срочно',
    },
    status: {
      to_do: 'К выполнению',
      in_progress: 'В работе',
      done: 'Завершено',
      cancelled: 'Отменено',
      deferred: 'Отложено',
    },
    relevance: {
      active: 'Активен',
      paused: 'Приостановлен',
    },
    time: {
      hm: '{h} ч {m} м',
      h: '{h} ч',
      m: '{m} м',
    },
    money: {
      budget: 'бюджет {amount}',
      estimate: 'оценка {amount}',
    },
    currency: {
      UAH: '₴ Гривна (UAH)',
      USD: '$ Доллар (USD)',
      EUR: '€ Евро (EUR)',
      GBP: '£ Фунт (GBP)',
      PLN: 'zł Злотый (PLN)',
    },
    deadline: {
      day: 'в течение дня',
      week: 'в течение недели',
      month: 'в течение месяца',
      year: 'в течение года',
      until: 'до {date}',
    },
    countdown: {
      today: 'Сегодня',
      tomorrow: 'Завтра',
      // формы числа (0.69): «через 3 дня», «просрочено на 5 дней» — было «дн.»
      inDays: 'Через {n} день | Через {n} дня | Через {n} дней',
      overdueDays: 'Просрочено на {n} день | Просрочено на {n} дня | Просрочено на {n} дней',
    },
    // «Сколько назад» (0.69): три формы на локаль — одна, две-четыре, много
    // (ru/uk), у en их две. Выбор формы и подстановку {n} делает tn()
    // (`…One` — единственное число без числа: «месяц назад», а не «1 месяц назад»)
    ago: {
      today: 'Сегодня',
      yesterday: 'Вчера',
      days: '{n} день назад | {n} дня назад | {n} дней назад',
      weeks: '{n} неделю назад | {n} недели назад | {n} недель назад',
      weeksOne: 'неделю назад',
      months: '{n} месяц назад | {n} месяца назад | {n} месяцев назад',
      monthsOne: 'месяц назад',
      years: '{n} год назад | {n} года назад | {n} лет назад',
      yearsOne: 'год назад',
    },
    recur: {
      kind: {
        interval: 'Каждые N дней',
        weekdays: 'Дни недели',
        monthly: 'День месяца',
      },
      daily: 'ежедневно',
      weekly: 'еженедельно',
      everyN: 'каждые {n} дн.',
      byWeekdays: 'по дням недели',
      monthlyDay: 'ежемесячно {day}-го',
      recurring: 'регулярная',
      // Дата регулярной читается не как срок, а как «когда пора» (0.91): «до
      // 11.10» значило бы «успей к», а повторяющаяся задача никуда не опаздывает
      next: 'след. {date}',
      // Подсказка к метке в списке (0.91, ТЗ 3.5): одной иконки мало — владелец
      // спрашивал, как вообще устроена регулярная задача, и ответ живёт здесь
      hintNext: 'Регулярная: {rule}. Следующий экземпляр — {date}',
      hint: 'Регулярная: {rule}. После закрытия появится следующий экземпляр',
    },
  },
}