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) }