From 238f4cf682174db1c6391c877984875600e19f43 Mon Sep 17 00:00:00 2001 From: Arsen Musayelyan Date: Wed, 11 Jan 2023 18:07:49 -0800 Subject: [PATCH] Add localization to API server --- cmd/lure-api-server/api.go | 72 +++++++++++++++++++++++++++++++++---- cmd/lure-api-server/main.go | 20 +++++++++++ 2 files changed, 86 insertions(+), 6 deletions(-) diff --git a/cmd/lure-api-server/api.go b/cmd/lure-api-server/api.go index 0e28982..d75c016 100644 --- a/cmd/lure-api-server/api.go +++ b/cmd/lure-api-server/api.go @@ -9,9 +9,11 @@ import ( "github.com/jmoiron/sqlx" "github.com/twitchtv/twirp" + "go.arsenm.dev/logger/log" "go.arsenm.dev/lure/internal/api" "go.arsenm.dev/lure/internal/config" "go.arsenm.dev/lure/internal/db" + "golang.org/x/text/language" ) type lureWebAPI struct { @@ -59,7 +61,7 @@ func (l lureWebAPI) Search(ctx context.Context, req *api.SearchRequest) (*api.Se if err != nil { return nil, err } - out.Packages = append(out.Packages, dbPkgToAPI(pkg)) + out.Packages = append(out.Packages, dbPkgToAPI(ctx, pkg)) } return out, err @@ -70,7 +72,7 @@ func (l lureWebAPI) GetPkg(ctx context.Context, req *api.GetPackageRequest) (*ap if err != nil { return nil, err } - return dbPkgToAPI(pkg), nil + return dbPkgToAPI(ctx, pkg), nil } func (l lureWebAPI) GetBuildScript(ctx context.Context, req *api.GetBuildScriptRequest) (*api.GetBuildScriptResponse, error) { @@ -94,16 +96,16 @@ func (l lureWebAPI) GetBuildScript(ctx context.Context, req *api.GetBuildScriptR return &api.GetBuildScriptResponse{Script: string(data)}, nil } -func dbPkgToAPI(pkg *db.Package) *api.Package { +func dbPkgToAPI(ctx context.Context, pkg *db.Package) *api.Package { return &api.Package{ Name: pkg.Name, Repository: pkg.Repository, Version: pkg.Version, Release: int64(pkg.Release), Epoch: ptr(int64(pkg.Epoch)), - Description: &pkg.Description, - Homepage: &pkg.Homepage, - Maintainer: &pkg.Maintainer, + Description: performTranslation(ctx, pkg.Description.Val), + Homepage: performTranslation(ctx, pkg.Homepage.Val), + Maintainer: performTranslation(ctx, pkg.Maintainer.Val), Architectures: pkg.Architectures.Val, Licenses: pkg.Licenses.Val, Provides: pkg.Provides.Val, @@ -125,3 +127,61 @@ func dbMapToAPI(m map[string][]string) map[string]*api.StringList { } return out } + +func performTranslation(ctx context.Context, v map[string]string) *string { + alVal := ctx.Value(acceptLanguageKey{}) + langVal := ctx.Value(langParameterKey{}) + + if alVal == nil && langVal == nil { + val, ok := v[""] + if !ok { + return ptr("") + } + return &val + } + + al, _ := alVal.(string) + lang, _ := langVal.(string) + + tags, _, err := language.ParseAcceptLanguage(al) + if err != nil { + log.Warn("Error parsing Accept-Language header").Err(err).Send() + } + + var bases []string + if lang != "" { + langTag, err := language.Parse(lang) + if err != nil { + log.Warn("Error parsing lang parameter").Err(err).Send() + bases = getLangBases(tags) + } else { + bases = getLangBases(append([]language.Tag{langTag}, tags...)) + } + } else { + bases = getLangBases(tags) + } + + if len(bases) == 1 { + bases = []string{"en", ""} + } + + for _, name := range bases { + val, ok := v[name] + if !ok { + continue + } + return &val + } + + return ptr("") +} + +func getLangBases(langs []language.Tag) []string { + out := make([]string, len(langs)+1) + for i, lang := range langs { + base, _ := lang.Base() + out[i] = base.String() + } + out[len(out)-1] = "" + return out +} diff --git a/cmd/lure-api-server/main.go b/cmd/lure-api-server/main.go index e35e4b4..1d14fb2 100644 --- a/cmd/lure-api-server/main.go +++ b/cmd/lure-api-server/main.go @@ -49,6 +49,7 @@ func main() { lureWebAPI{db: gdb}, twirp.WithServerPathPrefix(""), ) + handler = withAcceptLanguage(handler) handler = allowAllCORSHandler(handler) handler = handleWebhook(handler, sigCh) @@ -75,3 +76,22 @@ func allowAllCORSHandler(h http.Handler) http.Handler { h.ServeHTTP(res, req) }) } + +type acceptLanguageKey struct{} +type langParameterKey struct{} + +func withAcceptLanguage(h http.Handler) http.Handler { + return http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) { + ctx := req.Context() + + langs := req.Header.Get("Accept-Language") + ctx = context.WithValue(ctx, acceptLanguageKey{}, langs) + + lang := req.URL.Query().Get("lang") + ctx = context.WithValue(ctx, langParameterKey{}, lang) + + req = req.WithContext(ctx) + + h.ServeHTTP(res, req) + }) +}