MioIsland/ClaudeIsland/Core/Localization.swift
xmqywx 5deeaffc8a refactor(plugins): remove JSON-based plugin system
Replace with native .bundle plugin architecture in next commits.
Old declarative system (themes/buddy/sound JSON) removed entirely.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 21:21:18 +08:00

330 lines
17 KiB
Swift
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.

//
// Localization.swift
// ClaudeIsland
//
// Simple i18n helper: auto-detects system locale and provides
// English/Chinese translations for all user-visible strings.
//
import Foundation
enum L10n {
/// Language options: "auto" (system), "en", "zh"
static var appLanguage: String {
get { UserDefaults.standard.string(forKey: "appLanguage") ?? "auto" }
set { UserDefaults.standard.set(newValue, forKey: "appLanguage") }
}
static var isChinese: Bool {
switch appLanguage {
case "zh": return true
case "en": return false
default: // "auto"
let lang = Locale.current.language.languageCode?.identifier ?? "en"
return lang == "zh"
}
}
static var currentLanguageLabel: String {
switch appLanguage {
case "zh": return "中文"
case "en": return "English"
default: return isChinese ? "自动" : "Auto"
}
}
static func tr(_ en: String, _ zh: String) -> String {
isChinese ? zh : en
}
// Settings
static var language: String { tr("Language", "语言") }
// MARK: - Session list
static var sessions: String { tr("sessions", "个会话") }
static var noSessions: String { tr("No sessions", "暂无会话") }
static var runClaude: String { tr("Run claude in terminal", "在终端中运行 claude") }
static var needsInput: String { tr("Needs your input", "需要你的输入") }
static var you: String { tr("You:", "你:") }
static var working: String { tr("Working...", "工作中...") }
static var needsApproval: String { tr("Needs approval", "需要审批") }
static var doneJump: String { tr("Done \u{2014} click to jump", "完成 \u{2014} 点击跳转") }
static var compacting: String { tr("Compacting...", "压缩中...") }
static var idle: String { tr("Idle", "空闲") }
static var archived: String { tr("archived", "已归档") }
static var active: String { tr("active", "活跃") }
static func showAllSessions(_ count: Int) -> String { tr("Show all \(count) sessions", "显示全部 \(count) 个会话") }
// MARK: - Menu
static var back: String { tr("Back", "返回") }
static var groupByProject: String { tr("Group by Project", "按项目分组") }
static var pixelCatMode: String { tr("Pixel Cat Mode", "像素猫模式") }
static var launchAtLogin: String { tr("Launch at Login", "开机启动") }
static var hooks: String { tr("Hooks", "钩子") }
static var accessibility: String { tr("Accessibility", "辅助功能") }
static var version: String { tr("Version", "版本") }
static var quit: String { tr("Quit", "退出") }
static var on: String { tr("On", "") }
static var off: String { tr("Off", "") }
static var enable: String { tr("Enable", "启用") }
static var enabled: String { tr("On", "已开启") }
// MARK: - Settings window
static var systemSettings: String { tr("System Settings", "系统设置") }
static var openSettings: String { tr("Settings", "设置") }
static var tabGeneral: String { tr("General", "通用") }
static var tabAppearance: String { tr("Appearance", "外观") }
static var tabNotifications: String { tr("Notifications", "通知") }
static var tabBehavior: String { tr("Behavior", "行为") }
static var tabAdvanced: String { tr("Advanced", "高级") }
static var tabAbout: String { tr("About", "关于") }
static var tabPresets: String { tr("Launch Presets", "启动预设") }
static var tabCodeLight: String { tr("CodeLight", "CodeLight") }
static var pairedIPhones: String { tr("Paired iPhones", "已配对 iPhone") }
static var pairNewPhone: String { tr("Pair New iPhone", "配对新 iPhone") }
static var launchPresetsSection: String { tr("Launch Presets", "启动预设") }
static var addPreset: String { tr("New Preset", "新建预设") }
static var noPresets: String { tr("No presets yet — tap + to add one", "还没有预设,点击 + 添加") }
static var presetsHint: String { tr("Paired iPhones can launch these as new cmux sessions", "配对的 iPhone 可以用这些预设启动新的 cmux 会话") }
static var behavior: String { tr("Behavior", "行为") }
static var system: String { tr("System", "系统") }
static var appearanceSection: String { tr("Appearance", "外观") }
static var usageWarningThreshold: String { tr("Usage Warning", "用量警告") }
static var clearEndedSessions: String { tr("Clear Ended Sessions", "清除已结束会话") }
static var feedback: String { tr("Feedback", "反馈") }
static var starOnGitHub: String { tr("Star on GitHub", "GitHub 点星") }
static var wechatLabel: String { tr("WeChat", "微信") }
static var maintainedTagline: String { tr("Actively maintained · Your star keeps us going!", "持续更新中 · Star 是我们最大的动力!") }
// MARK: - Daily report
static var yesterdayLabel: String { tr("Yesterday", "昨天") }
static var turnsLabel: String { tr("Turns", "轮次") }
static var focusLabel: String { tr("Focus", "专注时长") }
static var linesLabel: String { tr("Lines", "代码行") }
static var sessionsLabel: String { tr("Sessions", "会话") }
static var projectsLabel: String { tr("Projects", "项目") }
static var peakBurstLabel: String { tr("Peak", "最长专注") }
static var filesLabel: String { tr("Files", "文件") }
static var peakHourLabel: String { tr("Peak hour", "活跃时段") }
static var topToolsHeader: String { tr("Top tools", "常用工具") }
static var topSkillsHeader: String { tr("Top skills", "常用 Skills") }
static var topMCPHeader: String { tr("MCP plugins", "MCP 调用") }
static var primaryProjectHeader: String { tr("Primary project", "主要项目") }
// Day / Week view switcher
static var dayViewTab: String { tr("Day", "") }
static var weekViewTab: String { tr("Week", "") }
// Week view extras
static var weekHighlightsHeader: String { tr("Week highlights", "本周高光") }
static var streakLabel: String { tr("Streak", "连续天数") }
static func streakDays(_ days: Int) -> String {
tr(days == 1 ? "\(days) day" : "\(days) days", "\(days)")
}
static var vsLastWeekHeader: String { tr("vs. last week", "对比上周") }
static func peakDayHighlight(_ weekdayName: String, turns: Int) -> String {
tr("Peak day: \(weekdayName) · \(turns) turns",
"峰值日: \(weekdayName) · \(turns)")
}
static func peakBurstHighlight(_ weekdayName: String, minutes: String) -> String {
tr("Longest focus: \(minutes) on \(weekdayName)",
"最长专注: \(minutes)\(weekdayName)")
}
static func primaryProjectHighlight(_ project: String) -> String {
tr("Main project: \(project)", "主要项目: \(project)")
}
static var noActivityThisWeek: String { tr("No activity this week yet.", "本周还没有活动") }
static var sparklineLabel: String { tr("Daily focus", "每日专注") }
/// Prefix for the sparkline normalization ceiling, e.g. "max 4h13m".
static var sparklineMaxPrefix: String { tr("max", "最高") }
// Hero card expand / collapse
static var expandLabel: String { tr("Show more", "查看更多") }
static var collapseLabel: String { tr("Show less", "收起") }
// First-launch loading state
static var analyzingTitle: String { tr("Crunching your numbers…", "正在统计你的数据…") }
static var analyzingSubtitle: String {
tr("Scanning the last 14 days of Claude activity. First launch takes a moment.",
"扫描过去 14 天的 Claude 活动,首次启动稍等一下。")
}
static func dailyTaglineWeek(_ focus: String) -> String {
tr("You worked with Claude for \(focus) this week — here's the recap.",
"本周你和 Claude 协作了 \(focus) — 一周回顾")
}
/// Tagline under the header, filled with the focus duration.
static func dailyTagline(_ focus: String) -> String {
tr("You worked with Claude for \(focus) — here's the recap.",
"你和 Claude 协作了 \(focus) — 昨日回顾")
}
static func focusHelperDesc(_ sessions: Int) -> String {
tr("Active time across \(sessions) sessions (idle gaps excluded)",
"\(sessions) 个会话的活跃时长(不含空闲)")
}
// MARK: - Notch collapsed status
static var approve: String { tr("approve", "审批") }
static var done: String { tr("done", "完成") }
// MARK: - Approval
static var allow: String { tr("Allow", "允许") }
static var deny: String { tr("Deny", "拒绝") }
static var permissionRequest: String { tr("Permission Request", "权限请求") }
static var goToTerminal: String { tr("Go to Terminal", "前往终端") }
static var terminal: String { tr("Terminal", "终端") }
// MARK: - Session state
static var ended: String { tr("Ended", "已结束") }
static var clearEnded: String { tr("Clear Ended", "清除已结束") }
// MARK: - Sound settings
static var soundSettings: String { tr("Sound Settings", "声音设置") }
static var globalMute: String { tr("Global Mute", "全部静音") }
static var eventSounds: String { tr("Event Sounds", "事件声音") }
static var notificationSound: String { tr("Notification Sound", "通知声音") }
static var screen: String { tr("Screen", "屏幕") }
static var automatic: String { tr("Automatic", "自动") }
static var auto_: String { tr("Auto", "自动") }
static var builtIn: String { tr("Built-in", "内置") }
static var main_: String { tr("Main", "主屏幕") }
static var builtInOrMain: String { tr("Built-in or Main", "内置或主屏幕") }
// MARK: - Sound events
static var sessionStart: String { tr("Session Start", "会话开始") }
static var processingBegins: String { tr("Processing Begins", "开始处理") }
static var approvalGranted: String { tr("Approval Granted", "已批准") }
static var approvalDenied: String { tr("Approval Denied", "已拒绝") }
static var sessionComplete: String { tr("Session Complete", "会话完成") }
static var error: String { tr("Error", "错误") }
static var contextCompacting: String { tr("Context Compacting", "上下文压缩") }
static var rateLimitWarning: String { tr("Usage Warning (90%)", "用量警告 (90%)") }
// MARK: - Chat view
static var loadingMessages: String { tr("Loading messages...", "加载消息中...") }
static var noMessages: String { tr("No messages", "暂无消息") }
static var processing: String { tr("Processing", "处理中") }
static var claudeNeedsInput: String { tr("Claude Code needs your input", "Claude Code 需要你的输入") }
static var interrupted: String { tr("Interrupted", "已中断") }
static func newMessages(_ count: Int) -> String { tr("\(count) new messages", "\(count) 条新消息") }
static func runningAgent(_ desc: String?) -> String {
let d = desc ?? tr("Running agent...", "运行代理中...")
return d
}
static var runningAgentDefault: String { tr("Running agent...", "运行代理中...") }
static func waiting(_ desc: String) -> String { tr("Waiting: \(desc)", "等待中: \(desc)") }
static func hiddenToolCalls(_ count: Int) -> String { tr("\(count) more tool calls", "还有 \(count) 个工具调用") }
static func subagentTools(_ count: Int) -> String { tr("Subagent used \(count) tools:", "子代理使用了 \(count) 个工具:") }
// MARK: - Tool result views
static var userModified: String { tr("(user modified)", "(用户已修改)") }
static var created: String { tr("Created", "已创建") }
static var written: String { tr("Written", "已写入") }
static func backgroundTask(_ id: String) -> String { tr("Background task: \(id)", "后台任务: \(id)") }
static var stderrLabel: String { tr("Stderr:", "错误输出:") }
static var noContent: String { tr("(no content)", "(无内容)") }
static var noMatches: String { tr("No matches", "未找到匹配") }
static func filesMatched(_ count: Int) -> String { tr("\(count) files matched", "\(count) 个文件有匹配") }
static var noFiles: String { tr("No files found", "未找到文件") }
static var moreTruncated: String { tr("... more (truncated)", "... 更多(已截断)") }
static func tools(_ count: Int) -> String { tr("\(count) tools", "\(count) 个工具") }
static var noResults: String { tr("No results found", "未找到结果") }
static func moreResults(_ count: Int) -> String { tr("... \(count) more results", "... 还有 \(count) 个结果") }
static func status(_ s: String) -> String { tr("Status: \(s)", "状态: \(s)") }
static func exitCode(_ code: Int) -> String { tr("Exit code: \(code)", "退出码: \(code)") }
static func shellKilled(_ id: String) -> String { tr("Shell \(id) killed", "Shell \(id) 已终止") }
static var completed: String { tr("Completed", "已完成") }
static func moreLines(_ count: Int) -> String { tr("... (\(count) more lines)", "... (\(count) 更多行)") }
static func moreFiles(_ count: Int) -> String { tr("... \(count) more files", "... 还有 \(count) 个文件") }
static func moreHunks(_ count: Int) -> String { tr("... \(count) more hunks", "... 还有 \(count) 个代码块") }
// MARK: - Sound event display names (for SoundManager)
static func soundEventName(_ event: String) -> String {
switch event {
case "session_start": return sessionStart
case "processing_begins": return processingBegins
case "needs_approval": return needsApproval
case "approval_granted": return approvalGranted
case "approval_denied": return approvalDenied
case "session_complete": return sessionComplete
case "error": return error
case "compacting": return contextCompacting
case "rate_limit_warning": return rateLimitWarning
default: return event
}
}
// MARK: - Sound settings preview tooltip
static func previewSound(_ name: String) -> String { tr("Preview \(name) sound", "预览 \(name) 声音") }
// MARK: - Notch view status text
static func approveWhat(_ tool: String) -> String { tr("\(L10n.approve) \(tool)?", "\(L10n.approve) \(tool)?") }
// MARK: - Smart interactions
static var smartSuppression: String { tr("Smart Suppression", "智能抑制") }
static var autoCollapseOnMouseLeave: String { tr("Auto-Collapse on Leave", "离开时自动收起") }
static var compactCollapsed: String { tr("Compact Notch", "紧凑刘海") }
// MARK: - Notch customization
//
// Deviation from spec: the spec (Section 4.5) lists these keys
// for `Localizable.xcstrings`, but this project currently uses
// the hand-rolled `L10n` helper (en + zh-Hans as Swift string
// pairs). Strings added here follow the established pattern
// and match the voice of surrounding entries. A future migration
// to `.xcstrings` can pick them up mechanically from this file.
static var notchSectionHeader: String { tr("Notch", "灵动岛") }
static var notchTheme: String { tr("Theme", "主题") }
static var notchThemeClassic: String { tr("Classic", "经典") }
static var notchThemePaper: String { tr("Paper", "纸张") }
static var notchThemeNeonLime: String { tr("Neon Lime", "霓虹青柠") }
static var notchThemeCyber: String { tr("Cyber", "赛博") }
static var notchThemeMint: String { tr("Mint", "薄荷") }
static var notchThemeSunset: String { tr("Sunset", "日落") }
static var notchFontSize: String { tr("Font Size", "字号") }
static var notchFontSmall: String { tr("S", "") }
static var notchFontDefault: String { tr("M", "") }
static var notchFontLarge: String { tr("L", "") }
static var notchFontXLarge: String { tr("XL", "特大") }
static var notchFontSmallFull: String { tr("Small", "") }
static var notchFontDefaultFull: String { tr("Default", "默认") }
static var notchFontLargeFull: String { tr("Large", "") }
static var notchFontXLargeFull: String { tr("Extra Large", "特大") }
static var notchShowBuddy: String { tr("Show Buddy", "显示宠物") }
static var notchShowUsageBar: String { tr("Show Usage Bar", "显示用量条") }
static var notchHardwareMode: String { tr("Hardware Notch", "硬件刘海") }
static var notchHardwareAuto: String { tr("Auto", "自动") }
static var notchHardwareForceVirtual: String { tr("Force Virtual", "强制虚拟") }
static var notchCustomizeButton: String { tr("Customize Size & Position…", "自定义尺寸与位置…") }
static var notchEditSave: String { tr("Save", "保存") }
static var notchEditCancel: String { tr("Cancel", "取消") }
static var notchEditNotchPreset: String { tr("Notch Preset", "贴合刘海") }
static var notchEditDragMode: String { tr("Drag Mode", "拖动模式") }
static var notchEditReset: String { tr("Reset", "复位") }
static var notchEditPresetDisabledTooltip: String { tr("Your device doesn't have a hardware notch", "你的设备没有硬件刘海") }
static func notchThemeName(_ id: NotchThemeID) -> String {
switch id {
case .classic: return notchThemeClassic
case .paper: return notchThemePaper
case .neonLime: return notchThemeNeonLime
case .cyber: return notchThemeCyber
case .mint: return notchThemeMint
case .sunset: return notchThemeSunset
}
}
}