const HW_LANG_KEY = "hw_ui_lang_v1";
const HW_I18N = {
  ru: {
    guildWar: "Война гильдий",
    dashboard: "Guild War Dashboard",
    admin: "Админка",
    contentManager: "Контент-менеджер",
    openApp: "Открыть приложение",
    selectGuild: "Выбрать гильдию...",
    backHome: "На начальный экран",
    all: "Все",
    wins: "Победы",
    losses: "Поражения",
    searchOpponent: "Поиск соперника…",
    battlesWithOpponent: "Бои с соперником",
    opponentsCount: "{count} соперников",
    opponent: "Соперник",
    playerAttacks: "Атаки игроков",
    type: "Тип",
    week: "Неделя {week}",
    swipeForPreviousWeek: "Свайпните влево, чтобы увидеть предыдущую неделю",
    more: "Ещё...",
    help: "Помощь",
    heroes: "Герои",
    titans: "Титаны",
    bot: "БОТ",
    botAttacks: "Бот атак",
    attackLog: "Журнал атак",
    selectGuildFirst: "Сначала выберите гильдию",
    botFightCitadel: "Цитадель",
    botFightIceBastion: "Бастион льда",
    botFightNatureGate: "Врата природы",
    botFightFireBastion: "Бастион огня",
    botFightBridge: "Мост",
    botFightElementsSource: "Источник стихий",
    botFightLighthouse: "Маяк",
    botFightFoundry: "Литейная",
    botFightMageAcademy: "Академия магов",
    botFightBarracks: "Казармы",
    botFightOpenSlot: "Открыть позицию {n}",
    botFightPosition: "Позиция {n}",
    botFightAdminHint: "Выберите гильдию и заполните позиции скриншотами. Квадратные позиции — герои, шестиугольные — титаны.",
    saveContent: "Сохранить контент",
    loadContent: "Загрузить контент",
    botFightExported: "Архив сохранён: {count} скриншотов",
    botFightImported: "Загружено: {count} скриншотов",
    botFightArchiveError: "Не удалось обработать архив",
    opponentNicknameOptional: "Ник соперника (необязательно)",
    opponentNicknamePlaceholder: "Введите ник соперника",
    nothingFound: "Ничего не найдено",
    screenshotMissing: "Скриншот не добавлен.\nЗагрузить его можно в админке.",
    screenshotsMissing: "Скриншоты не добавлены.\nЗагрузить их можно в админке.",
    loading: "Загрузка…",
    victory: "Победа",
    defeat: "Поражение",
    battleScreenshot: "Скриншот боя",
    battleCollection: "Подборка боёв",
    previousScreenshot: "Предыдущий скриншот",
    nextScreenshot: "Следующий скриншот",
    opponentNumber: "Соперник #{rank}",
    showPastWeeks: "Показать прошлые недели",
    noPastWeeks: "Прошлых недель нет",
    chooseOpponentGuild: "Выберите гильдию соперника",
    opponentGuilds: "Гильдии соперника",
    opponentGuildList: "Список гильдий соперника",
    total: "{count} всего",
    active: "активных",
    inReserve: "в резерве",
    guild: "Гильдия:",
    activeCards: "Активные карточки",
    reserveHidden: "Резерв (не отображается в приложении)",
    addOpponent: "Соперник",
    addOpponentFull: "Добавить соперника",
    addGuild: "Добавить гильдию",
    noActiveCards: "Нет активных карточек — добавьте соперника",
    addGuildPrompt: "Добавьте гильдию в блоке выше",
    noGuilds: "Гильдий пока нет — добавьте первую",
    edit: "Редактировать",
    editingOpponent: "Редактирование соперника",
    nicknameOpponent: "Ник / название соперника",
    weeks: "Недели",
    addWeek: "Добавить неделю",
    addWeekPruneConfirm: "Лимит — 3 недели. Создание новой удалит самую старую ({weeks}) вместе со скриншотами. Продолжить?",
    continueAction: "Продолжить",
    addMore: "Добавить",
    points: "Очки",
    addScreenshot: "Добавить скриншот",
    screenshotForPopup: "Скриншот для попапа",
    screenshotN: "Скриншот {n}",
    addFirstScreenshot: "Добавьте первый скриншот",
    weeksCount: "{count} недель",
    screenshotsCount: "{count} скриншотов",
    playerNick: "Ник игрока",
    homePlayers: "Игроки своей гильдии",
    homePlayersHint: "Добавьте до {max} ников. Они появятся в выпадающем списке при заполнении недель.",
    players: "игроков",
    addPlayer: "Добавить игрока",
    playerSlot: "Игрок {n}",
    deletePlayer: "Удалить игрока",
    dropBattleScreenshot: "Перетащите скриншот боя",
    dropScreenshot: "Перетащите скриншот",
    done: "Готово",
    save: "Сохранить",
    cancel: "Отмена",
    confirm: "Точно?",
    no: "Нет",
    attacksWins: "{total} атак · {wins} побед",
    hidden: "скрыта",
    activeState: "активна",
    archived: "в архиве",
    logo: "Лого",
    logoFull: "Логотип",
    guildName: "Название гильдии",
    homeGuildLogo: "Логотип своей гильдии",
    homeGuildLogoHint: "Загрузите логотип, и он будет показан в приложении рядом с названием гильдии.",
    guildLogoHint: "Логотип можно заменить при редактировании",
    delete: "Удалить",
    deleteWeek: "Удалить неделю",
    deleteScreenshot: "Удалить скриншот",
    deleteOpponent: "Удалить соперника",
    deleteCard: "Удалить карточку",
    deleteAllCards: "Удалить все карточки",
    deleteAllCardsConfirm: "Удалить все карточки соперников в неделе {week} (гильдия «{guild}»)? Другие недели затронуты не будут. Это действие нельзя отменить.",
    deleteAllCardsNone: "В этой неделе нет карточек",
    deleteGuild: "Удалить гильдию навсегда",
    closeEsc: "Закрыть (Esc)",
    newOpponent: "Новый соперник",
    player: "Игрок",
    hiddenParen: "(скрыта)",
    battleTabHint: "До {activeMax} активных карточек соперников отображаются в приложении, ещё до {reserveMax} можно держать в резерве. Каждая карточка — ник соперника и ряды кнопок «Герои» / «Титаны».",
    guildTabHint: "В выпадающем списке приложения отображается не более {max} гильдий. Лишние можно скрыть — все их бои и настройки сохранятся и восстановятся при повторном включении.",
    activeGuildWarning: "Активно {count} гильдий из {max}. Скройте лишние, чтобы в приложении остались только {max}.",
    automation: "Автоматизация",
    autoTip: "Загрузить f.zip — автосоздание и заполнение карточек соперников",
    autoPhaseRead: "Чтение архива…",
    autoPhaseDetect: "Анализ скринов (Герои/Титаны): {i} / {total}",
    autoPhaseCreate: "Создание карточек…",
    autoPhaseAttach: "Прикрепление скриншотов: {i} / {total}",
    autoDontClose: "Не закрывайте окно до завершения.",
    autoStatOpponents: "Новых соперников",
    autoStatAttacks: "Всего атак",
    autoStatShots: "Скриншотов",
    autoStatBlocks: "Блоков / скринов",
    autoSkipped: "Пропущено (достигнут лимит карточек): {n}",
    autoMissingShots: "Без скриншота: {n} ({list})",
    autoAmbiguousTitle: "Спорное определение Герои/Титаны",
    autoAmbiguousHint: "Эти скрины оказались близко к границе. Проверьте их вручную в карточке и при необходимости перенесите атаку:",
    autoErrNoTxt: "В архиве не найден файл .txt с данными.",
    autoErrEmptyTxt: "Файл .txt пуст или не распознан.",
    autoErrGeneric: "Не удалось обработать архив. Проверьте, что это корректный f.zip.",
    chooseWeek: "Выберите неделю",
    weekWord: "Неделя",
    weeksBack: "Недели",
    noWeeksYet: "Пока нет недель — нажмите «Добавить неделю»",
    deletePlayer: "Удалить игрока",
  },
  pt: {
    guildWar: "Guerra de Guildas",
    dashboard: "Painel de Guerra de Guildas",
    admin: "Admin",
    contentManager: "Gestor de conteúdo",
    openApp: "Abrir aplicação",
    selectGuild: "Selecionar guilda...",
    backHome: "Para a tela inicial",
    all: "Todos",
    wins: "Vitórias",
    losses: "Derrotas",
    searchOpponent: "Buscar adversário…",
    battlesWithOpponent: "Batalhas contra adversário",
    opponentsCount: "{count} adversários",
    opponent: "Adversário",
    playerAttacks: "Ataques dos jogadores",
    type: "Tipo",
    week: "Semana {week}",
    swipeForPreviousWeek: "Deslize para a esquerda para ver a semana anterior",
    more: "Mais...",
    help: "Ajuda",
    heroes: "Heróis",
    titans: "Titãs",
    bot: "BOT",
    botAttacks: "Ataque bot",
    attackLog: "Registro de ataques",
    selectGuildFirst: "Selecione uma guilda primeiro",
    botFightCitadel: "Cidadela",
    botFightIceBastion: "Bastião de gelo",
    botFightNatureGate: "Portão da natureza",
    botFightFireBastion: "Bastião de fogo",
    botFightBridge: "Ponte",
    botFightElementsSource: "Fonte dos elementos",
    botFightLighthouse: "Farol",
    botFightFoundry: "Fundição",
    botFightMageAcademy: "Academia de magos",
    botFightBarracks: "Quartel",
    botFightOpenSlot: "Abrir posição {n}",
    botFightPosition: "Posição {n}",
    botFightAdminHint: "Selecione uma guilda e preencha as posições com screenshots. Posições quadradas são heróis; hexagonais são titãs.",
    saveContent: "Salvar conteúdo",
    loadContent: "Carregar conteúdo",
    botFightExported: "Arquivo salvo: {count} screenshots",
    botFightImported: "Carregado: {count} screenshots",
    botFightArchiveError: "Não foi possível processar o arquivo",
    opponentNicknameOptional: "Nome do adversário (opcional)",
    opponentNicknamePlaceholder: "Digite o nome do adversário",
    nothingFound: "Nada encontrado",
    screenshotMissing: "Screenshot não adicionado.\nEnvie pela área admin.",
    screenshotsMissing: "Screenshots não adicionados.\nEnvie pela área admin.",
    loading: "Carregando…",
    victory: "Vitória",
    defeat: "Derrota",
    battleScreenshot: "Screenshot da batalha",
    battleCollection: "Seleção de batalhas",
    previousScreenshot: "Screenshot anterior",
    nextScreenshot: "Próximo screenshot",
    opponentNumber: "Adversário #{rank}",
    showPastWeeks: "Mostrar semanas anteriores",
    noPastWeeks: "Não há semanas anteriores",
    chooseOpponentGuild: "Selecione uma guilda adversária",
    opponentGuilds: "Guildas adversárias",
    opponentGuildList: "Lista de guildas adversárias",
    total: "{count} no total",
    active: "ativas",
    inReserve: "em reserva",
    guild: "Guilda:",
    activeCards: "Cartões ativos",
    reserveHidden: "Reserva (não aparece na aplicação)",
    addOpponent: "Adversário",
    addOpponentFull: "Adicionar adversário",
    addGuild: "Adicionar guilda",
    noActiveCards: "Sem cartões ativos — adicione um adversário",
    addGuildPrompt: "Adicione uma guilda no bloco acima",
    noGuilds: "Ainda não há guildas — adicione a primeira",
    edit: "Editar",
    editingOpponent: "Edição do adversário",
    nicknameOpponent: "Nick / nome do adversário",
    weeks: "Semanas",
    addWeek: "Adicionar semana",
    addWeekPruneConfirm: "Limite de 3 semanas. Criar uma nova excluirá a mais antiga ({weeks}) com as capturas. Continuar?",
    continueAction: "Continuar",
    addMore: "Adicionar",
    points: "Pontos",
    addScreenshot: "Adicionar screenshot",
    screenshotForPopup: "Screenshot para popup",
    screenshotN: "Screenshot {n}",
    addFirstScreenshot: "Adicione o primeiro screenshot",
    weeksCount: "{count} semanas",
    screenshotsCount: "{count} screenshots",
    playerNick: "Nick do jogador",
    homePlayers: "Jogadores da sua guilda",
    homePlayersHint: "Adicione até {max} nicks. Eles aparecerão na lista suspensa ao preencher as semanas.",
    players: "jogadores",
    addPlayer: "Adicionar jogador",
    playerSlot: "Jogador {n}",
    deletePlayer: "Excluir jogador",
    dropBattleScreenshot: "Arraste o screenshot da batalha",
    dropScreenshot: "Arraste o screenshot",
    done: "Pronto",
    save: "Salvar",
    cancel: "Cancelar",
    confirm: "Confirmar?",
    no: "Não",
    attacksWins: "{total} ataques · {wins} vitórias",
    hidden: "oculta",
    activeState: "ativa",
    archived: "no arquivo",
    logo: "Logo",
    logoFull: "Logotipo",
    guildName: "Nome da guilda",
    homeGuildLogo: "Logo da sua guilda",
    homeGuildLogoHint: "Envie o logo e ele aparecerá na aplicação ao lado do nome da guilda.",
    guildLogoHint: "O logotipo pode ser substituído ao editar",
    delete: "Excluir",
    deleteWeek: "Excluir semana",
    deleteScreenshot: "Excluir screenshot",
    deleteOpponent: "Excluir adversário",
    deleteCard: "Excluir cartão",
    deleteAllCards: "Excluir todos os cartões",
    deleteAllCardsConfirm: "Excluir todos os cartões de adversários na semana {week} (guilda «{guild}»)? As outras semanas não serão afetadas. Esta ação não pode ser desfeita.",
    deleteAllCardsNone: "Esta semana não tem cartões",
    deleteGuild: "Excluir guilda definitivamente",
    closeEsc: "Fechar (Esc)",
    newOpponent: "Novo adversário",
    player: "Jogador",
    hiddenParen: "(oculta)",
    battleTabHint: "Até {activeMax} cartões ativos de adversários aparecem na aplicação; outros {reserveMax} podem ficar na reserva. Cada cartão contém o nick do adversário e linhas de botões «Heróis» / «Titãs».",
    guildTabHint: "A lista suspensa da aplicação mostra no máximo {max} guildas. As excedentes podem ser ocultadas — suas batalhas e configurações serão mantidas e restauradas ao ativar novamente.",
    activeGuildWarning: "{count} guildas ativas de {max}. Oculte as excedentes para manter apenas {max} na aplicação.",
    automation: "Automação",
    autoTip: "Enviar f.zip — criação e preenchimento automático dos cartões de adversários",
    autoPhaseRead: "Lendo o arquivo…",
    autoPhaseDetect: "Analisando screenshots (Heróis/Titãs): {i} / {total}",
    autoPhaseCreate: "Criando cartões…",
    autoPhaseAttach: "Anexando screenshots: {i} / {total}",
    autoDontClose: "Não feche a janela até concluir.",
    autoStatOpponents: "Novos adversários",
    autoStatAttacks: "Total de ataques",
    autoStatShots: "Screenshots",
    autoStatBlocks: "Blocos / screenshots",
    autoSkipped: "Ignorados (limite de cartões atingido): {n}",
    autoMissingShots: "Sem screenshot: {n} ({list})",
    autoAmbiguousTitle: "Detecção incerta Heróis/Titãs",
    autoAmbiguousHint: "Estes screenshots ficaram perto do limite. Verifique-os manualmente no cartão e mova o ataque se necessário:",
    autoErrNoTxt: "Arquivo .txt com dados não encontrado no zip.",
    autoErrEmptyTxt: "O arquivo .txt está vazio ou não foi reconhecido.",
    autoErrGeneric: "Falha ao processar o arquivo. Verifique se é um f.zip válido.",
    chooseWeek: "Escolha a semana",
    weekWord: "Semana",
    weeksBack: "Semanas",
    noWeeksYet: "Ainda não há semanas — clique em «Adicionar semana»",
    deletePlayer: "Excluir jogador",
  },
};

