From 13c59c36997c2746944240fe2cabdaf754d5b4d9 Mon Sep 17 00:00:00 2001 From: juanatsap Date: Sun, 9 Nov 2025 21:03:39 +0000 Subject: [PATCH] refactor: separate UI translations from CV data - Created separate ui-en.json and ui-es.json files for UI strings - Removed 'ui' section from cv-en.json and cv-es.json - Added LoadUI() function to load UI translations separately - Updated handlers to load UI data independently from CV data - Updated template to use .UI instead of .CV.UI This separation follows proper concerns: - CV JSON files contain only professional CV content - UI JSON files contain only application interface strings - Each can be updated independently without affecting the other --- data/cv-en.json | 13 ------------ data/cv-es.json | 13 ------------ data/ui-en.json | 13 ++++++++++++ data/ui-es.json | 13 ++++++++++++ internal/handlers/cv.go | 16 +++++++++++++++ internal/models/cv.go | 26 +++++++++++++++++++++++- static/images/courses/linkedin-blue.png | Bin 0 -> 8902 bytes static/images/courses/linkedin.png | Bin 8902 -> 1180 bytes templates/index.html | 14 ++++++------- 9 files changed, 74 insertions(+), 34 deletions(-) create mode 100644 data/ui-en.json create mode 100644 data/ui-es.json create mode 100644 static/images/courses/linkedin-blue.png 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 0000000000000000000000000000000000000000..09aa8a0618e282a52f7638ebd38c8033a5a3b0d8 GIT binary patch literal 8902 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 UXkvA2B>(^b07*qoM6N<$f^g=`kpKVy literal 0 HcmV?d00001 diff --git a/static/images/courses/linkedin.png b/static/images/courses/linkedin.png index 09aa8a0618e282a52f7638ebd38c8033a5a3b0d8..bcad5ab171d9a7c8a2f8b349ee3d1a6d34d09406 100644 GIT binary patch literal 1180 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD1|%QND7OGoY)RhkE)4%caKYZ?lNlIT0zF+E zLn`LHz2%z`6Do1+<8#|`Cp91LTS04Ac!Y1Ab#BQcC$6Yik^NoPi<4S899dT;be|E4 zaanWDCwiC0v?jqAjjg&}D?*RFIOMCtq4xclVd>=rM=$fdq)el8w(Gk!L`;j{T|cw( z`M&+R=fpp&m%qCs>A<1bBH#ojp0FOBS9n6dQno5;a@`CEWrn;Tul1)(%m{4JKh$_y zeM9;0sXqR%RzxuFIrb)xO_r@-apH^hNA{@SvHw)~Y4OwME}IR4dyXymo>2FZ@j;r} zFAvkd(IrQQQI5%)5GbG)bcF^v7%7(Vd zXUZL0cwcT`c>B`&hs#cEU-+`%4}XoNpz498Uv3w$W$(~*V)$kERnO=C(zwHc&&(4q zrC-W(I-s6;yzZY&nnoBnj>1+6pF7d(IeubHEop`hvObkoEbJJ$7j zmtq4VR@blv@P1U%5jJScdYZFo@l)p~w*z9eE&V9Kp`381aq9cs*OQ*UD-b-uDp1E}uy*0HfV)=nkKSAtcB1NF_PyEmIRW#& z%gj2+&5*~q;nwomr3}{^4VfNrvhtdw)e7ug%dWS7_SN%wzrI-fk}624@-S@*pZZDc zfJMXp_&*UVn2s4<)tmeM)jtc1zscWfSTg=Z1irn*b6`EQM(Tz~ZfZVNy$_;gX6!aS z>vWF&!>fajxgJI`%-$R~oAdjsrg;YsCb(ZRox}IwYO|r*KL&@5?YGy2&)WZG*1u#= zHEZbw7v|hPd1Nxf9=n|Ilw+D#(%#OFM?|SQ3c+^UKw>@~1fnnYD4bQ9A zFSy@dT>hkpL0e+S`RpI(-DLF{s~S4*9hmrXp+>T*Lw-)k+e;Bs8if{=A6v{biD7TC z_^f>&5691A+Tu_V+1$Rh-SpOBDPB3Y%W(~Lua35HZMkfs#_#WZTjADn^SRc27cYL0 zug}h0(0X}!|Ekur`b~ur2OP?xKbJA&mr6gZYS@-kwIx`){%+}&7a1!W7q>pUvnTDZ z<)*F!H`D@aTT8<-1C`4roixJMiPg?WYX7dtcu9xMT8{OZmqcQof$O z9(9>vI9yRhEc%M?z=6IPQojF6+Pj#O3rSQmkOQqA97uZ%Pe!O!iVOD(e z@kevFJVP() b|HooBQ`Wq7mb4PExMA>g^>bP0l+XkKP822T literal 8902 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 UXkvA2B>(^b07*qoM6N<$f^g=`kpKVy 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}}