632 lines
17 KiB
Go
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 "?"
|
|
}
|