Object.assign(HW_I18N.ru, {
  pasteScreenshotHint: "После добавления нажмите Ctrl+V, чтобы вставить изображение",
  imageBrowsePaste: "или <u>выберите файл</u>, или нажмите Ctrl+V",
  replaceImage: "Заменить",
  deleteImage: "Удалить",
  showGuild: "Показать",
  hideGuild: "Скрыть (настройки сохранятся)",
  maxActiveGuilds: "Максимум {max} активных — сначала скройте другую",
  colors: "Цвета",
  accent: "Акцент",
  winLoss: "Победа / Поражение",
  background: "Фон",
  tableDensity: "Плотность таблицы",
  density: "Плотность",
  fontSize: "Размер шрифта",
  heading: "Заголовок",
  text: "Текст",
  buttonsNicks: "Кнопки/ники",
  pageTitle: "Война гильдий",
  adminPageTitle: "Война гильдий — Админка",
  invalidImage: "Используйте изображение PNG, JPEG, WebP или AVIF",
  imageReadFailed: "Не удалось прочитать изображение",
});

Object.assign(HW_I18N.pt, {
  pasteScreenshotHint: "Após adicionar, pressione Ctrl+V para colar uma imagem",
  imageBrowsePaste: "ou <u>escolha um arquivo</u>, ou pressione Ctrl+V",
  replaceImage: "Substituir",
  deleteImage: "Excluir",
  showGuild: "Mostrar",
  hideGuild: "Ocultar (configurações mantidas)",
  maxActiveGuilds: "Máximo de {max} guildas ativas — oculte outra primeiro",
  colors: "Cores",
  accent: "Destaque",
  winLoss: "Vitória / Derrota",
  background: "Fundo",
  tableDensity: "Densidade da tabela",
  density: "Densidade",
  fontSize: "Tamanho da fonte",
  heading: "Título",
  text: "Texto",
  buttonsNicks: "Botões/nicks",
  pageTitle: "Guerra de Guildas",
  adminPageTitle: "Guerra de Guildas — Admin",
  invalidImage: "Use uma imagem PNG, JPEG, WebP ou AVIF",
  imageReadFailed: "Não foi possível ler a imagem",
});

