1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
|
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
// Normalize \r\n to \n before splitting so both Windows and Unix line
// endings are handled uniformly by strings.Split.
normalized := strings.ReplaceAll(string(content), "\r\n", "\n")
for _, line := range strings.Split(normalized, "\n") {
if line = strings.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,
}
}
|