Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  process.go   Sprache: unbekannt

 
Spracherkennung für: .go vermutete Sprache: Unknown {[0] [0] [0]} [Methode: Schwerpunktbildung, einfache Gewichte, sechs Dimensionen]

package main

import (
 "context"
 "fmt"
 "log"
 "os"
 "path/filepath"
 "strings"
 "time"

 "gopkg.in/yaml.v3"
)

func processFile(ctx context.Context, translator docsTranslator, tm *TranslationMemory, docsRoot, filePath, srcLang, tgtLang string) (bool, string, error) {
 absPath, relPath, err := resolveDocsPath(docsRoot, filePath)
 if err != nil {
  return false, "", err
 }

 content, err := os.ReadFile(absPath)
 if err != nil {
  return false, "", err
 }

 frontMatter, body := splitFrontMatter(string(content))
 frontData := map[string]any{}
 if frontMatter != "" {
  if err := yaml.Unmarshal([]byte(frontMatter), &frontData); err != nil {
   return false, "", fmt.Errorf("frontmatter parse failed for %s: %w", relPath, err)
  }
 }

 if err := translateFrontMatter(ctx, translator, tm, frontData, relPath, srcLang, tgtLang); err != nil {
  return false, "", err
 }

 body, err = translateHTMLBlocks(ctx, translator, body, srcLang, tgtLang)
 if err != nil {
  return false, "", err
 }

 segments, err := extractSegments(body, relPath)
 if err != nil {
  return false, "", err
 }

 namespace := cacheNamespace()
 for i := range segments {
  seg := &segments[i]
  seg.CacheKey = cacheKey(namespace, srcLang, tgtLang, seg.SegmentID, seg.TextHash)
  if entry, ok := tm.Get(seg.CacheKey); ok {
   seg.Translated = entry.Translated
   continue
  }
  translated, err := translator.Translate(ctx, seg.Text, srcLang, tgtLang)
  if err != nil {
   return false, "", fmt.Errorf("translate failed (%s): %w", relPath, err)
  }
  seg.Translated = translated
  entry := TMEntry{
   CacheKey:   seg.CacheKey,
   SegmentID:  seg.SegmentID,
   SourcePath: relPath,
   TextHash:   seg.TextHash,
   Text:       seg.Text,
   Translated: translated,
   Provider:   docsPiProvider(),
   Model:      docsPiModel(),
   SrcLang:    srcLang,
   TgtLang:    tgtLang,
   UpdatedAt:  time.Now().UTC().Format(time.RFC3339),
  }
  tm.Put(entry)
 }

 translatedBody := applyTranslations(body, segments)
 updatedFront, err := encodeFrontMatter(frontData, relPath, content)
 if err != nil {
  return false, "", err
 }

 outputPath := filepath.Join(docsRoot, tgtLang, relPath)
 if err := os.MkdirAll(filepath.Dir(outputPath), 0o755); err != nil {
  return false, "", err
 }

 output := updatedFront + translatedBody
 return false, outputPath, os.WriteFile(outputPath, []byte(output), 0o644)
}

func splitFrontMatter(content string) (string, string) {
 if !strings.HasPrefix(content, "---") {
  return "", content
 }
 lines := strings.Split(content, "\n")
 if len(lines) < 2 {
  return "", content
 }
 endIndex := -1
 for i := 1; i < len(lines); i++ {
  if strings.TrimSpace(lines[i]) == "---" {
   endIndex = i
   break
  }
 }
 if endIndex == -1 {
  return "", content
 }
 front := strings.Join(lines[1:endIndex], "\n")
 body := strings.Join(lines[endIndex+1:], "\n")
 if strings.HasPrefix(body, "\n") {
  body = body[1:]
 }
 return front, body
}

func encodeFrontMatter(frontData map[string]any, relPath string, source []byte) (string, error) {
 if frontData == nil {
  frontData = map[string]any{}
 }
 frontData["x-i18n"] = map[string]any{
  "source_path":  relPath,
  "source_hash":  hashBytes(source),
  "provider":     docsPiProvider(),
  "model":        docsPiModel(),
  "workflow":     workflowVersion,
  "generated_at": time.Now().UTC().Format(time.RFC3339),
 }
 encoded, err := yaml.Marshal(frontData)
 if err != nil {
  return "", err
 }
 return fmt.Sprintf("---\n%s---\n\n", string(encoded)), nil
}

