7b60fdcf9c
**Main Changes:** 1. **Package Restructuring** - Separated mixed concerns into focused packages: - Created `internal/models/cv/` for CV domain logic (CV, Personal, Experience, etc.) - Created `internal/models/ui/` for UI presentation logic (InfoModal, ShortcutsModal, etc.) - Removed monolithic `internal/models/cv.go` (300+ lines → organized packages) 2. **Testing** - Added comprehensive unit tests: - `internal/models/cv/loader_test.go` - CV data loading and validation - `internal/models/ui/loader_test.go` - UI translations loading - All tests passing ✅ 3. **Documentation** - Added Go learning knowledge base: - `_go-learning/architecture/server-design.md` - Goroutines, graceful shutdown explained - `_go-learning/refactorings/001-cv-model-separation.md` - This refactoring documented - Public documentation showcasing Go expertise (README.md kept private) 4. **Handler Updates** - Updated imports to use new package structure: - `internal/handlers/cv.go` - Uses `cvmodel` and `uimodel` aliases **Benefits:** - ✅ Clear separation of concerns (domain vs presentation) - ✅ Better testability (isolated package testing) - ✅ Improved maintainability (smaller, focused files) - ✅ Scalability (each domain can evolve independently) - ✅ Follows Go best practices (small, cohesive packages) **Other Updates:** - Updated middleware security checks - Template improvements - Organized completed prompts **Testing:** - All Go unit tests pass (cv, ui, handlers) - Server verified with curl tests (English, Spanish, Health endpoints) - Frontend functionality unchanged (refactoring is transparent to UI)
57 lines
1.4 KiB
Go
57 lines
1.4 KiB
Go
package ui
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"os"
|
|
)
|
|
|
|
// LoadUI loads UI translations from a JSON file for the specified language
|
|
func LoadUI(lang string) (*UI, error) {
|
|
if lang != "en" && lang != "es" {
|
|
return nil, fmt.Errorf("unsupported language: %s", lang)
|
|
}
|
|
|
|
filename := fmt.Sprintf("data/ui-%s.json", lang)
|
|
filepath, err := findDataFile(filename)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
data, err := os.ReadFile(filepath)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("error reading file %s: %w", filename, err)
|
|
}
|
|
|
|
var uiData UI
|
|
if err := json.Unmarshal(data, &uiData); err != nil {
|
|
return nil, fmt.Errorf("error parsing JSON: %w", err)
|
|
}
|
|
|
|
return &uiData, nil
|
|
}
|
|
|
|
// findDataFile locates a data file by searching up the directory tree
|
|
func findDataFile(filename string) (string, error) {
|
|
// Try current directory first
|
|
if _, err := os.Stat(filename); err == nil {
|
|
return filename, nil
|
|
}
|
|
|
|
// Try parent directories (for tests running from subdirectories)
|
|
paths := []string{
|
|
filename, // Current dir
|
|
"../" + filename, // One level up
|
|
"../../" + filename, // Two levels up (for tests in internal/handlers)
|
|
"../../../" + filename, // Three levels up
|
|
}
|
|
|
|
for _, path := range paths {
|
|
if _, err := os.Stat(path); err == nil {
|
|
return path, nil
|
|
}
|
|
}
|
|
|
|
return "", fmt.Errorf("file not found: %s (searched: current dir, ../, ../../, ../../../)", filename)
|
|
}
|