Files
tslink/gui/i18n.go
T
2026-07-26 20:44:49 +08:00

605 lines
16 KiB
Go

package gui
// Lang selects the UI label set. Chinese is the project's primary audience;
// English exists because a machine without a CJK font cannot draw Chinese, and
// silently rendering tofu boxes would be worse than translating.
type Lang int
const (
LangZH Lang = iota
LangEN
)
// Name is the language's own name, for the settings toggle.
func (l Lang) Name() string {
if l == LangEN {
return "English"
}
return "中文"
}
// Key identifies a translatable string.
type Key int
const (
KAppTitle Key = iota
KAppSubtitle
// Navigation.
KNavOverview
KNavPeers
KNavDiag
KNavLogs
KNavSettings
// Service lifecycle.
KStateStarting
KStateConnecting
KStateRunning
KStateDegraded
KStateStopped
KStateError
KStateRetrying
// Splash steps.
KStepConfig
KStepFonts
KStepTsnet
KStepRules
KStepDiscovery
KStepMonitors
KStepReady
KSplashHint
KSplashStuckHint
KSplashExportLog
KSplashRetry
// Shared vocabulary.
KYes
KNo
KUnknown
KSupported
KUnsupported
KEnabled
KDisabled
KNone
KRefresh
KRetry
KClose
KCopy
KCopied
KDetails
KLoading
KError
KNever
KJustNow
KSecondsAgo
KMinutesAgo
KHoursAgo
KTotal
KOnline
KOffline
// Overview.
KOvTailnet
KOvSelf
KOvPeersOnline
KOvForwardRules
KOvConnectRules
KOvUptime
KOvHealth
KOvQuickDiag
KOvNoIssues
// Peers page.
KPeersTitle
KPeersLinked
KPeersEmpty
KPeersResolving
KPeerLatency
KPeerRoute
KPeerRouteDirect
KPeerRouteDERP
KPeerRoutePeerRelay
KPeerRouteOffline
KPeerRouteUnknown
KPeerAvg
KPeerMin
KPeerMax
KPeerJitter
KPeerLoss
KPeerRx
KPeerTx
KPeerLastSeen
KPeerLastHandshake
KPeerAddresses
KPeerEndpoint
KPeerOS
KPeerExitNode
KPeerTags
KGraphTitle
KGraphEmpty
KGraphWindow
KGraphLegendHint
// Local services (overview).
KSvcTitle
KSvcSubtitle
KSvcEmpty
KSvcBroadcast
// Diagnostics page.
KDiagTitle
KDiagRun
KDiagRunning
KDiagRerun
KDiagNever
KDiagLastRun
KDiagCopyReport
KDiagSecIface
KDiagSecUDP
KDiagSecNAT
KDiagSecPortMap
KDiagSecOverseas
KDiagSecEgress
KDiagSecTailscale
KDiagNatType
KDiagNatMapping
KDiagNatFiltering
KDiagNatHairpin
KDiagNatPortPreserve
KDiagUdpV4
KDiagUdpV6
KDiagUdpPortsOK
KDiagUdpPortsBlocked
KDiagIfaceDefaultV4
KDiagIfaceDefaultV6
KDiagUPnP
KDiagNATPMP
KDiagPCP
KDiagGateway
KDiagExternalIP
KDiagOverseasTarget
KDiagEgressMethod
KDiagEgressIP
KDiagEgressGeo
KDiagEgressDivergent
KDiagEgressDivergentHint
KDiagEgressDivergentHTTP
KDiagGeoSkipped
KDiagPreferredDERP
KDiagDerpLatency
KDiagCaptivePortal
KDiagMappingVaries
KDiagSkipGeo
KDiagSkipGeoHint
// NAT names.
KNatOpen
KNatFullCone
KNatRestricted
KNatPortRestricted
KNatSymmetric
KNatUDPBlocked
KNatSymmetricFW
KNatUnknown
// Logs page.
KLogsTitle
KLogsSearch
KLogsLevel
KLogsSource
KLogsFollow
KLogsAll
KLogsEmpty
KLogsCopyAll
KLogsSaveFile
KLogsUpload
KLogsUploading
KLogsUploaded
KLogsUploadFail
KLogsRedact
KLogsRedactHint
KLogsShown
KLogsDropped
KLogsIncludeDiag
// Settings.
KSetTheme
KSetThemeDark
KSetThemeLight
KSetLanguage
KSetAbout
KSetConfigPath
KSetVersion
KSetFont
KSetFontMissing
kCount
)
var zhStrings = [kCount]string{
KAppTitle: "tslink",
KAppSubtitle: "Tailscale 内网穿透",
KNavOverview: "概览",
KNavPeers: "节点",
KNavDiag: "网络诊断",
KNavLogs: "日志",
KNavSettings: "设置",
KStateStarting: "正在启动",
KStateConnecting: "正在连接",
KStateRunning: "运行中",
KStateDegraded: "降级运行",
KStateStopped: "已停止",
KStateError: "出错",
KStateRetrying: "正在重试",
KStepConfig: "读取配置",
KStepFonts: "加载字体",
KStepTsnet: "接入 Tailscale 网络",
KStepRules: "解析转发规则",
KStepDiscovery: "启动局域网发现",
KStepMonitors: "启动状态监控",
KStepReady: "准备就绪",
KSplashHint: "首次接入 Tailscale 可能需要十几秒",
KSplashStuckHint: "当前步骤耗时异常,可导出日志以便排查",
KSplashExportLog: "导出日志",
KSplashRetry: "启动失败,正在重试",
KYes: "是",
KNo: "否",
KUnknown: "未知",
KSupported: "支持",
KUnsupported: "不支持",
KEnabled: "已启用",
KDisabled: "已禁用",
KNone: "无",
KRefresh: "刷新",
KRetry: "重试",
KClose: "关闭",
KCopy: "复制",
KCopied: "已复制",
KDetails: "详情",
KLoading: "加载中",
KError: "错误",
KNever: "从未",
KJustNow: "刚刚",
KSecondsAgo: "秒前",
KMinutesAgo: "分钟前",
KHoursAgo: "小时前",
KTotal: "共",
KOnline: "在线",
KOffline: "离线",
KOvTailnet: "Tailnet",
KOvSelf: "本机",
KOvPeersOnline: "在线节点",
KOvForwardRules: "转发规则",
KOvConnectRules: "连接规则",
KOvUptime: "运行时长",
KOvHealth: "健康状况",
KOvQuickDiag: "运行网络诊断",
KOvNoIssues: "未发现问题",
KPeersTitle: "Tailscale 节点",
KPeersLinked: "已关联",
KPeersEmpty: "暂无节点",
KPeersResolving: "正在解析配置中的节点",
KPeerLatency: "延迟",
KPeerRoute: "链路",
KPeerRouteDirect: "直连",
KPeerRouteDERP: "DERP 中继",
KPeerRoutePeerRelay: "对等中继",
KPeerRouteOffline: "离线",
KPeerRouteUnknown: "未知",
KPeerAvg: "平均",
KPeerMin: "最低",
KPeerMax: "最高",
KPeerJitter: "抖动",
KPeerLoss: "丢包",
KPeerRx: "接收",
KPeerTx: "发送",
KPeerLastSeen: "最后在线",
KPeerLastHandshake: "最后握手",
KPeerAddresses: "地址",
KPeerEndpoint: "端点",
KPeerOS: "系统",
KPeerExitNode: "出口节点",
KPeerTags: "标签",
KGraphTitle: "延迟图谱",
KGraphEmpty: "正在采集延迟数据",
KGraphWindow: "最近",
KGraphLegendHint: "点击图例可隐藏对应节点",
KSvcTitle: "本机服务",
KSvcSubtitle: "tslink 在本机监听并转发到对应服务器",
KSvcEmpty: "配置中没有连接规则",
KSvcBroadcast: "已广播",
KDiagTitle: "网络诊断",
KDiagRun: "开始诊断",
KDiagRunning: "诊断中",
KDiagRerun: "重新诊断",
KDiagNever: "尚未运行诊断",
KDiagLastRun: "上次运行",
KDiagCopyReport: "复制诊断报告",
KDiagSecIface: "本机出口地址",
KDiagSecUDP: "UDP 连通性",
KDiagSecNAT: "NAT 类型",
KDiagSecPortMap: "端口映射",
KDiagSecOverseas: "境外连通性",
KDiagSecEgress: "出口 IP 与归属地",
KDiagSecTailscale: "Tailscale 内部状态",
KDiagNatType: "NAT 类型",
KDiagNatMapping: "映射行为",
KDiagNatFiltering: "过滤行为",
KDiagNatHairpin: "发夹回环",
KDiagNatPortPreserve: "端口保持",
KDiagUdpV4: "IPv4 UDP",
KDiagUdpV6: "IPv6 UDP",
KDiagUdpPortsOK: "可用端口",
KDiagUdpPortsBlocked: "被封端口",
KDiagIfaceDefaultV4: "默认 IPv4 源地址",
KDiagIfaceDefaultV6: "默认 IPv6 源地址",
KDiagUPnP: "UPnP IGD",
KDiagNATPMP: "NAT-PMP",
KDiagPCP: "PCP",
KDiagGateway: "网关",
KDiagExternalIP: "外部地址",
KDiagOverseasTarget: "测试目标",
KDiagEgressMethod: "探测方式",
KDiagEgressIP: "出口 IP",
KDiagEgressGeo: "归属地",
KDiagEgressDivergent: "出口不一致",
KDiagEgressDivergentHint: "STUN(UDP)本身就看到多个公网 IP,直连打洞会受影响",
KDiagEgressDivergentHTTP: "仅 HTTP 探测看到不同的公网 IP,STUN(UDP)出口一致,通常不影响打洞",
KDiagGeoSkipped: "已跳过归属地查询",
KDiagPreferredDERP: "首选 DERP",
KDiagDerpLatency: "DERP 延迟",
KDiagCaptivePortal: "门户劫持",
KDiagMappingVaries: "映射随目标变化",
KDiagSkipGeo: "不查询归属地",
KDiagSkipGeoHint: "归属地查询会把你的公网 IP 发送给第三方服务",
KNatOpen: "开放网络",
KNatFullCone: "完全锥形",
KNatRestricted: "地址限制锥形",
KNatPortRestricted: "端口限制锥形",
KNatSymmetric: "对称型",
KNatUDPBlocked: "UDP 被阻断",
KNatSymmetricFW: "对称型防火墙",
KNatUnknown: "无法判定",
KLogsTitle: "日志",
KLogsSearch: "搜索日志…",
KLogsLevel: "级别",
KLogsSource: "来源",
KLogsFollow: "自动跟随",
KLogsAll: "全部",
KLogsEmpty: "没有匹配的日志",
KLogsCopyAll: "复制到剪贴板",
KLogsSaveFile: "保存到文件",
KLogsUpload: "上传并分享",
KLogsUploading: "正在上传",
KLogsUploaded: "上传成功,链接已复制",
KLogsUploadFail: "上传失败",
KLogsRedact: "隐去密钥",
KLogsRedactHint: "上传前会自动隐去 authkey 等凭据",
KLogsShown: "已显示",
KLogsDropped: "条早期日志已被丢弃",
KLogsIncludeDiag: "附带诊断报告",
KSetTheme: "主题",
KSetThemeDark: "深色",
KSetThemeLight: "浅色",
KSetLanguage: "语言",
KSetAbout: "关于",
KSetConfigPath: "配置文件",
KSetVersion: "版本",
KSetFont: "中文字体",
KSetFontMissing: "未找到中文字体,界面已切换为英文",
}
var enStrings = [kCount]string{
KAppTitle: "tslink",
KAppSubtitle: "Tailscale link layer",
KNavOverview: "Overview",
KNavPeers: "Peers",
KNavDiag: "Diagnostics",
KNavLogs: "Logs",
KNavSettings: "Settings",
KStateStarting: "Starting",
KStateConnecting: "Connecting",
KStateRunning: "Running",
KStateDegraded: "Degraded",
KStateStopped: "Stopped",
KStateError: "Error",
KStateRetrying: "Retrying",
KStepConfig: "Loading configuration",
KStepFonts: "Loading fonts",
KStepTsnet: "Joining the tailnet",
KStepRules: "Resolving forward rules",
KStepDiscovery: "Starting LAN discovery",
KStepMonitors: "Starting monitors",
KStepReady: "Ready",
KSplashHint: "The first tailnet join can take a dozen seconds",
KSplashStuckHint: "This step is taking unusually long — export the log to investigate",
KSplashExportLog: "Export log",
KSplashRetry: "Startup failed, retrying",
KYes: "Yes",
KNo: "No",
KUnknown: "Unknown",
KSupported: "Supported",
KUnsupported: "Not supported",
KEnabled: "Enabled",
KDisabled: "Disabled",
KNone: "None",
KRefresh: "Refresh",
KRetry: "Retry",
KClose: "Close",
KCopy: "Copy",
KCopied: "Copied",
KDetails: "Details",
KLoading: "Loading",
KError: "Error",
KNever: "Never",
KJustNow: "just now",
KSecondsAgo: "s ago",
KMinutesAgo: "m ago",
KHoursAgo: "h ago",
KTotal: "Total",
KOnline: "Online",
KOffline: "Offline",
KOvTailnet: "Tailnet",
KOvSelf: "This node",
KOvPeersOnline: "Peers online",
KOvForwardRules: "Forward rules",
KOvConnectRules: "Connect rules",
KOvUptime: "Uptime",
KOvHealth: "Health",
KOvQuickDiag: "Run diagnostics",
KOvNoIssues: "No issues found",
KPeersTitle: "Tailscale peers",
KPeersLinked: "Linked",
KPeersEmpty: "No peers yet",
KPeersResolving: "Resolving the peers named in the config",
KPeerLatency: "Latency",
KPeerRoute: "Route",
KPeerRouteDirect: "Direct",
KPeerRouteDERP: "DERP relay",
KPeerRoutePeerRelay: "Peer relay",
KPeerRouteOffline: "Offline",
KPeerRouteUnknown: "Unknown",
KPeerAvg: "avg",
KPeerMin: "min",
KPeerMax: "max",
KPeerJitter: "jitter",
KPeerLoss: "loss",
KPeerRx: "Rx",
KPeerTx: "Tx",
KPeerLastSeen: "Last seen",
KPeerLastHandshake: "Last handshake",
KPeerAddresses: "Addresses",
KPeerEndpoint: "Endpoint",
KPeerOS: "OS",
KPeerExitNode: "Exit node",
KPeerTags: "Tags",
KGraphTitle: "Latency graph",
KGraphEmpty: "Collecting latency samples",
KGraphWindow: "last",
KGraphLegendHint: "Click a legend entry to hide that peer",
KSvcTitle: "Local services",
KSvcSubtitle: "Listening on this machine, forwarded to each server",
KSvcEmpty: "No connect rules configured",
KSvcBroadcast: "Broadcast",
KDiagTitle: "Network diagnostics",
KDiagRun: "Run diagnostics",
KDiagRunning: "Running",
KDiagRerun: "Run again",
KDiagNever: "Not run yet",
KDiagLastRun: "Last run",
KDiagCopyReport: "Copy report",
KDiagSecIface: "Local egress addresses",
KDiagSecUDP: "UDP connectivity",
KDiagSecNAT: "NAT type",
KDiagSecPortMap: "Port mapping",
KDiagSecOverseas: "Overseas reachability",
KDiagSecEgress: "Egress IP and geolocation",
KDiagSecTailscale: "Tailscale internals",
KDiagNatType: "NAT type",
KDiagNatMapping: "Mapping behaviour",
KDiagNatFiltering: "Filtering behaviour",
KDiagNatHairpin: "Hairpinning",
KDiagNatPortPreserve: "Port preserving",
KDiagUdpV4: "IPv4 UDP",
KDiagUdpV6: "IPv6 UDP",
KDiagUdpPortsOK: "Reachable ports",
KDiagUdpPortsBlocked: "Blocked ports",
KDiagIfaceDefaultV4: "Default IPv4 source",
KDiagIfaceDefaultV6: "Default IPv6 source",
KDiagUPnP: "UPnP IGD",
KDiagNATPMP: "NAT-PMP",
KDiagPCP: "PCP",
KDiagGateway: "Gateway",
KDiagExternalIP: "External address",
KDiagOverseasTarget: "Target",
KDiagEgressMethod: "Method",
KDiagEgressIP: "Egress IP",
KDiagEgressGeo: "Location",
KDiagEgressDivergent: "Egress mismatch",
KDiagEgressDivergentHint: "STUN (UDP) itself saw more than one public IP, so direct connections will suffer",
KDiagEgressDivergentHTTP: "Only the HTTP probes disagreed; the STUN (UDP) egress is consistent, so hole punching is usually unaffected",
KDiagGeoSkipped: "Geolocation skipped",
KDiagPreferredDERP: "Preferred DERP",
KDiagDerpLatency: "DERP latency",
KDiagCaptivePortal: "Captive portal",
KDiagMappingVaries: "Mapping varies by destination",
KDiagSkipGeo: "Skip geolocation",
KDiagSkipGeoHint: "Geolocation sends your public IP to a third-party service",
KNatOpen: "Open internet",
KNatFullCone: "Full cone",
KNatRestricted: "Address-restricted cone",
KNatPortRestricted: "Port-restricted cone",
KNatSymmetric: "Symmetric",
KNatUDPBlocked: "UDP blocked",
KNatSymmetricFW: "Symmetric firewall",
KNatUnknown: "Undetermined",
KLogsTitle: "Logs",
KLogsSearch: "Search logs…",
KLogsLevel: "Level",
KLogsSource: "Source",
KLogsFollow: "Follow",
KLogsAll: "All",
KLogsEmpty: "No matching log entries",
KLogsCopyAll: "Copy to clipboard",
KLogsSaveFile: "Save to file",
KLogsUpload: "Upload and share",
KLogsUploading: "Uploading",
KLogsUploaded: "Uploaded, link copied",
KLogsUploadFail: "Upload failed",
KLogsRedact: "Redact secrets",
KLogsRedactHint: "Credentials such as authkeys are removed before upload",
KLogsShown: "shown",
KLogsDropped: "earlier entries were dropped",
KLogsIncludeDiag: "Include diagnostics",
KSetTheme: "Theme",
KSetThemeDark: "Dark",
KSetThemeLight: "Light",
KSetLanguage: "Language",
KSetAbout: "About",
KSetConfigPath: "Config file",
KSetVersion: "Version",
KSetFont: "CJK font",
KSetFontMissing: "No CJK font found, the UI fell back to English",
}
// Tr returns the localised string for k, falling back to English and then to a
// visible placeholder rather than an empty label.
func Tr(l Lang, k Key) string {
if k < 0 || k >= kCount {
return "?"
}
if l == LangZH {
if s := zhStrings[k]; s != "" {
return s
}
}
if s := enStrings[k]; s != "" {
return s
}
return "?"
}