func translateFrontMatter(ctx context.Context, translator docsTranslator, tm *TranslationMemory, data map[string]any, relPath, srcLang, tgtLang string) error {
 if len(data) == 0 {
  return nil
 }
 if summary, ok := data["summary"].(string); ok {
  if docsI18nVerboseLogs() {
   log.Printf("docs-i18n: frontmatter start %s field=summary bytes=%d", relPath, len(summary))
  }
  translated, err := translateSnippet(ctx, translator, tm, relPath+":frontmatter:summary", summary, srcLang, tgtLang)
  if err != nil {
   return err
  }
  if docsI18nVerboseLogs() {
   log.Printf("docs-i18n: frontmatter done %s field=summary out_bytes=%d", relPath, len(translated))
  }
  data["summary"] = translated
 }
 if title, ok := data["title"].(string); ok {
  if docsI18nVerboseLogs() {
   log.Printf("docs-i18n: frontmatter start %s field=title bytes=%d", relPath, len(title))
  }
  translated, err := translateSnippet(ctx, translator, tm, relPath+":frontmatter:title", title, srcLang, tgtLang)
  if err != nil {
   return err
  }
  if docsI18nVerboseLogs() {
   log.Printf("docs-i18n: frontmatter done %s field=title out_bytes=%d", relPath, len(translated))
  }
  data["title"] = translated
 }
 if readWhen, ok := data["read_when"].([]any); ok {
  translated := make([]any, 0, len(readWhen))
  for idx, item := range readWhen {
   textValue, ok := item.(string)
   if !ok {
    translated = append(translated, item)
    continue
   }
   if docsI18nVerboseLogs() {
    log.Printf("docs-i18n: frontmatter start %s field=read_when[%d] bytes=%d", relPath, idx, len(textValue))
   }
   value, err := translateSnippet(ctx, translator, tm, fmt.Sprintf("%s:frontmatter:read_when:%d", relPath, idx), textValue, srcLang, tgtLang)
   if err != nil {
    return err
   }
   if docsI18nVerboseLogs() {
    log.Printf("docs-i18n: frontmatter done %s field=read_when[%d] out_bytes=%d", relPath, idx, len(value))
   }
   translated = append(translated, value)
  }
  data["read_when"] = translated
 }
 return nil
}

func docsI18nVerboseLogs() bool {
 value := strings.TrimSpace(os.Getenv("OPENCLAW_DOCS_I18N_VERBOSE_LOGS"))
 if value == "" {
  return false
 }
 switch strings.ToLower(value) {
 case "1", "true", "yes", "on", "debug", "verbose":
  return true
 default:
  return false
 }
}

func translateSnippet(ctx context.Context, translator docsTranslator, tm *TranslationMemory, segmentID, textValue, srcLang, tgtLang string) (string, error) {
 if strings.TrimSpace(textValue) == "" {
  return textValue, nil
 }
 namespace := cacheNamespace()
 textHash := hashText(textValue)
 ck := cacheKey(namespace, srcLang, tgtLang, segmentID, textHash)
 if entry, ok := tm.Get(ck); ok {
  return entry.Translated, nil
 }
 translated, err := translator.Translate(ctx, textValue, srcLang, tgtLang)
 if err != nil {
  return "", err
 }
 shouldCache := true
 if validationErr := validateFrontmatterScalarTranslation(textValue, translated); validationErr != nil {
  log.Printf("docs-i18n: frontmatter fallback %s reason=%v", segmentID, validationErr)
  translated = textValue
  shouldCache = false
 }
 entry := TMEntry{
  CacheKey:   ck,
  SegmentID:  segmentID,
  SourcePath: segmentID,
  TextHash:   textHash,
  Text:       textValue,
  Translated: translated,
  Provider:   docsPiProvider(),
  Model:      docsPiModel(),
  SrcLang:    srcLang,
  TgtLang:    tgtLang,
  UpdatedAt:  time.Now().UTC().Format(time.RFC3339),
 }
 if shouldCache {
  tm.Put(entry)
 }
 return translated, nil
}

func validateFrontmatterScalarTranslation(source, translated string) error {
 trimmed := strings.TrimSpace(translated)
 if trimmed == "" {
  return fmt.Errorf("empty translation")
 }
 lower := strings.ToLower(trimmed)
 if strings.Contains(lower, "<frontmatter>") || strings.Contains(lower, "</frontmatter>") || strings.Contains(lower, "<body>") || strings.Contains(lower, "</body>") {
  return fmt.Errorf("tagged document wrapper detected")
 }
 if strings.Contains(trimmed, "[[[FM_") {
  return fmt.Errorf("frontmatter marker leaked into scalar translation")
 }
 if strings.Contains(trimmed, "\n---\n") || strings.HasPrefix(trimmed, "---\n") {
  return fmt.Errorf("yaml document boundary detected")
 }
 if !strings.Contains(source, "\n") && strings.Count(trimmed, "\n") >= 3 {
  return fmt.Errorf("unexpected multiline expansion")
 }
 sourceLen := len(strings.TrimSpace(source))
 translatedLen := len(trimmed)
 if sourceLen > 0 {
  limit := sourceLen*8 + 256
  if limit < 512 {
   limit = 512
  }
  if translatedLen > limit {
   return fmt.Errorf("unexpected size expansion source=%d translated=%d", sourceLen, translatedLen)
  }
 }
 for _, key := range []string{"title:", "summary:", "read_when:"} {
  if strings.Contains(lower, "\n"+key) || strings.HasPrefix(lower, key) {
   return fmt.Errorf("frontmatter key leaked into scalar translation")
  }
 }
 return nil
}

[Dauer der Verarbeitung: 0.22 Sekunden, vorverarbeitet 2026-04-27]

                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge