mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-12 21:53:00 -06:00
fix(docs-i18n): reject leaked placeholder variants
This commit is contained in:
@@ -78,6 +78,9 @@ func validateDocBodyFencedLiterals(source, translated string) error {
|
||||
}
|
||||
sourceStructure := summarizeDocChunkStructure(source)
|
||||
translatedStructure := summarizeDocChunkStructure(translated)
|
||||
if !sameI18NProtocolMarkers(source, translated) {
|
||||
return fmt.Errorf("i18n placeholder mismatch")
|
||||
}
|
||||
if !slices.Equal(sourceStructure.listShapes, translatedStructure.listShapes) {
|
||||
return fmt.Errorf("list structure mismatch: source=%v translated=%v", sourceStructure.listShapes, translatedStructure.listShapes)
|
||||
}
|
||||
@@ -236,6 +239,12 @@ func validateDocChunkTranslation(source, translated string) error {
|
||||
sourceLower := strings.ToLower(source)
|
||||
translatedLower := strings.ToLower(translated)
|
||||
for _, token := range docsProtocolTokens {
|
||||
if token == "__OC_I18N_" {
|
||||
if !sameI18NProtocolMarkers(source, translated) {
|
||||
return fmt.Errorf("protocol token leaked: %s", token)
|
||||
}
|
||||
continue
|
||||
}
|
||||
tokenLower := strings.ToLower(token)
|
||||
if strings.Contains(sourceLower, tokenLower) {
|
||||
continue
|
||||
@@ -278,6 +287,16 @@ func validateDocChunkTranslation(source, translated string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func sameI18NProtocolMarkers(source, translated string) bool {
|
||||
if !sameStringMultiset(placeholderRe.FindAllString(source, -1), placeholderRe.FindAllString(translated, -1)) {
|
||||
return false
|
||||
}
|
||||
sourceResidual := placeholderRe.ReplaceAllString(source, "")
|
||||
translatedResidual := placeholderRe.ReplaceAllString(translated, "")
|
||||
return strings.Count(strings.ToLower(sourceResidual), "__oc_i18n_") ==
|
||||
strings.Count(strings.ToLower(translatedResidual), "__oc_i18n_")
|
||||
}
|
||||
|
||||
func sameStringMultiset(left, right []string) bool {
|
||||
if len(left) != len(right) {
|
||||
return false
|
||||
|
||||
@@ -546,6 +546,44 @@ func TestValidateDocChunkTranslationRejectsInventedI18NPlaceholder(t *testing.T)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateDocChunkTranslationRejectsAdditionalI18NPlaceholder(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
source := "```text\n__OC_I18N_900000__\n```\n"
|
||||
translated := "```text\n__OC_I18N_900000__\n```\n__OC_I18N_900014__\n"
|
||||
|
||||
err := validateDocChunkTranslation(source, translated)
|
||||
if err == nil {
|
||||
t.Fatal("expected additional i18n placeholder to be rejected")
|
||||
}
|
||||
if !strings.Contains(err.Error(), "protocol token leaked: __OC_I18N_") {
|
||||
t.Fatalf("expected i18n placeholder leakage error, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateDocChunkTranslationRejectsMalformedI18NPlaceholder(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
for _, leaked := range []string{"__oc_i18n_900014__", "__OC_I18N_invalid__"} {
|
||||
err := validateDocChunkTranslation("Regular paragraph.\n", "Обычный абзац.\n"+leaked+"\n")
|
||||
if err == nil {
|
||||
t.Fatalf("expected malformed i18n placeholder %q to be rejected", leaked)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateDocBodyFencedLiteralsRejectsRestoredPlaceholderLeak(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
source := "Before.\n\n```ts\nconst value = \"<user-id>\";\n```\n\nAfter.\n"
|
||||
translated := "До.\n\n__OC_I18N_900014__\n\nПосле.\n"
|
||||
|
||||
err := validateDocBodyFencedLiterals(source, translated)
|
||||
if err == nil {
|
||||
t.Fatal("expected restored placeholder leak to be rejected")
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateDocChunkTranslationRejectsHeadingLoss(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
@@ -2142,7 +2180,7 @@ func TestProcessFileDocUsesFieldLevelFrontmatterTranslation(t *testing.T) {
|
||||
if !strings.Contains(text, "在 Fly.io 上部署 OpenClaw") {
|
||||
t.Fatalf("expected translated read_when entry in output:\n%s", text)
|
||||
}
|
||||
if !strings.Contains(text, "prompt_version: 16") {
|
||||
if !strings.Contains(text, "prompt_version: 17") {
|
||||
t.Fatalf("expected prompt version 15 in output metadata:\n%s", text)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ import (
|
||||
|
||||
const (
|
||||
workflowVersion = 16
|
||||
promptVersion = 16
|
||||
promptVersion = 17
|
||||
docsI18nEngineName = "codex"
|
||||
envDocsI18nProvider = "OPENCLAW_DOCS_I18N_PROVIDER"
|
||||
envDocsI18nModel = "OPENCLAW_DOCS_I18N_MODEL"
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
func TestCacheNamespaceIncludesPromptVersion(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
if want := "prompt=16"; !strings.Contains(cacheNamespace(), want) {
|
||||
if want := "prompt=17"; !strings.Contains(cacheNamespace(), want) {
|
||||
t.Fatalf("expected cache namespace to contain %q, got %q", want, cacheNamespace())
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user