package batch import ( "fmt" "os" "strings" "codeberg.org/snonux/totalrecall/internal" ) // WordEntry represents a word with optional translation type WordEntry struct { Bulgarian string Translation string // NeedsTranslation indicates if translation from English to Bulgarian is needed NeedsTranslation bool // CardType indicates whether this is en-bg or bg-bg card CardType internal.CardType } // ReadBatchFile reads words from a file and returns WordEntry slice // Supports formats: // - Bulgarian word only: "ябълка" (will be translated to English) // - With translation: "ябълка = apple" (both provided, no translation needed) // - English only: "= apple" (will be translated to Bulgarian) // - Bulgarian-Bulgarian: "word1 == definition" (bg-bg card, double equals) func ReadBatchFile(filename string) ([]WordEntry, error) { content, err := os.ReadFile(filename) if err != nil { return nil, fmt.Errorf("failed to read batch file: %w", err) } var entries []WordEntry lines := string(content) for _, line := range splitLines(lines) { if line = trimSpace(line); line != "" { entry := parseBatchLine(line) if entry != nil { entries = append(entries, *entry) } } } return entries, nil } // parseBatchLine parses a single batch file line and returns the appropriate WordEntry func parseBatchLine(line string) *WordEntry { // Check for Bulgarian-Bulgarian format first (double equals ==) if strings.Contains(line, "==") { parts := strings.SplitN(line, "==", 2) if len(parts) == 2 { bulgarian1 := strings.TrimSpace(parts[0]) bulgarian2 := strings.TrimSpace(parts[1]) if bulgarian1 != "" && bulgarian2 != "" { return &WordEntry{ Bulgarian: bulgarian1, Translation: bulgarian2, NeedsTranslation: false, CardType: internal.CardTypeBgBg, } } } return nil } // Check for English-Bulgarian format (single equals =) if strings.Contains(line, "=") { parts := strings.SplitN(line, "=", 2) if len(parts) == 2 { bulgarian := strings.TrimSpace(parts[0]) english := strings.TrimSpace(parts[1]) if bulgarian == "" && english != "" { // Format: "= ENGLISH" - need to translate English to Bulgarian return &WordEntry{ Bulgarian: "", Translation: english, NeedsTranslation: true, CardType: internal.CardTypeEnBg, } } else if bulgarian != "" && english != "" { // Format: "BULGARIAN = ENGLISH" - both provided return &WordEntry{ Bulgarian: bulgarian, Translation: english, NeedsTranslation: false, CardType: internal.CardTypeEnBg, } } } return nil } // Just a Bulgarian word - needs translation to English return &WordEntry{ Bulgarian: line, Translation: "", NeedsTranslation: false, CardType: internal.CardTypeEnBg, } } // splitLines splits a string by newlines func splitLines(s string) []string { var lines []string current := "" for _, r := range s { if r == '\n' { lines = append(lines, current) current = "" } else if r != '\r' { current += string(r) } } if current != "" { lines = append(lines, current) } return lines } // trimSpace trims whitespace from string func trimSpace(s string) string { start := 0 end := len(s) // Trim from start for start < end && isSpace(rune(s[start])) { start++ } // Trim from end for end > start && isSpace(rune(s[end-1])) { end-- } return s[start:end] } func isSpace(r rune) bool { return r == ' ' || r == '\t' || r == '\n' || r == '\r' }