HW_I18N.en = {
  guildWar: "Guild War",
  dashboard: "Guild War Dashboard",
  admin: "Admin",
  contentManager: "Content manager",
  openApp: "Open dashboard",
  selectGuild: "Select guild...",
  backHome: "Back to home",
  all: "All",
  wins: "Wins",
  losses: "Losses",
  searchOpponent: "Search opponent...",
  battlesWithOpponent: "Battles with opponent",
  opponentsCount: "{count} opponents",
  opponent: "Opponent",
  playerAttacks: "Player attacks",
  type: "Type",
  week: "Week {week}",
  swipeForPreviousWeek: "Swipe left to view the previous week",
  more: "More...",
  help: "Help",
  heroes: "Heroes",
  titans: "Titans",
  bot: "BOT",
  botAttacks: "Bot attack",
  attackLog: "Attack log",
  selectGuildFirst: "Select a guild first",
  botFightCitadel: "Citadel",
  botFightIceBastion: "Ice Bastion",
  botFightNatureGate: "Nature Gate",
  botFightFireBastion: "Fire Bastion",
  botFightBridge: "Bridge",
  botFightElementsSource: "Elements Source",
  botFightLighthouse: "Lighthouse",
  botFightFoundry: "Foundry",
  botFightMageAcademy: "Mage Academy",
  botFightBarracks: "Barracks",
  botFightOpenSlot: "Open position {n}",
  botFightPosition: "Position {n}",
  botFightAdminHint: "Select a guild and fill the positions with screenshots. Square positions are heroes; hexagonal positions are titans.",
  saveContent: "Save content",
  loadContent: "Load content",
  botFightExported: "Archive saved: {count} screenshots",
  botFightImported: "Loaded: {count} screenshots",
  botFightArchiveError: "Could not process the archive",
  opponentNicknameOptional: "Opponent nickname (optional)",
  opponentNicknamePlaceholder: "Enter opponent nickname",
  nothingFound: "Nothing found",
  screenshotMissing: "Screenshot not added.\nUpload it in the admin panel.",
  screenshotsMissing: "Screenshots not added.\nUpload them in the admin panel.",
  loading: "Loading...",
  victory: "Victory",
  defeat: "Defeat",
  battleScreenshot: "Battle screenshot",
  battleCollection: "Battle collection",
  previousScreenshot: "Previous screenshot",
  nextScreenshot: "Next screenshot",
  opponentNumber: "Opponent #{rank}",
  showPastWeeks: "Show past weeks",
  noPastWeeks: "No past weeks",
  chooseOpponentGuild: "Choose an opponent guild",
  opponentGuilds: "Opponent guilds",
  opponentGuildList: "Opponent guild list",
  total: "{count} total",
  active: "active",
  inReserve: "in reserve",
  guild: "Guild:",
  activeCards: "Active cards",
  reserveHidden: "Reserve (not shown in the dashboard)",
  addOpponent: "Opponent",
  addOpponentFull: "Add opponent",
  addGuild: "Add guild",
  noActiveCards: "No active cards — add an opponent",
  addGuildPrompt: "Add a guild in the section above",
  noGuilds: "No guilds yet — add the first one",
  edit: "Edit",
  editingOpponent: "Edit opponent",
  nicknameOpponent: "Opponent nickname / name",
  weeks: "Weeks",
  addWeek: "Add week",
  addWeekPruneConfirm: "The limit is 3 weeks. Creating a new one will delete the oldest ({weeks}) with its screenshots. Continue?",
  continueAction: "Continue",
  addMore: "Add",
  points: "Points",
  addScreenshot: "Add screenshot",
  screenshotForPopup: "Screenshot for popup",
  screenshotN: "Screenshot {n}",
  addFirstScreenshot: "Add the first screenshot",
  weeksCount: "{count} weeks",
  screenshotsCount: "{count} screenshots",
  playerNick: "Player nickname",
  homePlayers: "Your guild players",
  homePlayersHint: "Add up to {max} nicknames. They will appear in the dropdown when filling weeks.",
  players: "players",
  addPlayer: "Add player",
  playerSlot: "Player {n}",
  deletePlayer: "Delete player",
  dropBattleScreenshot: "Drop battle screenshot",
  dropScreenshot: "Drop screenshot",
  done: "Done",
  save: "Save",
  cancel: "Cancel",
  confirm: "Are you sure?",
  no: "No",
  attacksWins: "{total} attacks · {wins} wins",
  hidden: "hidden",
  activeState: "active",
  archived: "archived",
  logo: "Logo",
  logoFull: "Logo",
  guildName: "Guild name",
  homeGuildLogo: "Your guild logo",
  homeGuildLogoHint: "Upload a logo to show it next to your guild name in the dashboard.",
  guildLogoHint: "The logo can be replaced while editing",
  delete: "Delete",
  deleteWeek: "Delete week",
  deleteScreenshot: "Delete screenshot",
  deleteOpponent: "Delete opponent",
  deleteCard: "Delete card",
  deleteAllCards: "Delete all cards",
  deleteAllCardsConfirm: "Delete all opponent cards in week {week} for guild “{guild}”? Other weeks will not be affected. This cannot be undone.",
  deleteAllCardsNone: "There are no cards in this week",
  deleteGuild: "Delete guild permanently",
  closeEsc: "Close (Esc)",
  newOpponent: "New opponent",
  player: "Player",
  hiddenParen: "(hidden)",
  battleTabHint: "Up to {activeMax} active opponent cards are shown in the dashboard, with up to {reserveMax} more kept in reserve. Each card contains an opponent nickname and Heroes / Titans attack rows.",
  guildTabHint: "The dashboard dropdown shows up to {max} guilds. Extra guilds can be hidden; their battles and settings are preserved and restored when enabled again.",
  activeGuildWarning: "{count} of {max} guilds are active. Hide extra guilds to keep only {max} in the dashboard.",
  automation: "Automation",
  autoTip: "Upload f.zip to automatically create and fill opponent cards",
  autoPhaseRead: "Reading archive...",
  autoPhaseDetect: "Analyzing screenshots (Heroes/Titans): {i} / {total}",
  autoPhaseCreate: "Creating cards...",
  autoPhaseAttach: "Attaching screenshots: {i} / {total}",
  autoDontClose: "Do not close this window until complete.",
  autoStatOpponents: "New opponents",
  autoStatAttacks: "Total attacks",
  autoStatShots: "Screenshots",
  autoStatBlocks: "Blocks / screenshots",
  autoSkipped: "Skipped (card limit reached): {n}",
  autoMissingShots: "Missing screenshot: {n} ({list})",
  autoAmbiguousTitle: "Uncertain Heroes/Titans detection",
  autoAmbiguousHint: "These screenshots were close to the detection threshold. Check them manually and move the attack if needed:",
  autoErrNoTxt: "No .txt data file was found in the archive.",
  autoErrEmptyTxt: "The .txt file is empty or could not be recognized.",
  autoErrGeneric: "Could not process the archive. Check that it is a valid f.zip.",
  chooseWeek: "Choose a week",
  weekWord: "Week",
  weeksBack: "Weeks",
  noWeeksYet: "No weeks yet — click “Add week”",
  pasteScreenshotHint: "After adding, press Ctrl+V to paste an image",
  imageBrowsePaste: "or <u>browse files</u>, or press Ctrl+V",
  replaceImage: "Replace",
  deleteImage: "Delete",
  showGuild: "Show",
  hideGuild: "Hide (settings are preserved)",
  maxActiveGuilds: "Maximum {max} active guilds — hide another one first",
  colors: "Colors",
  accent: "Accent",
  winLoss: "Victory / Defeat",
  background: "Background",
  tableDensity: "Table density",
  density: "Density",
  fontSize: "Font size",
  heading: "Heading",
  text: "Text",
  buttonsNicks: "Buttons/nicknames",
  pageTitle: "Guild War",
  adminPageTitle: "Guild War — Admin",
  invalidImage: "Use a PNG, JPEG, WebP, or AVIF image",
  imageReadFailed: "Could not read the image",
};

