Files
artex/intercept/intercept_localized_test.go
T
dela 97668dab7e
ci / go (push) Waiting to run
ci / go-db (agent) (push) Waiting to run
ci / go-db (config) (push) Waiting to run
ci / go-db (db) (push) Waiting to run
ci / go-db (evidence) (push) Waiting to run
ci / go-db (llmrec) (push) Waiting to run
ci / go-db (server) (push) Waiting to run
detections / detections (push) Waiting to run
docs / links (push) Waiting to run
web / web (push) Waiting to run
Localize user-facing UI, agent output, and backend messages to Simplified Chinese
2026-10-09 14:08:31 +08:00

101 lines
3.3 KiB
Go

package intercept
import (
"fmt"
"strings"
"testing"
"unicode"
)
// hasHangul reports whether s contains any Hangul syllable.
func hasHangul(s string) bool {
for _, r := range s {
if r >= 0xAC00 && r <= 0xD7A3 {
return true
}
}
return false
}
// hasHan reports whether s contains any CJK Han ideograph.
func hasHan(s string) bool {
for _, r := range s {
if unicode.Is(unicode.Han, r) {
return true
}
}
return false
}
// assertChinese fails if s lacks Han ideographs or still carries Hangul. Reverting
// any localized message back to Korean trips hasHangul, so the test is not vacuous.
func assertChinese(t *testing.T, label, s string) {
t.Helper()
if !hasHan(s) {
t.Errorf("%s: 缺少汉字: %q", label, s)
}
if hasHangul(s) {
t.Errorf("%s: 仍残留韩文: %q", label, s)
}
}
// TestInterceptMessagesLocalized pins the user-facing judge/approval messages to
// Korean. These surface in the approval record reason, the activity stream, and
// the 409 response for an already-decided request.
func TestInterceptMessagesLocalized(t *testing.T) {
for _, c := range []struct{ name, s string }{
{"msgReviewContextIncomplete", msgReviewContextIncomplete},
{"msgModelApprovalFailed", msgModelApprovalFailed},
{"msgModelOutputUnparsable", msgModelOutputUnparsable},
{"reasonWorkCanceled", reasonWorkCanceled},
{"reasonWorkCanceledPreExec", reasonWorkCanceledPreExec},
{"reasonApprovalTimeout", reasonApprovalTimeout},
{"reasonManualDeny", reasonManualDeny},
{"reasonManualAllow", reasonManualAllow},
{"ErrAlreadyDecided", ErrAlreadyDecided.Error()},
} {
assertChinese(t, c.name, c.s)
}
}
// TestJudgeActionLabelLocalized checks the three judge verdict labels are Korean
// (허용 / 차단 / 확인 요청, per the glossary) and that an unknown action still
// passes through untranslated.
func TestJudgeActionLabelLocalized(t *testing.T) {
for _, action := range []string{"allow", "deny", "ask"} {
assertChinese(t, "judgeActionLabel("+action+")", judgeActionLabel(action))
}
if got := judgeActionLabel("weird"); got != "weird" {
t.Errorf("judgeActionLabel(weird) = %q, want passthrough", got)
}
}
// TestDefaultMessageLocalized checks the rule-derived deny/ask messages are Korean
// and still embed the rule name, while allow stays empty.
func TestDefaultMessageLocalized(t *testing.T) {
for _, action := range []string{"deny", "ask"} {
msg := defaultMessage(action, "R1")
assertChinese(t, "defaultMessage("+action+")", msg)
if !strings.Contains(msg, "R1") {
t.Errorf("defaultMessage(%s) dropped rule name: %q", action, msg)
}
}
if got := defaultMessage("allow", "R1"); got != "" {
t.Errorf("defaultMessage(allow) = %q, want empty", got)
}
}
// TestToolApprovalSummaryLocalized checks the activity summary is Korean and stays
// parseable by transcript.tsx, which extracts the pending id via /\(#(\d+)\)/ and
// the tool name via /도구\s+(\S+)\s+승인/.
func TestToolApprovalSummaryLocalized(t *testing.T) {
s := fmt.Sprintf(msgToolApprovalRequestFmt, "Bash", 42)
assertChinese(t, "msgToolApprovalRequestFmt", s)
if !strings.Contains(s, "(#42)") {
t.Errorf("summary lost the (#N) marker (transcript.tsx pending_id regex): %q", s)
}
if !strings.Contains(s, "工具 Bash 审批") {
t.Errorf("summary lost the '工具 X 审批' shape (transcript.tsx toolName regex): %q", s)
}
}