diff --git a/data/cv-en.json b/data/cv-en.json index 7bb8336..8123143 100644 --- a/data/cv-en.json +++ b/data/cv-en.json @@ -911,19 +911,6 @@ "other": { "driverLicense": "Type B" }, - "ui": { - "infoModal": { - "title": "About this CV", - "description": "This interactive CV was built by myself with Go + HTMX, showcasing modern hypermedia architecture without heavy JavaScript frameworks.", - "techStack": { - "goHono": "Go + Hono", - "htmx": "HTMX", - "html5": "Semantic HTML5", - "css3": "Pure CSS3" - }, - "viewSource": "View Source Code" - } - }, "meta": { "version": "2025-11-09", "lastUpdated": "2025-11-08", diff --git a/data/cv-es.json b/data/cv-es.json index 3f0cb62..a10e4c2 100644 --- a/data/cv-es.json +++ b/data/cv-es.json @@ -916,19 +916,6 @@ "other": { "driverLicense": "Tipo B" }, - "ui": { - "infoModal": { - "title": "Acerca de este CV", - "description": "Este CV interactivo fue construido por mí mismo con Go + HTMX, demostrando arquitectura moderna de hipermedia sin frameworks pesados de JavaScript.", - "techStack": { - "goHono": "Go + Hono", - "htmx": "HTMX", - "html5": "HTML5 Semántico", - "css3": "CSS3 Puro" - }, - "viewSource": "Ver código fuente" - } - }, "meta": { "version": "2025-11-09", "lastUpdated": "2025-11-08", diff --git a/data/ui-en.json b/data/ui-en.json new file mode 100644 index 0000000..70ab5f1 --- /dev/null +++ b/data/ui-en.json @@ -0,0 +1,13 @@ +{ + "infoModal": { + "title": "About this CV", + "description": "This interactive CV was built by myself with Go + HTMX, showcasing modern hypermedia architecture without heavy JavaScript frameworks.", + "techStack": { + "goHono": "Go + Hono", + "htmx": "HTMX", + "html5": "Semantic HTML5", + "css3": "Pure CSS3" + }, + "viewSource": "View Source Code" + } +} diff --git a/data/ui-es.json b/data/ui-es.json new file mode 100644 index 0000000..c07708a --- /dev/null +++ b/data/ui-es.json @@ -0,0 +1,13 @@ +{ + "infoModal": { + "title": "Acerca de este CV", + "description": "Este CV interactivo fue construido por mí mismo con Go + HTMX, demostrando arquitectura moderna de hipermedia sin frameworks pesados de JavaScript.", + "techStack": { + "goHono": "Go + Hono", + "htmx": "HTMX", + "html5": "HTML5 Semántico", + "css3": "CSS3 Puro" + }, + "viewSource": "Ver código fuente" + } +} diff --git a/internal/handlers/cv.go b/internal/handlers/cv.go index f2591c4..1abc793 100644 --- a/internal/handlers/cv.go +++ b/internal/handlers/cv.go @@ -51,6 +51,13 @@ func (h *CVHandler) Home(w http.ResponseWriter, r *http.Request) { return } + // Load UI translations + ui, err := models.LoadUI(lang) + if err != nil { + HandleError(w, r, DataLoadError(err, "UI")) + return + } + // Calculate duration for each experience for i := range cv.Experience { cv.Experience[i].Duration = calculateDuration( @@ -78,6 +85,7 @@ func (h *CVHandler) Home(w http.ResponseWriter, r *http.Request) { // Prepare template data data := map[string]interface{}{ "CV": cv, + "UI": ui, "Lang": lang, "SkillsLeft": skillsLeft, "SkillsRight": skillsRight, @@ -120,6 +128,13 @@ func (h *CVHandler) CVContent(w http.ResponseWriter, r *http.Request) { return } + // Load UI translations + ui, err := models.LoadUI(lang) + if err != nil { + HandleError(w, r, DataLoadError(err, "UI")) + return + } + // Calculate duration for each experience for i := range cv.Experience { cv.Experience[i].Duration = calculateDuration( @@ -147,6 +162,7 @@ func (h *CVHandler) CVContent(w http.ResponseWriter, r *http.Request) { // Prepare template data data := map[string]interface{}{ "CV": cv, + "UI": ui, "Lang": lang, "SkillsLeft": skillsLeft, "SkillsRight": skillsRight, diff --git a/internal/models/cv.go b/internal/models/cv.go index 0d7c900..0e4cdc2 100644 --- a/internal/models/cv.go +++ b/internal/models/cv.go @@ -22,7 +22,6 @@ type CV struct { Courses []Course `json:"courses"` References []Reference `json:"references"` Other Other `json:"other"` - UI UI `json:"ui"` Meta Meta `json:"meta"` } @@ -212,3 +211,28 @@ func LoadCV(lang string) (*CV, error) { return &cv, nil } + +// LoadUI loads UI translations from a JSON file for the specified language +func LoadUI(lang string) (*UI, error) { + // Validate language + if lang != "en" && lang != "es" { + return nil, fmt.Errorf("unsupported language: %s", lang) + } + + // Determine which JSON file to load + filename := fmt.Sprintf("data/ui-%s.json", lang) + + // Read the JSON file + data, err := os.ReadFile(filename) + if err != nil { + return nil, fmt.Errorf("error reading file %s: %w", filename, err) + } + + // Parse JSON + var ui UI + if err := json.Unmarshal(data, &ui); err != nil { + return nil, fmt.Errorf("error parsing JSON: %w", err) + } + + return &ui, nil +} diff --git a/static/images/courses/linkedin-blue.png b/static/images/courses/linkedin-blue.png new file mode 100644 index 0000000..09aa8a0 Binary files /dev/null and b/static/images/courses/linkedin-blue.png differ diff --git a/static/images/courses/linkedin.png b/static/images/courses/linkedin.png index 09aa8a0..bcad5ab 100644 Binary files a/static/images/courses/linkedin.png and b/static/images/courses/linkedin.png differ diff --git a/templates/index.html b/templates/index.html index 6129b26..3430ec1 100644 --- a/templates/index.html +++ b/templates/index.html @@ -297,37 +297,37 @@
-

{{.CV.UI.InfoModal.Title}}

+

{{.UI.InfoModal.Title}}

CV {{.CurrentYear}} - {JAMR}

- {{.CV.UI.InfoModal.Description}} + {{.UI.InfoModal.Description}}

- {{.CV.UI.InfoModal.TechStack.GoHono}} + {{.UI.InfoModal.TechStack.GoHono}}
- {{.CV.UI.InfoModal.TechStack.HTMX}} + {{.UI.InfoModal.TechStack.HTMX}}
- {{.CV.UI.InfoModal.TechStack.HTML5}} + {{.UI.InfoModal.TechStack.HTML5}}
- {{.CV.UI.InfoModal.TechStack.CSS3}} + {{.UI.InfoModal.TechStack.CSS3}}
- {{.CV.UI.InfoModal.ViewSource}} + {{.UI.InfoModal.ViewSource}}