bskyweb: basic i18n setup
Uses Cookies, then HTTP Accept-Language, then default, to negotiate language setting. The cookie name is 'lang', and the value can be any string which would be valid in Accept-Language. This includes a trivial 2-char ISO code. Language setting is returned as 2-char ISO code (though could be more flexible in the future if needed). HTML language is configured (attr), and a secondary per-language scripts.html file is included. As a hack Makefile generates the scripts_*.html files; typescript build system will need to populate those appropriately as part of 'make build-web' to finish integration.
This commit is contained in:
@@ -9,6 +9,7 @@ static/js/*.js
|
||||
static/js/*.map
|
||||
static/js/*.js.LICENSE.txt
|
||||
templates/scripts.html
|
||||
templates/scripts_*.html
|
||||
|
||||
# Don't ignore this file
|
||||
!.gitignore
|
||||
|
||||
+1
-1
@@ -42,4 +42,4 @@ check: ## Compile everything, checking syntax (does not output binaries)
|
||||
|
||||
.PHONY: run-dev-bskyweb
|
||||
run-dev-bskyweb: .env ## Runs 'bskyweb' for local dev
|
||||
GOLOG_LOG_LEVEL=info go run ./cmd/bskyweb serve --debug
|
||||
GOLOG_LOG_LEVEL=info go run ./cmd/bskyweb serve
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/labstack/echo/v4"
|
||||
"golang.org/x/text/language"
|
||||
)
|
||||
|
||||
// this constant determines the supported languages. the first in the array is used as a fallback.
|
||||
//
|
||||
// NOTE: intentionally using 2-char codes here instead of the named constants
|
||||
// https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes
|
||||
var langMatcher = language.NewMatcher([]language.Tag{
|
||||
language.MustParse("en"), // English: default/fallback
|
||||
language.MustParse("ja"), // Japanese
|
||||
language.MustParse("pt"), // Portuguese
|
||||
language.MustParse("de"), // German
|
||||
language.MustParse("hi"), // Hindi
|
||||
})
|
||||
|
||||
// cookie value should have same syntax as an Accept-Language HTTP header
|
||||
var langCookieName = "lang"
|
||||
|
||||
// returns an ISO 639 2-char language code to use for this request.
|
||||
//
|
||||
// tries a cookie first, then Accept-Language HTTP header, then a default
|
||||
func determineLangCode(c echo.Context) string {
|
||||
|
||||
cookieVal := ""
|
||||
cookie, err := c.Cookie(langCookieName)
|
||||
if err != nil {
|
||||
c.Logger().Warn(err)
|
||||
} else {
|
||||
cookieVal = cookie.Value
|
||||
}
|
||||
|
||||
hdr := c.Request().Header.Get("Accept-Language")
|
||||
langTag, _ := language.MatchStrings(langMatcher, cookieVal, hdr)
|
||||
base, _ := langTag.Base()
|
||||
return base.String()
|
||||
}
|
||||
@@ -276,16 +276,19 @@ func (srv *Server) errorHandler(err error, c echo.Context) {
|
||||
// handler for endpoint that have no specific server-side handling
|
||||
func (srv *Server) WebGeneric(c echo.Context) error {
|
||||
data := pongo2.Context{}
|
||||
data["lang"] = determineLangCode(c)
|
||||
return c.Render(http.StatusOK, "base.html", data)
|
||||
}
|
||||
|
||||
func (srv *Server) WebHome(c echo.Context) error {
|
||||
data := pongo2.Context{}
|
||||
data["lang"] = determineLangCode(c)
|
||||
return c.Render(http.StatusOK, "home.html", data)
|
||||
}
|
||||
|
||||
func (srv *Server) WebPost(c echo.Context) error {
|
||||
data := pongo2.Context{}
|
||||
data["lang"] = determineLangCode(c)
|
||||
handle := c.Param("handle")
|
||||
rkey := c.Param("rkey")
|
||||
// sanity check argument
|
||||
@@ -321,6 +324,7 @@ func (srv *Server) WebPost(c echo.Context) error {
|
||||
|
||||
func (srv *Server) WebProfile(c echo.Context) error {
|
||||
data := pongo2.Context{}
|
||||
data["lang"] = determineLangCode(c)
|
||||
handle := c.Param("handle")
|
||||
// sanity check argument
|
||||
if len(handle) > 4 && len(handle) < 128 {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<!DOCTYPE html>
|
||||
<html lang="{{ lang }}">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1, viewport-fit=cover">
|
||||
@@ -172,6 +172,11 @@
|
||||
}
|
||||
</style>
|
||||
{% include "scripts.html" %}
|
||||
{% if lang == "en" %}{% include "scripts_en.html" %}{% endif %}
|
||||
{% if lang == "ja" %}{% include "scripts_ja.html" %}{% endif %}
|
||||
{% if lang == "pt" %}{% include "scripts_pt.html" %}{% endif %}
|
||||
{% if lang == "de" %}{% include "scripts_de.html" %}{% endif %}
|
||||
{% if lang == "hi" %}{% include "scripts_hi.html" %}{% endif %}
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/static/apple-touch-icon.png">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="/static/favicon-32x32.png">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="/static/favicon-16x16.png">
|
||||
|
||||
Reference in New Issue
Block a user