fix(docs): preserve inline code literals

This commit is contained in:
Peter Steinberger
2026-07-15 03:02:49 -04:00
parent 0d7da61e9b
commit 6beb726be7
4 changed files with 62 additions and 4 deletions

View File

@@ -494,7 +494,7 @@ When a channel cannot render interactive controls, button and select values
fall back to plain text. The fallback behavior preserves usability while
keeping opaque callback data private:
- **`command`-typed actions** render as `label: \`command\`` so users can
- **`command`-typed actions** render as `` label: `command` `` so users can
copy the command and run it manually in the channel input.
- **`callback`-typed actions** and legacy **`value`** fields render as
label-only. The opaque callback value is not exposed in fallback text.

View File

@@ -97,6 +97,9 @@ func validateDocBodyFencedLiterals(source, translated string) error {
if !slices.Equal(sourceStructure.listShapes, translatedStructure.listShapes) {
return fmt.Errorf("list structure mismatch: source=%v translated=%v", sourceStructure.listShapes, translatedStructure.listShapes)
}
if !sameStringMultiset(sourceStructure.inlineCodeSpans, translatedStructure.inlineCodeSpans) {
return fmt.Errorf("inline code mismatch: source=%d translated=%d", len(sourceStructure.inlineCodeSpans), len(translatedStructure.inlineCodeSpans))
}
if !slices.Equal(sourceStructure.fencedPlaceholders, translatedStructure.fencedPlaceholders) {
return fmt.Errorf("fenced placeholder mismatch: source=%d translated=%d", len(sourceStructure.fencedPlaceholders), len(translatedStructure.fencedPlaceholders))
}

View File

@@ -744,6 +744,61 @@ func TestValidateDocChunkTranslationAcceptsReorderedInlineCode(t *testing.T) {
}
}
func TestMaskMarkdownDocSyntaxPreservesCanonicalNestedBackticks(t *testing.T) {
t.Parallel()
source := strings.Join([]string{
"- A Windows path can end in a backslash: `C:\\`.",
"- **`command`-typed actions** render as `` label: `command` `` so users can copy it.",
"- **`callback`-typed actions** and legacy **`value`** fields render label-only.",
"",
}, "\n")
state := NewPlaceholderState(source)
placeholders := []string{}
mapping := map[string]string{}
masked := maskMarkdownDocSyntax(source, state.Next, &placeholders, mapping)
wantLiterals := []string{"`command`", "`` label: `command` ``", "`callback`", "`value`", "`C:\\`"}
for _, literal := range wantLiterals {
if strings.Contains(masked, literal) {
t.Fatalf("expected %q to be masked:\n%s", literal, masked)
}
}
for _, prose := range []string{"typed actions", "so users can copy it", "fields render label-only", "A Windows path can end in a backslash"} {
if !strings.Contains(masked, prose) {
t.Fatalf("expected translatable prose %q to remain visible:\n%s", prose, masked)
}
}
maskedLiterals := []string{}
for _, value := range mapping {
if strings.HasPrefix(value, "`") {
maskedLiterals = append(maskedLiterals, value)
}
}
if !sameStringMultiset(wantLiterals, maskedLiterals) {
t.Fatalf("masked inline literals = %v, want %v", maskedLiterals, wantLiterals)
}
if restored := unmaskMarkdown(masked, placeholders, mapping); restored != source {
t.Fatalf("inline-code round trip changed source:\n%s\nwant:\n%s", restored, source)
}
}
func TestValidateDocBodyRejectsTranslatedInlineCode(t *testing.T) {
t.Parallel()
source := "- **`callback`-typed actions** and legacy **`value`** fields render label-only.\n"
translated := "- **`कॉलबैक`-typed actions** and legacy **`मान`** fields render label-only.\n"
err := validateDocBodyFencedLiterals(source, translated)
if err == nil || !strings.Contains(err.Error(), "inline code mismatch") {
t.Fatalf("expected final-document inline-code mismatch, got %v", err)
}
preserved := "- **`callback`-प्रकार की कार्रवाइयाँ** और पुराने **`value`** फ़ील्ड केवल लेबल दिखाते हैं।\n"
if err := validateDocBodyFencedLiterals(source, preserved); err != nil {
t.Fatalf("expected translated prose with preserved inline code to pass: %v", err)
}
}
func TestValidateDocChunkTranslationRejectsTranslatedMultiBacktickCode(t *testing.T) {
t.Parallel()
@@ -2329,8 +2384,8 @@ 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: 28") {
t.Fatalf("expected prompt version 28 in output metadata:\n%s", text)
if !strings.Contains(text, "prompt_version: 29") {
t.Fatalf("expected prompt version 29 in output metadata:\n%s", text)
}
}

View File

@@ -12,7 +12,7 @@ import (
const (
workflowVersion = 16
promptVersion = 28
promptVersion = 29
docsI18nEngineName = "codex"
envDocsI18nProvider = "OPENCLAW_DOCS_I18N_PROVIDER"
envDocsI18nModel = "OPENCLAW_DOCS_I18N_MODEL"