admin 8dc496b626
Some checks failed
CI / test (push) Has been cancelled
Release / release (push) Failing after 4m36s
first commit
2026-03-08 15:40:34 +07:00

296 lines
11 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package tui
import (
"os"
"path/filepath"
"strings"
)
// Lang is the UI language code.
type Lang string
const (
LangEn Lang = "en"
LangRu Lang = "ru"
)
// L holds all localizable UI strings.
type L struct {
// General
Help string
Quit string
Cancel string
Send string
New string
Clear string
Complete string
ScrollMore string
ScrollClose string
ScrollPct string
// Placeholder & input
Placeholder string
// Help overlay
KeyboardShortcuts string
InputShortcuts string
SlashCommands string
SendMessage string
NewLineInInput string
CycleMode string
QuickModelSwitch string
CancelStreaming string
QuitKeys string
ClearScreen string
NewConversation string
ToggleHelp string
ExpandTools string
ToggleToolDetails string
CopyLastResponse string
ToggleThinking string
ToggleCompact string
OpenInEditor string
BrowseHistory string
ScrollViewport string
HalfPageScroll string
Autocomplete string
AttachFile string
ActivateSkill string
RunSlashCommand string
Language string
LanguageF2 string
// Side panel
SidePanelAIAgent string
SidePanelTagline string
SidePanelModels string
SidePanelServers string
SidePanelICE string
SidePanelQuickActions string
SidePanelHelp string
SidePanelHelpDesc string
SidePanelServersDesc string
SidePanelModelDesc string
SidePanelLoadDesc string
SidePanelLoad string
ToolsConnected string
NoServersConnected string
ICEConversations string
ICECrossSessionActive string
ICEDisabled string
ICECrossSessionInactive string
// Model picker
SelectModel string
// Modes
ModeAsk string
ModePlan string
ModeBuild string
// Window title
WindowTitle string
WindowTitleThink string
WindowTitleStream string
WindowTitleDone string
// Key hints (short action names)
HintSend string
HintComplete string
HintHelp string
HintCancel string
HintQuit string
HintNew string
HintClear string
HintCommands string
HintFiles string
HintSkills string
// Toasts / messages
NoModelsAvailable string
LanguageSet string
}
var localeEn = L{
Help: "Help", Quit: "quit", Cancel: "cancel", Send: "send", New: "new", Clear: "clear", Complete: "complete",
ScrollMore: "↓ scroll for more", ScrollClose: "Esc or q to close", ScrollPct: "%.0f%% · j/k to scroll",
Placeholder: "Ask anything... (Enter to send, ctrl+b for sidebar)",
KeyboardShortcuts: "Keyboard Shortcuts",
InputShortcuts: "Input Shortcuts",
SlashCommands: "Slash Commands",
SendMessage: "Send message",
NewLineInInput: "New line in input",
CycleMode: "Cycle mode (ASK/PLAN/BUILD)",
QuickModelSwitch: "Quick model switch",
CancelStreaming: "Cancel streaming / close overlay",
QuitKeys: "Quit",
ClearScreen: "Clear screen (keep history)",
NewConversation: "New conversation",
ToggleHelp: "Toggle this help (when input empty)",
ExpandTools: "Expand/collapse all tools",
ToggleToolDetails: "Toggle last tool details",
CopyLastResponse: "Copy last response",
ToggleThinking: "Toggle thinking display",
ToggleCompact: "Toggle compact mode",
OpenInEditor: "Open input in $EDITOR",
BrowseHistory: "Browse input history",
ScrollViewport: "Scroll viewport",
HalfPageScroll: "Half-page scroll",
Autocomplete: "Autocomplete (commands/files/skills)",
AttachFile: "Attach file or agent",
ActivateSkill: "Activate skill",
RunSlashCommand: "Run slash command",
Language: "Language",
LanguageF2: "Switch interface language (F2)",
SidePanelAIAgent: "AI AGENT",
SidePanelTagline: "100% local · Your data never leaves",
SidePanelModels: "Models",
SidePanelServers: "Servers",
SidePanelICE: "ICE",
SidePanelQuickActions: "Quick Actions",
SidePanelHelp: "Help",
SidePanelHelpDesc: "Keyboard shortcuts",
SidePanelServersDesc: "List connected tools",
SidePanelModelDesc: "Switch model",
SidePanelLoad: "Load",
SidePanelLoadDesc: "Add context from file",
ToolsConnected: "%d tools connected",
NoServersConnected: "No servers connected",
ICEConversations: "%d conversations",
ICECrossSessionActive: "Cross-session memory active",
ICEDisabled: "ICE disabled",
ICECrossSessionInactive: "Cross-session memory inactive",
SelectModel: "Select Model",
ModeAsk: "ASK", ModePlan: "PLAN", ModeBuild: "BUILD",
WindowTitle: "AI AGENT", WindowTitleThink: "AI AGENT · thinking...",
WindowTitleStream: "AI AGENT · streaming...", WindowTitleDone: "AI AGENT · done",
HintSend: "send", HintComplete: "complete", HintHelp: "help", HintCancel: "cancel", HintQuit: "quit",
HintNew: "new", HintClear: "clear", HintCommands: "commands", HintFiles: "files", HintSkills: "skills",
NoModelsAvailable: "No models available. Check Ollama connection.",
LanguageSet: "Language: %s",
}
var localeRu = L{
Help: "Справка", Quit: "выход", Cancel: "отмена", Send: "отправить", New: "новый", Clear: "очистить", Complete: "дополнение",
ScrollMore: "↓ листать вниз", ScrollClose: "Esc или q — закрыть", ScrollPct: "%.0f%% · j/k листать",
Placeholder: "Спросите что угодно... (Enter — отправить, ctrl+b — панель)",
KeyboardShortcuts: "Горячие клавиши",
InputShortcuts: "Клавиши ввода",
SlashCommands: "Слэш-команды",
SendMessage: "Отправить сообщение",
NewLineInInput: "Новая строка в поле ввода",
CycleMode: "Режим (ASK/PLAN/BUILD)",
QuickModelSwitch: "Быстрая смена модели",
CancelStreaming: "Отмена / закрыть окно",
QuitKeys: "Выход",
ClearScreen: "Очистить экран (история сохраняется)",
NewConversation: "Новый диалог",
ToggleHelp: "Показать справку (при пустом вводе)",
ExpandTools: "Развернуть/свернуть инструменты",
ToggleToolDetails: "Детали последнего инструмента",
CopyLastResponse: "Копировать последний ответ",
ToggleThinking: "Показать процесс размышления",
ToggleCompact: "Компактный режим",
OpenInEditor: "Открыть в $EDITOR",
BrowseHistory: "История ввода",
ScrollViewport: "Прокрутка",
HalfPageScroll: "На полстраницы",
Autocomplete: "Дополнение (команды/файлы/навыки)",
AttachFile: "Прикрепить файл или агента",
ActivateSkill: "Подключить навык",
RunSlashCommand: "Выполнить слэш-команду",
Language: "Язык",
LanguageF2: "Язык интерфейса (F2)",
SidePanelAIAgent: "AI AGENT",
SidePanelTagline: "100% локально · Ваши данные не покидают устройство",
SidePanelModels: "Модели",
SidePanelServers: "Серверы",
SidePanelICE: "ICE",
SidePanelQuickActions: "Быстрые действия",
SidePanelHelp: "Справка",
SidePanelHelpDesc: "Горячие клавиши",
SidePanelServersDesc: "Подключённые инструменты",
SidePanelModelDesc: "Сменить модель",
SidePanelLoad: "Загрузить",
SidePanelLoadDesc: "Добавить контекст из файла",
ToolsConnected: "Подключено инструментов: %d",
NoServersConnected: "Серверы не подключены",
ICEConversations: "Диалогов: %d",
ICECrossSessionActive: "Память между сессиями активна",
ICEDisabled: "ICE выключен",
ICECrossSessionInactive: "Память между сессиями неактивна",
SelectModel: "Выбор модели",
ModeAsk: "ASK", ModePlan: "PLAN", ModeBuild: "BUILD",
WindowTitle: "AI AGENT", WindowTitleThink: "AI AGENT · думает...",
WindowTitleStream: "AI AGENT · отвечает...", WindowTitleDone: "AI AGENT · готово",
HintSend: "отправить", HintComplete: "дополнение", HintHelp: "справка", HintCancel: "отмена", HintQuit: "выход",
HintNew: "новый", HintClear: "очистить", HintCommands: "команды", HintFiles: "файлы", HintSkills: "навыки",
NoModelsAvailable: "Нет моделей. Проверьте подключение к Ollama.",
LanguageSet: "Язык: %s",
}
// Locale returns the strings for the given language. Unknown lang falls back to English.
func Locale(lang Lang) L {
switch lang {
case LangRu:
return localeRu
default:
return localeEn
}
}
// LangName returns a display name for the language.
func LangName(lang Lang) string {
switch lang {
case LangRu:
return "Русский"
default:
return "English"
}
}
// NextLang cycles to the next language (en -> ru -> en).
func NextLang(lang Lang) Lang {
switch lang {
case LangEn:
return LangRu
case LangRu:
return LangEn
default:
return LangEn
}
}
// DefaultLangPath returns the path for storing UI language preference.
func DefaultLangPath() string {
home, err := os.UserHomeDir()
if err != nil {
return "lang"
}
return filepath.Join(home, ".config", "ai-agent", "lang")
}
// LoadLang reads the saved language from DefaultLangPath(). Returns LangEn if missing or invalid.
func LoadLang() Lang {
data, err := os.ReadFile(DefaultLangPath())
if err != nil {
return LangEn
}
switch strings.TrimSpace(strings.ToLower(string(data))) {
case "ru", "русский":
return LangRu
default:
return LangEn
}
}
// SaveLang writes the language to DefaultLangPath().
func SaveLang(lang Lang) error {
path := DefaultLangPath()
dir := filepath.Dir(path)
if err := os.MkdirAll(dir, 0o755); err != nil {
return err
}
return os.WriteFile(path, []byte(lang), 0o644)
}