function getHwLang() {
  try {
    const v = localStorage.getItem(HW_LANG_KEY);
    return v === "pt" || v === "en" ? v : "ru";
  } catch (e) {
    return "ru";
  }
}

function hwT(key, vars = {}) {
  const lang = window.HW_LANG || getHwLang();
  const dict = HW_I18N[lang] || HW_I18N.ru;
  let s = dict[key] || HW_I18N.ru[key] || key;
  Object.keys(vars).forEach((k) => {
    s = s.replaceAll("{" + k + "}", String(vars[k]));
  });
  return s;
}

function useHwLanguage() {
  const [lang, setLangState] = React.useState(getHwLang);
  React.useEffect(() => {
    window.HW_LANG = lang;
    document.documentElement.lang = lang;
    document.title = hwT(window.HW_ADMIN_PAGE ? "adminPageTitle" : "pageTitle");
    document.querySelectorAll("image-slot").forEach((slot) => slot.setAttribute("data-lang", lang));
  }, [lang]);
  const setLang = (next) => {
    const v = next === "pt" || next === "en" ? next : "ru";
    try { localStorage.setItem(HW_LANG_KEY, v); } catch (e) { /* ignore */ }
    window.HW_LANG = v;
    setLangState(v);
  };
  return [lang, setLang];
}

function LanguageToggle({ lang, setLang }) {
  const languages = [
    { id: "ru", label: "RU", title: "Русский" },
    { id: "pt", label: "PT", title: "Português" },
    { id: "en", label: "EN", title: "English" },
  ];
  return (
    <div role="group" aria-label="Language" style={{
      display: "inline-flex", alignItems: "center", gap: 3, padding: 3,
      borderRadius: 999, border: "1px solid var(--card-border)", background: "var(--surface-2)",
      flexShrink: 0,
    }}>
      {languages.map((item) => {
        const active = item.id === lang;
        return (
          <button key={item.id} onClick={() => setLang(item.id)} title={item.title} aria-pressed={active} style={{
            padding: "6px 9px", borderRadius: 999, border: "none", cursor: "pointer",
            background: active ? "var(--accent)" : "transparent",
            color: active ? "#06101f" : "var(--text-faint)",
            fontFamily: "var(--font-mono)", fontSize: 11, fontWeight: 800, letterSpacing: ".04em",
          }}>{item.label}</button>
        );
      })}
    </div>
  );
}

window.HW_LANG = getHwLang();
Object.assign(window, { HW_I18N, hwT, useHwLanguage, LanguageToggle });
