Files
tslink/gui/i18n.go
T
2026-07-26 09:39:17 +00:00

632 lines
17 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
KNavLan
KNavDiag
KNavLogs
KNavSettings
// Service lifecycle.
KStateStarting
KStateConnecting
KStateRunning
KStateDegraded
KStateStopped
KStateError
KStateRetrying
// Splash steps.
KStepConfig
KStepFonts
KStepTsnet
KStepRules
KStepDiscovery
KStepMonitors
KStepReady
KSplashHint
KSplashLogHint
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
KOvLanServers
KOvForwardRules
KOvConnectRules
KOvUptime
KOvHealth
KOvQuickDiag
KOvNoIssues
// Peers page.
KPeersTitle
KPeersLinked
KPeersOther
KPeersEmpty
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
// LAN page.
KLanTitle
KLanSubtitle
KLanEmpty
KLanListening
KLanMotd
KLanPort
KLanAddress
KLanSeen
KLanSelf
KLanSelfHint
KLanPackets
KLanBindError
// 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
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
KLogsOpenOverlay
// Settings.
KSetTheme
KSetThemeDark
KSetThemeLight
KSetLanguage
KSetAbout
KSetConfigPath
KSetVersion
KSetFont
KSetFontMissing
kCount
)
var zhStrings = [kCount]string{
KAppTitle: "tslink",
KAppSubtitle: "Tailscale 内网穿透",
KNavOverview: "概览",
KNavPeers: "节点",
KNavLan: "局域网",
KNavDiag: "网络诊断",
KNavLogs: "日志",
KNavSettings: "设置",
KStateStarting: "正在启动",
KStateConnecting: "正在连接",
KStateRunning: "运行中",
KStateDegraded: "降级运行",
KStateStopped: "已停止",
KStateError: "出错",
KStateRetrying: "正在重试",
KStepConfig: "读取配置",
KStepFonts: "加载字体",
KStepTsnet: "接入 Tailscale 网络",
KStepRules: "解析转发规则",
KStepDiscovery: "启动局域网发现",
KStepMonitors: "启动状态监控",
KStepReady: "准备就绪",
KSplashHint: "首次接入 Tailscale 可能需要十几秒",
KSplashLogHint: "实时日志(截图时可一并保留)",
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: "在线节点",
KOvLanServers: "局域网服务器",
KOvForwardRules: "转发规则",
KOvConnectRules: "连接规则",
KOvUptime: "运行时长",
KOvHealth: "健康状况",
KOvQuickDiag: "运行网络诊断",
KOvNoIssues: "未发现问题",
KPeersTitle: "Tailscale 节点",
KPeersLinked: "已关联",
KPeersOther: "其他节点",
KPeersEmpty: "暂无节点",
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: "最近 20 分钟",
KGraphLegendHint: "点击图例可隐藏对应节点",
KLanTitle: "局域网 Minecraft 服务器",
KLanSubtitle: "监听 224.0.2.60:4445 的广播",
KLanEmpty: "未发现局域网服务器",
KLanListening: "监听中",
KLanMotd: "服务器名称",
KLanPort: "端口",
KLanAddress: "地址",
KLanSeen: "最后广播",
KLanSelf: "本机广播",
KLanSelfHint: "由 tslink 转发并广播,说明隧道已生效",
KLanPackets: "收包",
KLanBindError: "无法监听组播",
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: "不同探测方式得到了不同的公网 IP,通常说明有代理或分流工具在生效",
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: "附带诊断报告",
KLogsOpenOverlay: "浮层日志",
KSetTheme: "主题",
KSetThemeDark: "深色",
KSetThemeLight: "浅色",
KSetLanguage: "语言",
KSetAbout: "关于",
KSetConfigPath: "配置文件",
KSetVersion: "版本",
KSetFont: "中文字体",
KSetFontMissing: "未找到中文字体,界面已切换为英文",
}
var enStrings = [kCount]string{
KAppTitle: "tslink",
KAppSubtitle: "Tailscale link layer",
KNavOverview: "Overview",
KNavPeers: "Peers",
KNavLan: "LAN",
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",
KSplashLogHint: "Live log (stays visible in screenshots)",
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",
KOvLanServers: "LAN servers",
KOvForwardRules: "Forward rules",
KOvConnectRules: "Connect rules",
KOvUptime: "Uptime",
KOvHealth: "Health",
KOvQuickDiag: "Run diagnostics",
KOvNoIssues: "No issues found",
KPeersTitle: "Tailscale peers",
KPeersLinked: "Linked",
KPeersOther: "Other peers",
KPeersEmpty: "No peers yet",
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 20 minutes",
KGraphLegendHint: "Click a legend entry to hide that peer",
KLanTitle: "Minecraft servers on the LAN",
KLanSubtitle: "Listening for broadcasts on 224.0.2.60:4445",
KLanEmpty: "No LAN servers discovered",
KLanListening: "Listening",
KLanMotd: "Name",
KLanPort: "Port",
KLanAddress: "Address",
KLanSeen: "Last broadcast",
KLanSelf: "Ours",
KLanSelfHint: "Advertised by tslink, so the tunnel is working",
KLanPackets: "packets",
KLanBindError: "Cannot join multicast group",
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: "Different probes saw different public IPs, which usually means a proxy or split tunnel is active",
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",
KLogsOpenOverlay: "Log overlay",
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 "?"
}