初版功能完成
ci / Go checks (ubuntu-latest) (push) Has been cancelled
ci / Go checks (windows-latest) (push) Has been cancelled

This commit is contained in:
qsc
2026-08-29 13:12:17 +08:00
commit 142e5dc7d6
217 changed files with 21313 additions and 0 deletions
+96
View File
@@ -0,0 +1,96 @@
// Package localization provides Chinese operator-facing labels while keeping
// protocol codes and persisted enum values stable.
package localization
import "strings"
var sessionStatuses = map[string]string{
"IDLE": "空闲",
"CREATING": "正在创建",
"PREPARING_SITE": "正在准备现场端",
"READY": "准备就绪",
"ACTIVE": "活动中",
"STOPPING": "正在停止",
"CLOSED": "已关闭",
"FAILED": "失败",
}
var nodeStatuses = map[string]string{
"ONLINE": "在线",
"UNSTABLE": "连接不稳定",
"OFFLINE": "离线",
}
var routeResults = map[string]string{
"DIRECT": "直连路由",
"ROUTED": "明确路由",
"DEFAULT_ONLY": "仅有默认路由",
"NO_ROUTE": "没有路由",
"OVERLAY_CONFLICT": "与 Overlay 网段冲突",
}
var errorCodes = map[string]string{
"SERVER_UNREACHABLE": "无法连接服务器",
"JOIN_TOKEN_INVALID": "Join Token 无效",
"NODE_AUTH_FAILED": "节点身份认证失败",
"OVERLAY_LOCAL_CONFLICT": "Overlay 网段与本地网络冲突",
"ENGINEER_SESSION_EXISTS": "Engineer 已存在未结束的会话",
"SITE_OFFLINE": "现场端离线",
"CIDR_INVALID": "远程网段格式无效",
"CIDR_LOCAL_CONFLICT": "远程网段与 Engineer 本地网络冲突",
"CIDR_OVERLAY_CONFLICT": "远程网段与 Overlay 网段冲突",
"SITE_NO_ROUTE": "现场端没有通往远程网段的明确路由",
"NETSTACK_UNAVAILABLE": "现场端 netstack 网关不可用",
"FLOW_LIMIT_REACHED": "现场端连接流数量已达到上限",
"SESSION_TIMEOUT": "会话建立超时",
"SESSION_INJECT_FAILED": "会话数据包注入失败",
"NODE_RUNTIME_REBUILT": "节点网络运行时已重建",
"NODE_REVOKED": "节点已被撤销",
"ADMIN_DISCONNECT": "管理员强制断开",
"ENGINEER_OPERATOR": "Engineer 操作员主动断开",
}
func bilingual(value string, labels map[string]string) string {
value = strings.TrimSpace(value)
if label, ok := labels[value]; ok {
return label + "" + value + ""
}
return value
}
// SessionStatus returns a Chinese label with the stable wire value retained.
func SessionStatus(value string) string { return bilingual(value, sessionStatuses) }
// NodeStatus returns a Chinese label with the stable persisted value retained.
func NodeStatus(value string) string { return bilingual(value, nodeStatuses) }
// RouteResult returns a Chinese route decision with the stable result retained.
func RouteResult(value string) string { return bilingual(value, routeResults) }
// Reason translates a stable error/reason code without hiding its original value.
func Reason(value string) string { return bilingual(value, errorCodes) }
// ErrorMessage translates common Windows/operator errors. Unknown errors are
// deliberately preserved verbatim so diagnostics are never lost.
func ErrorMessage(value string) string {
trimmed := strings.TrimSpace(value)
translations := []struct {
fragment string
chinese string
}{
{"administrator privileges are required to manage the RemLink Wintun adapter", "需要以管理员身份运行,才能管理 RemLink Wintun 网卡"},
{"decrypt WireGuard private key: unprotect secret with DPAPI", "无法解密 WireGuard 私钥:identity.json 不是由当前 Windows 系统生成,需重新注册节点"},
{"Join Token is required for first registration", "首次注册需要在 YAML 中填写 Join Token"},
{"configured Server URL differs from persisted Node identity", "YAML 中的 Server URL 与已保存的节点身份不一致"},
{"Site has no route to Remote CIDR", "现场端没有通往远程网段的明确路由"},
{"Engineer Session runtime is not ready", "Engineer 会话运行时尚未就绪"},
{"Node Session runtime is not initialized", "节点会话运行时尚未初始化"},
{"Site Session runtime is not ready", "Site 会话运行时尚未就绪"},
}
for _, translation := range translations {
if strings.Contains(trimmed, translation.fragment) {
return translation.chinese + "(原始错误:" + trimmed + ""
}
}
return Reason(trimmed)
}
+32
View File
@@ -0,0 +1,32 @@
package localization
import (
"strings"
"testing"
)
func TestStableValuesRemainVisibleInChineseLabels(t *testing.T) {
for _, test := range []struct {
got, chinese, stable string
}{
{SessionStatus("FAILED"), "失败", "FAILED"},
{NodeStatus("UNSTABLE"), "连接不稳定", "UNSTABLE"},
{RouteResult("DEFAULT_ONLY"), "仅有默认路由", "DEFAULT_ONLY"},
{Reason("SITE_NO_ROUTE"), "没有通往远程网段", "SITE_NO_ROUTE"},
} {
if !strings.Contains(test.got, test.chinese) || !strings.Contains(test.got, test.stable) {
t.Fatalf("label %q does not contain %q and %q", test.got, test.chinese, test.stable)
}
}
}
func TestErrorMessageTranslatesKnownErrorsAndPreservesUnknown(t *testing.T) {
known := "decrypt WireGuard private key: unprotect secret with DPAPI: invalid state"
if got := ErrorMessage(known); !strings.Contains(got, "无法解密") || !strings.Contains(got, known) {
t.Fatalf("known error translation = %q", got)
}
unknown := "a future diagnostic with important detail"
if got := ErrorMessage(unknown); got != unknown {
t.Fatalf("unknown error translation = %q, want original", got)
}
}