Compare commits
4 Commits
Author | SHA1 | Date |
---|---|---|
Cadey Ratio | 6feb95eb68 | |
Cadey Ratio | df7258c5c7 | |
Cadey Ratio | 10f880d674 | |
Cadey Ratio | cc6692138b |
|
@ -7,6 +7,7 @@ import (
|
|||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/Unknwon/i18n"
|
||||
"github.com/Xe/ln"
|
||||
)
|
||||
|
||||
|
@ -21,7 +22,32 @@ func (s *Site) renderTemplatePage(templateFname string, data interface{}) http.H
|
|||
s.tlock.RLock()
|
||||
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
|
||||
|
||||
if s.templates[templateFname] == nil {
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -12,6 +12,7 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/Unknwon/i18n"
|
||||
"github.com/Xe/jsonfeed"
|
||||
"github.com/Xe/ln"
|
||||
"github.com/gorilla/feeds"
|
||||
|
@ -62,6 +63,10 @@ func Build() (*Site, error) {
|
|||
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{
|
||||
rssFeed: &feeds.Feed{
|
||||
Title: "Christine Dodrill's Blog",
|
||||
|
|
|
@ -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
|
||||
|
|
@ -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 =
|
||||
|
|
@ -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
2
go.mod
|
@ -1,6 +1,7 @@
|
|||
module github.com/Xe/site
|
||||
|
||||
require (
|
||||
github.com/Unknwon/i18n v0.0.0-20171114194641-b64d33658966 // indirect
|
||||
github.com/Xe/gopreload v0.0.0-20170326043426-a00a8beb369c
|
||||
github.com/Xe/jsonfeed v0.0.0-20170520170432-e21591505612
|
||||
github.com/Xe/ln v0.0.0-20170921000907-466e05b2ef3e
|
||||
|
@ -17,5 +18,6 @@ require (
|
|||
github.com/stretchr/testify v1.2.2 // indirect
|
||||
github.com/tj/front v0.0.0-20170212063142-739be213b0a1
|
||||
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
|
||||
)
|
||||
|
|
4
go.sum
4
go.sum
|
@ -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/go.mod h1:0aSWHJguPNHo6zlU7A4Ktua1A/VUr5Jdr1QZ2amOkAQ=
|
||||
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=
|
||||
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/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/go.mod h1:WDnlLJ4WF5VGsH/HVa3CI79GS0ol3YnhVnKP89i0kNg=
|
||||
|
|
|
@ -56,11 +56,11 @@
|
|||
{{ template "scripts" . }}
|
||||
<div class="container">
|
||||
<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>
|
||||
{{ template "content" . }}
|
||||
<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>
|
||||
<script>
|
||||
if (navigator.serviceWorker.controller) {
|
||||
|
|
|
@ -1,21 +1,21 @@
|
|||
{{ define "title" }}
|
||||
<title>Blog - Christine Dodrill</title>
|
||||
<title>{{ trans "header" "blog" }} - {{ trans "header" "name" }}</title>
|
||||
{{ end }}
|
||||
|
||||
{{ define "content" }}
|
||||
<h1>Blogposts</h1>
|
||||
<h1>{{ trans "blog" "index_title" }}</h1>
|
||||
|
||||
<p>
|
||||
<ul>
|
||||
{{ range . }}
|
||||
<li>{{ .Date }} - <a href="{{ .Link }}">{{ .Title }}</a></li>
|
||||
<li>{{ trans "blog" "posted_on" .Date }} - <a href="{{ .Link }}">{{ .Title }}</a></li>
|
||||
{{ end }}
|
||||
</ul>
|
||||
</p>
|
||||
|
||||
<br />
|
||||
|
||||
<h2>Other Blogs I Find Interesting</h2>
|
||||
<h2>{{ trans "blog" "blogroll" }}</h2>
|
||||
|
||||
<ul>
|
||||
<li><a href="https://write.as/excerpts/">Excerpts</a></li>
|
||||
|
@ -25,6 +25,7 @@
|
|||
<li><a href="https://shamanic.vision/">Shamanic Vision</a></li>
|
||||
</ul>
|
||||
|
||||
<h2>{{ trans "blog" "comments" }}</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>
|
||||
|
@ -33,6 +34,8 @@
|
|||
<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.
|
||||
|
||||
<br />
|
||||
|
||||
Literally preaching to the literal choir.
|
||||
</blockquote>
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{{ define "title" }}
|
||||
<title>{{ .Title }} - Christine Dodrill</title>
|
||||
<title>{{ .Title }} - {{ trans "header" "name" }}</title>
|
||||
|
||||
<!-- Twitter -->
|
||||
<meta name="twitter:card" content="summary" />
|
||||
|
@ -10,11 +10,11 @@
|
|||
<!-- Facebook -->
|
||||
<meta property="og:type" content="website" />
|
||||
<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 -->
|
||||
<meta name="description" content="{{ .Title }} - Christine Dodrill's Blog" />
|
||||
<meta name="author" content="Christine Dodrill">
|
||||
<meta name="description" content="{{ .Title }} - {{ trans "blog" "title" }}" />
|
||||
<meta name="author" content="{{ trans "header" "name" }}">
|
||||
{{ end }}
|
||||
|
||||
{{ define "content" }}
|
||||
|
|
|
@ -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" }}
|
||||
<h1>Contact Information</h1>
|
||||
<h1>{{ trans "contact" "header" }}</h1>
|
||||
<div class="grid">
|
||||
<div class="cell -6of12">
|
||||
<h3>Email</h3>
|
||||
<h3>{{ trans "contact" "email" }}</h3>
|
||||
<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>Social Media</h3>
|
||||
<h3>{{ trans "contact" "social_media" }}</h3>
|
||||
<ul>
|
||||
<li><a href="https://github.com/Xe">Github</a></li>
|
||||
<li><a href="https://twitter.com/theprincessxena">Twitter</a></li>
|
||||
|
@ -20,8 +18,11 @@
|
|||
</ul>
|
||||
</div>
|
||||
<div class="cell -6of12">
|
||||
<h3>Other Information</h3>
|
||||
<p>To send me donations, my bitcoin address is <code>1Gi2ZF2C9CU9QooH8bQMB2GJ2iL6shVnVe</code>.</p>
|
||||
<h3>{{ trans "contact" "other_info" }}</h3>
|
||||
<p>{{ trans "contact" "donations" }} <code>1Gi2ZF2C9CU9QooH8bQMB2GJ2iL6shVnVe</code>.</p>
|
||||
|
||||
<h4>IRC</h4>
|
||||
<p>{{ trans "contact" "irc_comment" }}</p>
|
||||
|
||||
<h4>Telegram</h4>
|
||||
<p><a href="https://t.me/miamorecadenza">@miamorecadenza</a></p>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{{ define "title" }}
|
||||
<title>Error - Christine Dodrill</title>
|
||||
<title>{{ trans "error" "title" }} - {{ trans "header" "name" }}</title>
|
||||
{{ end }}
|
||||
|
||||
{{ define "content" }}
|
||||
|
|
|
@ -1,29 +1,36 @@
|
|||
{{ define "title" }}<title>Christine Dodrill</title>{{ end }}
|
||||
{{ define "title" }}<title>{{ trans "header" "name" }}</title>{{ end }}
|
||||
|
||||
{{ define "content" }}
|
||||
<div class="grid">
|
||||
<div class="cell -3of12 content">
|
||||
<img src="/static/img/avatar.png">
|
||||
<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 class="cell -9of12 content">
|
||||
<h1>Christine Dodrill</h1>
|
||||
<h4>Web and Backend Services Devops Specialist</h4>
|
||||
<h5>Skills</h5>
|
||||
<h1>{{ trans "header" "name" }}</h1>
|
||||
<h4>{{ trans "index" "title" }}</h4>
|
||||
<h5>{{ trans "index" "skills" }}</h5>
|
||||
<ul>
|
||||
<li>Go, Lua, Nim, Haskell, C, Python (3.x) and other languages</li>
|
||||
<li>Docker (deployment, development & more)</li>
|
||||
<li>Mashups of data</li>
|
||||
<li>Package maintainer for Alpine Linux</li>
|
||||
<li>Speaks English, toki pona, and la .lojban.</li>
|
||||
</ul>
|
||||
|
||||
<h5>Highlighted Projects</h5>
|
||||
<h5>{{ trans "index" "highlighted_projects" }}</h5>
|
||||
<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/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/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>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -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" }}
|
||||
{{ . }}
|
||||
|
||||
<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 }}
|
||||
|
|
Loading…
Reference in New Issue