Compare commits

...

4 Commits
main ... i18n-2

Author SHA1 Message Date
Cadey Ratio 6feb95eb68 try 2 2018-12-01 18:19:32 -08:00
Cadey Ratio df7258c5c7 update translations 2018-12-01 18:00:57 -08:00
Cadey Ratio 10f880d674 templates: use translations 2018-12-01 18:00:47 -08:00
Cadey Ratio cc6692138b start translations 2018-12-01 17:46:25 -08:00
15 changed files with 294 additions and 28 deletions

View File

@ -7,6 +7,7 @@ import (
"net/http" "net/http"
"time" "time"
"github.com/Unknwon/i18n"
"github.com/Xe/ln" "github.com/Xe/ln"
) )
@ -21,7 +22,32 @@ func (s *Site) renderTemplatePage(templateFname string, data interface{}) http.H
s.tlock.RLock() s.tlock.RLock()
defer s.tlock.RUnlock() defer s.tlock.RUnlock()
var t *template.Template const fallbackLang = `en-US`
getTranslation := func(group, key string, vals ...interface{}) string {
var lang string
locale, err := GetPreferredLocale(r)
if err != nil {
ln.Error(r.Context(), err)
lang = fallbackLang
goto skip
}
if !i18n.IsExist(locale.Lang) {
lang = fallbackLang
goto skip
}
lang = locale.Lang
skip:
return i18n.Tr(lang, group+"."+key, vals...)
}
funcMap := template.FuncMap{
"trans": getTranslation,
}
var t = template.New(templateFname).Funcs(funcMap)
var err error var err error
if s.templates[templateFname] == nil { if s.templates[templateFname] == nil {

97
cmd/site/locale.go Normal file
View File

@ -0,0 +1,97 @@
package main
import (
"errors"
"net/http"
"strconv"
"strings"
)
// Locale is locale value from the Accept-Language header in request
type Locale struct {
Lang, Country string
Qual float64
}
// Name returns the locale value in 'lang' or 'lang_country' format
// eg: de_DE, en_US, gb
func (l *Locale) Name() string {
if len(l.Country) > 0 {
return l.Lang + "_" + l.Country
}
return l.Lang
}
// ParseLocale creates a Locale from a locale string
func ParseLocale(locale string) Locale {
locsplt := strings.Split(locale, "_")
resp := Locale{}
resp.Lang = locsplt[0]
if len(locsplt) > 1 {
resp.Country = locsplt[1]
}
return resp
}
const (
acceptLanguage = "Accept-Language"
)
func supportedLocales(alstr string) []Locale {
locales := make([]Locale, 0)
alstr = strings.Replace(alstr, " ", "", -1)
if alstr == "" {
return locales
}
al := strings.Split(alstr, ",")
for _, lstr := range al {
locales = append(locales, Locale{
Lang: parseLang(lstr),
Country: parseCountry(lstr),
Qual: parseQual(lstr),
})
}
return locales
}
// GetLocales returns supported locales for the given requet
func GetLocales(r *http.Request) []Locale {
return supportedLocales(r.Header.Get(acceptLanguage))
}
// GetPreferredLocale return preferred locale for the given reuqest
// returns error if there is no preferred locale
func GetPreferredLocale(r *http.Request) (*Locale, error) {
locales := GetLocales(r)
if len(locales) == 0 {
return &Locale{}, errors.New("No locale found")
}
return &locales[0], nil
}
func parseLang(val string) string {
locale := strings.Split(val, ";")[0]
lang := strings.Split(locale, "-")[0]
return lang
}
func parseCountry(val string) string {
locale := strings.Split(val, ";")[0]
spl := strings.Split(locale, "-")
if len(spl) > 1 {
return spl[1]
}
return ""
}
func parseQual(val string) float64 {
spl := strings.Split(val, ";")
if len(spl) > 1 {
qual, err := strconv.ParseFloat(strings.Split(spl[1], "=")[1], 64)
if err != nil {
return 1
}
return qual
}
return 1
}

View File

@ -12,6 +12,7 @@ import (
"sync" "sync"
"time" "time"
"github.com/Unknwon/i18n"
"github.com/Xe/jsonfeed" "github.com/Xe/jsonfeed"
"github.com/Xe/ln" "github.com/Xe/ln"
"github.com/gorilla/feeds" "github.com/gorilla/feeds"
@ -62,6 +63,10 @@ func Build() (*Site, error) {
Date string Date string
} }
i18n.SetMessage("en-US", "conf/locale/locale_en-US.ini")
i18n.SetMessage("toki", "conf/locale/locale_toki.ini")
i18n.SetDefaultLang("en-US")
s := &Site{ s := &Site{
rssFeed: &feeds.Feed{ rssFeed: &feeds.Feed{
Title: "Christine Dodrill's Blog", Title: "Christine Dodrill's Blog",

View File

@ -0,0 +1,40 @@
[blog]
blogroll = Other Blogs I Find Interesting
description = My blog posts and rants about various technology things.
disclaimer = Content posted on %s, opinions and preferences of the author may have changed since then.
index_title = Blogposts
posted_on = Posted on %s
read_this = Read Post
title = Christine Dodrill\'s Blog
comments = Selected Commentary on These Blogposts
[contact]
donations = To send me donations, my bitcoin address is:
email = Email
header = Contact Information
other_info = Other Information
social_media = Social Media
[error]
post_not_found = no such post found: %s
title = Error
[header]
blog = Blog
contact = Contact
name = Christine Dodrill
resume = Resume
[index]
contact_me = Contact Me
highlighted_projects = Highlighted Projects
skills = Skills
title = Web and Backend Services Devops Specialist
[meta]
copyright = Copyright %s Christine Dodrill. Any and all opinions listed here are my own, not my employer\'s.
rss_copyright = This work is copyright Christine Dodrill. My viewpoints are my own and not the view of any employer past, current or future.
[resume]
plaintext = Plain-text version of this resume here

View File

@ -0,0 +1,41 @@
[blog]
blogroll =
description =
disclaimer =
index_title =
posted_on =
read_this =
title =
comments =
[contact]
donations =
email =
header =
irc_comment =
other_info =
social_media =
[error]
post_not_found =
title =
[header]
blog =
contact =
name =
resume =
[index]
contact_me =
highlighted_projects =
skills =
title =
[meta]
copyright =
rss_copyright =
[resume]
plaintext =

View File

@ -0,0 +1,40 @@
[blog]
blogroll = lipu sona pi jan ante
description = lipu ni li jan Wisi Totiwi pi lipu sona. lipu sona ni li ilo pona li ilo sona.
disclaimer = tenpo %s la lipu ni li pali. tenpo ni la jan Wisi Totiwi li ken nasin sona ante.
index_title = lipu sona
posted_on = tenpo pi %s
read_this = lukin e ni
title = jan Wisi Totiwi pi lipu sona
comments = tenpo pini la jan ante li toki e ni
[contact]
donations = ken la sina pana mani e mi. sina wile kepeken lipu:
email = ilo toki
header = lipu toki e mi
other_info = lipu ante
social_media = kalama ilo toki
[error]
post_not_found = lipu %s li pona ala. ona li lukin ala.
title = pakala
[header]
blog = lipu sona
contact = lipu toki
name = jan Wisi Totiwi
resume = lipu pali mi
[index]
contact_me = toki e mi
highlighted_projects = pali musi e mi
skills = kepeken pali e mi
title = jan pali e ilo suli
[meta]
copyright = lipu ni li pali e jan Wisi Totiwi pi suli %s. sina pali ala e ni. tenpo ale la nasin sona mi li nasin sona ala pi kulupu lawa mi.
rss_copyright = lipu ni li pali e jan Wisi Totiwi. sina pali ala e ni. tenpo ale la nasin sona mi li nasin sona ala pi kulupu lawa mi.
[resume]
plaintext = sina wile lipu pona la sina lukin e ni

2
go.mod
View File

@ -1,6 +1,7 @@
module github.com/Xe/site module github.com/Xe/site
require ( require (
github.com/Unknwon/i18n v0.0.0-20171114194641-b64d33658966 // indirect
github.com/Xe/gopreload v0.0.0-20170326043426-a00a8beb369c github.com/Xe/gopreload v0.0.0-20170326043426-a00a8beb369c
github.com/Xe/jsonfeed v0.0.0-20170520170432-e21591505612 github.com/Xe/jsonfeed v0.0.0-20170520170432-e21591505612
github.com/Xe/ln v0.0.0-20170921000907-466e05b2ef3e github.com/Xe/ln v0.0.0-20170921000907-466e05b2ef3e
@ -17,5 +18,6 @@ require (
github.com/stretchr/testify v1.2.2 // indirect github.com/stretchr/testify v1.2.2 // indirect
github.com/tj/front v0.0.0-20170212063142-739be213b0a1 github.com/tj/front v0.0.0-20170212063142-739be213b0a1
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect
gopkg.in/ini.v1 v1.39.0 // indirect
gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0 // indirect gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0 // indirect
) )

4
go.sum
View File

@ -1,3 +1,5 @@
github.com/Unknwon/i18n v0.0.0-20171114194641-b64d33658966 h1:Mp8GNJ/tdTZIEdLdZfykEJaL3mTyEYrSzYNcdoQKpJk=
github.com/Unknwon/i18n v0.0.0-20171114194641-b64d33658966/go.mod h1:SFtfq0zFPsENI7DpE87QM2hcYu5QQ0fRdCgP+P1Hrqo=
github.com/Xe/gopreload v0.0.0-20170326043426-a00a8beb369c h1:lqTJqaoonxgJMvvfl1ukr/3qCEGWC0nQxzPezbJrhHs= github.com/Xe/gopreload v0.0.0-20170326043426-a00a8beb369c h1:lqTJqaoonxgJMvvfl1ukr/3qCEGWC0nQxzPezbJrhHs=
github.com/Xe/gopreload v0.0.0-20170326043426-a00a8beb369c/go.mod h1:0aSWHJguPNHo6zlU7A4Ktua1A/VUr5Jdr1QZ2amOkAQ= github.com/Xe/gopreload v0.0.0-20170326043426-a00a8beb369c/go.mod h1:0aSWHJguPNHo6zlU7A4Ktua1A/VUr5Jdr1QZ2amOkAQ=
github.com/Xe/jsonfeed v0.0.0-20170520170432-e21591505612 h1:5cPld6YTMozzm3lK9VCnOErgoFbADM2hZc4KDu0YNKs= github.com/Xe/jsonfeed v0.0.0-20170520170432-e21591505612 h1:5cPld6YTMozzm3lK9VCnOErgoFbADM2hZc4KDu0YNKs=
@ -33,5 +35,7 @@ github.com/tj/front v0.0.0-20170212063142-739be213b0a1 h1:lA+aPRvltlx2fwv/BnxyYS
github.com/tj/front v0.0.0-20170212063142-739be213b0a1/go.mod h1:deJrtusCTptAW4EUn5vBLpl3dhNqPqUwEjWJz5UNxpQ= github.com/tj/front v0.0.0-20170212063142-739be213b0a1/go.mod h1:deJrtusCTptAW4EUn5vBLpl3dhNqPqUwEjWJz5UNxpQ=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/ini.v1 v1.39.0 h1:Jf2sFGT+sAd7i+4ftUN1Jz90uw8XNH8NXbbOY16taA8=
gopkg.in/ini.v1 v1.39.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0 h1:POO/ycCATvegFmVuPpQzZFJ+pGZeX22Ufu6fibxDVjU= gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0 h1:POO/ycCATvegFmVuPpQzZFJ+pGZeX22Ufu6fibxDVjU=
gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0/go.mod h1:WDnlLJ4WF5VGsH/HVa3CI79GS0ol3YnhVnKP89i0kNg= gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0/go.mod h1:WDnlLJ4WF5VGsH/HVa3CI79GS0ol3YnhVnKP89i0kNg=

View File

@ -56,11 +56,11 @@
{{ template "scripts" . }} {{ template "scripts" . }}
<div class="container"> <div class="container">
<header> <header>
<p><a href="/">Christine Dodrill</a> - <a href="/blog">Blog</a> - <a href="/contact">Contact</a> - <a href="/resume">Resume</a></p> <p><a href="/">{{ trans "header" "name" }}</a> - <a href="/blog">{{ trans "header" "blog" }}</a> - <a href="/contact">{{ trans "header" "contact" }}</a> - <a href="/resume">{{ trans "header" "resume" }}</a></p>
</header> </header>
{{ template "content" . }} {{ template "content" . }}
<footer> <footer>
<blockquote>Copyright 2018 Christine Dodrill. Any and all opinions listed here are my own and not representative of my employer.</blockquote> <blockquote>{{ trans "meta" "copyright" "2018" }}</blockquote>
</footer> </footer>
<script> <script>
if (navigator.serviceWorker.controller) { if (navigator.serviceWorker.controller) {

View File

@ -1,21 +1,21 @@
{{ define "title" }} {{ define "title" }}
<title>Blog - Christine Dodrill</title> <title>{{ trans "header" "blog" }} - {{ trans "header" "name" }}</title>
{{ end }} {{ end }}
{{ define "content" }} {{ define "content" }}
<h1>Blogposts</h1> <h1>{{ trans "blog" "index_title" }}</h1>
<p> <p>
<ul> <ul>
{{ range . }} {{ range . }}
<li>{{ .Date }} - <a href="{{ .Link }}">{{ .Title }}</a></li> <li>{{ trans "blog" "posted_on" .Date }} - <a href="{{ .Link }}">{{ .Title }}</a></li>
{{ end }} {{ end }}
</ul> </ul>
</p> </p>
<br /> <br />
<h2>Other Blogs I Find Interesting</h2> <h2>{{ trans "blog" "blogroll" }}</h2>
<ul> <ul>
<li><a href="https://write.as/excerpts/">Excerpts</a></li> <li><a href="https://write.as/excerpts/">Excerpts</a></li>
@ -25,6 +25,7 @@
<li><a href="https://shamanic.vision/">Shamanic Vision</a></li> <li><a href="https://shamanic.vision/">Shamanic Vision</a></li>
</ul> </ul>
<h2>{{ trans "blog" "comments" }}</h2>
<h2>Selected Commentary on These Blogposts</h2> <h2>Selected Commentary on These Blogposts</h2>
<h3><a href="/blog/experimental-rilkef-2018-11-30">I Put Words on this Webpage so You Have to Listen to Me Now</a></h3> <h3><a href="/blog/experimental-rilkef-2018-11-30">I Put Words on this Webpage so You Have to Listen to Me Now</a></h3>
@ -33,6 +34,8 @@
<blockquote> <blockquote>
Top tier satire. Won't be read by anyone who should read it, and will be ignored/laughed at by anyone who does/already agrees. Top tier satire. Won't be read by anyone who should read it, and will be ignored/laughed at by anyone who does/already agrees.
<br />
Literally preaching to the literal choir. Literally preaching to the literal choir.
</blockquote> </blockquote>

View File

@ -1,5 +1,5 @@
{{ define "title" }} {{ define "title" }}
<title>{{ .Title }} - Christine Dodrill</title> <title>{{ .Title }} - {{ trans "header" "name" }}</title>
<!-- Twitter --> <!-- Twitter -->
<meta name="twitter:card" content="summary" /> <meta name="twitter:card" content="summary" />
@ -10,11 +10,11 @@
<!-- Facebook --> <!-- Facebook -->
<meta property="og:type" content="website" /> <meta property="og:type" content="website" />
<meta property="og:title" content="{{ .Title }}" /> <meta property="og:title" content="{{ .Title }}" />
<meta property="og:site_name" content="Christine Dodrill's Blog" /> <meta property="og:site_name" content="{{ trans "blog" "title" }}" />
<!-- Description --> <!-- Description -->
<meta name="description" content="{{ .Title }} - Christine Dodrill's Blog" /> <meta name="description" content="{{ .Title }} - {{ trans "blog" "title" }}" />
<meta name="author" content="Christine Dodrill"> <meta name="author" content="{{ trans "header" "name" }}">
{{ end }} {{ end }}
{{ define "content" }} {{ define "content" }}

View File

@ -1,15 +1,13 @@
{{ define "title" }}<title>Contact - Christine Dodrill</title>{{ end }} {{ define "title" }}<title>{{ trans "header" "contact" }} - {{ trans "header" "name" }}</title>{{ end }}
{{ define "content" }} {{ define "content" }}
<h1>Contact Information</h1> <h1>{{ trans "contact" "header" }}</h1>
<div class="grid"> <div class="grid">
<div class="cell -6of12"> <div class="cell -6of12">
<h3>Email</h3> <h3>{{ trans "contact" "email" }}</h3>
<p>me@christine.website</p> <p>me@christine.website</p>
<p>My GPG fingerprint is <code>799F 9134 8118 1111</code>. If you get an email that appears to be from me and the signature does not match that fingerprint, it is not from me. You may download a copy of my public key <a href="/static/gpg.pub">here</a>.</p> <h3>{{ trans "contact" "social_media" }}</h3>
<h3>Social Media</h3>
<ul> <ul>
<li><a href="https://github.com/Xe">Github</a></li> <li><a href="https://github.com/Xe">Github</a></li>
<li><a href="https://twitter.com/theprincessxena">Twitter</a></li> <li><a href="https://twitter.com/theprincessxena">Twitter</a></li>
@ -20,8 +18,11 @@
</ul> </ul>
</div> </div>
<div class="cell -6of12"> <div class="cell -6of12">
<h3>Other Information</h3> <h3>{{ trans "contact" "other_info" }}</h3>
<p>To send me donations, my bitcoin address is <code>1Gi2ZF2C9CU9QooH8bQMB2GJ2iL6shVnVe</code>.</p> <p>{{ trans "contact" "donations" }} <code>1Gi2ZF2C9CU9QooH8bQMB2GJ2iL6shVnVe</code>.</p>
<h4>IRC</h4>
<p>{{ trans "contact" "irc_comment" }}</p>
<h4>Telegram</h4> <h4>Telegram</h4>
<p><a href="https://t.me/miamorecadenza">@miamorecadenza</a></p> <p><a href="https://t.me/miamorecadenza">@miamorecadenza</a></p>

View File

@ -1,5 +1,5 @@
{{ define "title" }} {{ define "title" }}
<title>Error - Christine Dodrill</title> <title>{{ trans "error" "title" }} - {{ trans "header" "name" }}</title>
{{ end }} {{ end }}
{{ define "content" }} {{ define "content" }}

View File

@ -1,29 +1,36 @@
{{ define "title" }}<title>Christine Dodrill</title>{{ end }} {{ define "title" }}<title>{{ trans "header" "name" }}</title>{{ end }}
{{ define "content" }} {{ define "content" }}
<div class="grid"> <div class="grid">
<div class="cell -3of12 content"> <div class="cell -3of12 content">
<img src="/static/img/avatar.png"> <img src="/static/img/avatar.png">
<br /> <br />
<a href="/contact" class="justify-content-center">Contact Me</a> <a href="/contact" class="justify-content-center">{{ trans "index" "contact_me" }}</a>
</div> </div>
<div class="cell -9of12 content"> <div class="cell -9of12 content">
<h1>Christine Dodrill</h1> <h1>{{ trans "header" "name" }}</h1>
<h4>Web and Backend Services Devops Specialist</h4> <h4>{{ trans "index" "title" }}</h4>
<h5>Skills</h5> <h5>{{ trans "index" "skills" }}</h5>
<ul> <ul>
<li>Go, Lua, Nim, Haskell, C, Python (3.x) and other languages</li> <li>Go, Lua, Nim, Haskell, C, Python (3.x) and other languages</li>
<li>Docker (deployment, development & more)</li> <li>Docker (deployment, development & more)</li>
<li>Mashups of data</li> <li>Mashups of data</li>
<li>Package maintainer for Alpine Linux</li> <li>Package maintainer for Alpine Linux</li>
<li>Speaks English, toki pona, and la .lojban.</li>
</ul> </ul>
<h5>Highlighted Projects</h5> <h5>{{ trans "index" "highlighted_projects" }}</h5>
<ul> <ul>
<li><a href="https://github.com/Xe/PonyAPI">PonyAPI</a> - My Little Pony: Friendship is Magic Episode information API</li> <li><a href="https://github.com/Xe/PonyAPI">PonyAPI</a> - My Little Pony: Friendship is Magic Episode information API</li>
<li><a href="https://github.com/PonyvilleFM/aura">Aura</a> - PonyvilleFM live DJ recording bot</li> <li><a href="https://github.com/PonyvilleFM/aura">Aura</a> - PonyvilleFM live DJ recording bot</li>
<li><a href="https://github.com/Elemental-IRCd/elemental-ircd">Elemental-IRCd</a> - IRC Server Software</li> <li><a href="https://github.com/Elemental-IRCd/elemental-ircd">Elemental-IRCd</a> - IRC Server Software</li>
<li><a href="https://github.com/Xe/site">This website</a> - The backend and templates for this website</li> <li><a href="https://github.com/Xe/site">This website</a> - The backend and templates for this website</li>
<li><a href="https://github.com/Xe/olin">Olin</a> - WebAssembly on the server</li>
<li><a href="https://github.com/Xe/aports">aports</a> - Alpine Linux ports</li>
<li><a href="https://github.com/Xe/when-then-zen">when-then-zen</a> - Meditation instructions in Gherkin</li>
<li><a href="https://github.com/Xe/creators-code">Creator's Code</a> - Minimal code of conduct for communities</li>
<li><a href="https://github.com/Xe/printerfacts">printerfacts</a> - Informative facts about printers</li>
<li><a href="https://github.com/Xe/x">x</a> - Experiments and toys</li>
</ul> </ul>
</div> </div>
</div> </div>

View File

@ -1,9 +1,9 @@
{{ define "title" }}<title>Resume - Christine Dodrill</title>{{ end }} {{ define "title" }}<title>{{ trans "header" "resume" }} - {{ trans "header" "name" }}</title>{{ end }}
{{ define "content" }} {{ define "content" }}
{{ . }} {{ . }}
<hr /> <hr />
<a href="/static/resume/resume.md">Plain-text version of this resume here</a> <a href="/static/resume/resume.md">{{ trans "resume" "plaintext" }}</a>
{{ end }} {{ end }}