Translations & certificates

- Translation system, possibility to define different language using
  meta.language setting
- Only en-EN and fi-FI implemented
- Added certificates section, for miscellaneous certs and licences
This commit is contained in:
Jarno Rankinen 2024-02-10 14:54:20 +02:00
parent 6c16eb5a7c
commit a286b61c58
6 changed files with 108 additions and 30 deletions

13
main.go
View File

@ -17,8 +17,10 @@ import (
var static embed.FS var static embed.FS
var templates map[string]*template.Template var templates map[string]*template.Template
var configFile string var configFile string
var strs map[string]map[string]string
func main() { func main() {
loadStrings()
cfgFile := flag.String("config", "./data/resume.yaml", "Path to the configuration YAML") cfgFile := flag.String("config", "./data/resume.yaml", "Path to the configuration YAML")
flag.Parse() flag.Parse()
@ -53,7 +55,9 @@ func home(w http.ResponseWriter, r *http.Request) {
"templates/metatag.html", "templates/metatag.html",
"templates/githubCorner.html", "templates/githubCorner.html",
} }
tmpl, err := template.ParseFS(static, templateFiles...) var err error
tmpl := template.New("index").Funcs(templateFunctions())
tmpl, err = tmpl.ParseFS(static, templateFiles...)
if err != nil { if err != nil {
slog.Error(err.Error()) slog.Error(err.Error())
http.Error(w, "Server error", http.StatusInternalServerError) http.Error(w, "Server error", http.StatusInternalServerError)
@ -69,7 +73,6 @@ func home(w http.ResponseWriter, r *http.Request) {
data.Theme = urlSlice[len(urlSlice)-1] data.Theme = urlSlice[len(urlSlice)-1]
} }
data.Year = time.Now().Format("2006") data.Year = time.Now().Format("2006")
tmpl.Funcs(templateFunctions())
err = tmpl.Execute(w, *data) err = tmpl.Execute(w, *data)
if err != nil { if err != nil {
slog.Error(err.Error()) slog.Error(err.Error())
@ -82,5 +85,11 @@ func templateFunctions() template.FuncMap {
"html": func(raw string) template.HTML { "html": func(raw string) template.HTML {
return template.HTML(raw) return template.HTML(raw)
}, },
"translate": func(label, lang string) string {
if strs[lang][label] == "" {
return label + " (no translation)"
}
return strs[lang][label]
},
} }
} }

View File

@ -13,19 +13,20 @@ type Resume struct {
} }
type Profile struct { type Profile struct {
Name string `yaml:"name"` Name string `yaml:"name"`
Title string `yaml:"title"` Title string `yaml:"title"`
City string `yaml:"city"` City string `yaml:"city"`
Phone string `yaml:"phone"` Phone string `yaml:"phone"`
Email string `yaml:"email"` Email string `yaml:"email"`
Socials Socials `yaml:"socials"` Socials Socials `yaml:"socials"`
Photo string `yaml:"photo"` Photo string `yaml:"photo"`
Summary string `yaml:"summary"` Summary string `yaml:"summary"`
Experience []Job `yaml:"experience"` Experience []Job `yaml:"experience"`
Education []Education `yaml:"education"` Education []Education `yaml:"education"`
Skills []Skill `yaml:"skills"` Skills []Skill `yaml:"skills"`
Projects any `yaml:"projects"` Projects any `yaml:"projects"`
Languages []Language `yaml:"languages"` Languages []Language `yaml:"languages"`
Certificates []Certificate `yaml:"certificates"`
} }
func (p *Profile) GetTagWidth(t string) string { func (p *Profile) GetTagWidth(t string) string {
@ -47,9 +48,9 @@ func (p *Profile) GetTagWidth(t string) string {
return fmt.Sprintf("%dch", l) return fmt.Sprintf("%dch", l)
} }
func (job *Job) html(raw string) template.HTML { //func (job *Job) html(raw string) template.HTML {
return template.HTML(raw) // return template.HTML(raw)
} //}
type Job struct { type Job struct {
Company string `yaml:"company"` Company string `yaml:"company"`
@ -92,8 +93,6 @@ func (language *Language) VisualLevel(level int) template.HTML {
return _visualLevel(level) return _visualLevel(level)
} }
type skills []Skill
type Social struct { type Social struct {
Media string `yaml:"media"` Media string `yaml:"media"`
UserId string `yaml:"userId"` UserId string `yaml:"userId"`
@ -116,3 +115,7 @@ type Language struct {
Name string `yaml:"name"` Name string `yaml:"name"`
Level int `yaml:"level"` Level int `yaml:"level"`
} }
type Certificate struct {
Name string `yaml:"name"`
}

View File

@ -11,3 +11,6 @@
.subtitle { .subtitle {
color: var(--subtitle-color); } color: var(--subtitle-color); }
.tag:not(body).is-primary {
color: #2f2f2f; }

View File

@ -14,4 +14,8 @@
.subtitle { .subtitle {
color: var(--subtitle-color); color: var(--subtitle-color);
}
.tag:not(body).is-primary {
color: #2f2f2f;
} }

34
strings.go Normal file
View File

@ -0,0 +1,34 @@
package main
func loadStrings() {
strs = make(map[string]map[string]string)
strs["en-EN"] = make(map[string]string)
strs["en-EN"] = map[string]string{
"summary": "SUMMARY",
"experience": "EXPERIENCE",
"education": "EDUCATION",
"projects": "PROJECTS",
"skills": "SKILLS",
"languages": "LANGUAGES",
"certificates": "CERTIFICATES, LICENSES ETC",
"see_dark": "See Dark Theme",
"see_light": "See Light Theme",
"all_rights_reserved": "All Rights Reserved.",
"powered_by": "Powered by <a href=\"https://github.com/0ranki/go-resume\">go-resume</a>",
}
strs["fi-FI"] = make(map[string]string)
strs["fi-FI"] = map[string]string{
"summary": "YLEISTÄ",
"experience": "TYÖKOKEMUS",
"education": "KOULUTUS",
"projects": "PROJEKTIT",
"skills": "TAIDOT",
"languages": "KIELITAITO",
"certificates": "LUVAT, TODISTUKSET YM.",
"see_dark": "Tumma teema",
"see_light": "Vaalea teema",
"all_rights_reserved": "Kaikki oikeudet pidätetään.",
"powered_by": "Luotu käyttäen sovellusta <a href=\"https://github.com/0ranki/go-resume\">go-resume</a>",
}
}

View File

@ -1,3 +1,7 @@
{{ define "index" }}
{{ $lang := .Meta.Language }}
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
@ -71,7 +75,7 @@
<div class="column is-three-fifths"> <div class="column is-three-fifths">
<div class="summary"> <div class="summary">
<div class="title is-size-5 has-text-primary has-text-weight-bold"> <div class="title is-size-5 has-text-primary has-text-weight-bold">
SUMMARY {{ translate "summary" $lang }}
</div> </div>
<div class="wrapper">{{ .Profile.Summary }}</div> <div class="wrapper">{{ .Profile.Summary }}</div>
</div> </div>
@ -79,7 +83,7 @@
{{ with .Profile.Experience }} {{ with .Profile.Experience }}
<div class="experience"> <div class="experience">
<div class="title is-size-5 has-text-primary has-text-weight-bold"> <div class="title is-size-5 has-text-primary has-text-weight-bold">
EXPERIENCE {{ translate "experience" $lang }}
</div> </div>
<!--<% content.data.experiences.forEach(function(experience){ %>--> <!--<% content.data.experiences.forEach(function(experience){ %>-->
@ -113,7 +117,7 @@
{{ with .Profile.Education }} {{ with .Profile.Education }}
<div class="education"> <div class="education">
<div class="title is-size-5 has-text-primary has-text-weight-bold"> <div class="title is-size-5 has-text-primary has-text-weight-bold">
EDUCATION {{ translate "education" $lang }}
</div> </div>
{{ range . }} {{ range . }}
@ -141,9 +145,10 @@
{{ with .Profile.Projects }} {{ with .Profile.Projects }}
<div class="projects"> <div class="projects">
<div class="title is-size-5 has-text-primary has-text-weight-bold"> <div class="title is-size-5 has-text-primary has-text-weight-bold">
PROJECTS {{ translate "projects" $lang }}
</div> </div>
<!--TODO: projects-->
<% content.data.projects.forEach(function(proj){ %> <% content.data.projects.forEach(function(proj){ %>
<div class="item"> <div class="item">
<div class="is-size-5"> <div class="is-size-5">
@ -160,7 +165,7 @@
{{ with .Profile.Skills }} {{ with .Profile.Skills }}
<div class="skills"> <div class="skills">
<div class="title is-size-5 has-text-primary has-text-weight-bold"> <div class="title is-size-5 has-text-primary has-text-weight-bold">
SKILLS {{ translate "skills" $lang }}
</div> </div>
<div class="wrapper"> <div class="wrapper">
{{ range . }} {{ range . }}
@ -182,7 +187,7 @@
{{ with .Profile.Languages }} {{ with .Profile.Languages }}
<div class="languages"> <div class="languages">
<div class="title is-size-5 has-text-primary has-text-weight-bold"> <div class="title is-size-5 has-text-primary has-text-weight-bold">
LANGUAGES {{ translate "languages" $lang }}
</div> </div>
<div class="wrapper"> <div class="wrapper">
{{ range . }} {{ range . }}
@ -200,6 +205,25 @@
</div> </div>
</div> </div>
{{ end }} {{ end }}
{{ with .Profile.Certificates }}
<div class="certificates">
<div class="title is-size-5 has-text-primary has-text-weight-bold">
{{ translate "certificates" $lang }}
</div>
{{ range . }}
<div class="item">
<div class="is-size-5">
<div class="tag is-size-6 is-primary text-dark" style="margin-bottom: 5px;">
{{ .Name }}
</div>
</div>
</div>
{{ end }}
</div>
{{ end }}
</div> </div>
{{ end }} {{ end }}
</div> </div>
@ -209,14 +233,14 @@
<footer class="footer"> <footer class="footer">
<div class="content has-text-centered"> <div class="content has-text-centered">
{{ if eq .Theme "light" }} {{ if eq .Theme "light" }}
<a href="/dark">See Dark Theme</a> <a href="/dark">{{ translate "see_dark" $lang }}</a>
{{ else }} {{ else }}
<a href="/light">See Light Theme</a> <a href="/light">{{ translate "see_light" $lang }}</a>
{{ end }} {{ end }}
<br /> <br />
Copyright © {{ .Year }} {{ .Profile.Name }}. All rights Reserved. Copyright © {{ .Year }} {{ .Profile.Name }}. {{ translate "all_rights_reserved" $lang }}
<br /> <br />
Powered by <a href="https://github.com/0ranki/go-resume">go-resume</a> {{ translate "powered_by" $lang | html }}
</div> </div>
</footer> </footer>
@ -225,3 +249,4 @@
</body> </body>
</html> </html>
{{ end }}