Add cookie: Locale

This commit is contained in:
iacore
2024-10-08 22:55:11 +00:00
parent d3e1d4fadf
commit e27dc301e2
9 changed files with 84 additions and 40 deletions
+8 -8
View File
@@ -29,14 +29,14 @@ const (
R18G XRestrict = 2
)
func (x XRestrict) Localize(l i18n.Localizer) string {
func (x XRestrict) String() string {
switch x {
case Safe:
return l.Tr("Safe")
return i18n.Tr("Safe")
case R18:
return l.Tr("R18")
return i18n.Tr("R18")
case R18G:
return l.Tr("R18G")
return i18n.Tr("R18G")
}
log.Panicf("invalid value: %#v", int(x))
return ""
@@ -56,14 +56,14 @@ const (
AI AiType = 2
)
func (x AiType) Localize(l i18n.Localizer) string {
func (x AiType) String() string {
switch x {
case Unrated:
return l.Tr("Unrated")
return i18n.Tr("Unrated")
case NotAI:
return l.Tr("Not AI")
return i18n.Tr("Not AI")
case AI:
return l.Tr("AI")
return i18n.Tr("AI")
}
log.Panicf("invalid value: %#v", int(x))
return ""
+3 -2
View File
@@ -1,10 +1,11 @@
# Localization
Notes on i18n/
Important notice: please don't translate server logs with `i18n.*()`. It uses the request locale, not the server one.
## Todo
- [ ] Add env PIXIVFE_SERVER_LOCALE and set `i18n.GlobalLocale` to that on startup
- [x] Add cookie: Locale
- [ ] Add option to set locale in settings page
- [ ] Rewrite jet template on load to use translated strings
- [ ] Check if any jet template strings are ignored (false negative)
- Setup Crowdin
+1
View File
@@ -21,6 +21,7 @@ require (
github.com/sethvargo/go-limiter v1.0.0
github.com/soluble-ai/go-jnode v0.1.11
github.com/tidwall/gjson v1.18.0
github.com/timandy/routine v1.1.4
github.com/yargevad/filepathx v1.0.0
github.com/zeebo/xxh3 v1.0.2
golang.org/x/net v0.30.0
+10
View File
@@ -10,6 +10,8 @@ github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
github.com/andybalholm/cascadia v1.3.2 h1:3Xi6Dw5lHF15JtdcmAHD3i1+T8plmv7BQ/nsViSLyss=
github.com/andybalholm/cascadia v1.3.2/go.mod h1:7gtRlve5FxPPgIgX36uWBX58OdBsSS6lUvCFb+h7KvU=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
github.com/go-faker/faker/v4 v4.5.0 h1:ARzAY2XoOL9tOUK+KSecUQzyXQsUaZHefjyF8x6YFHc=
@@ -37,18 +39,24 @@ github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D
github.com/oklog/ulid/v2 v2.1.0 h1:+9lhoxAP56we25tyYETBBY1YLA2SaoLvUFgrP2miPJU=
github.com/oklog/ulid/v2 v2.1.0/go.mod h1:rcEKHmBBKfef9DhnvX7y1HZBYxjXb0cP5ExxNsTT1QQ=
github.com/pborman/getopt v0.0.0-20170112200414-7148bc3a4c30/go.mod h1:85jBQOZwpVEaDAr341tbn15RS4fCAsIst0qp7i8ex1o=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/sethvargo/go-envconfig v1.1.0 h1:cWZiJxeTm7AlCvzGXrEXaSTCNgip5oJepekh/BOQuog=
github.com/sethvargo/go-envconfig v1.1.0/go.mod h1:JLd0KFWQYzyENqnEPWWZ49i4vzZo/6nRidxI8YvGiHw=
github.com/sethvargo/go-limiter v1.0.0 h1:JqW13eWEMn0VFv86OKn8wiYJY/m250WoXdrjRV0kLe4=
github.com/sethvargo/go-limiter v1.0.0/go.mod h1:01b6tW25Ap+MeLYBuD4aHunMrJoNO5PVUFdS9rac3II=
github.com/soluble-ai/go-jnode v0.1.11 h1:To9h6zWI6qr5Vphz0XO4JtCRlkhfilH2EDNwtAZkZT4=
github.com/soluble-ai/go-jnode v0.1.11/go.mod h1:mKFUM7xxXMBVOygZeE8od2Qls1f3E3NHY1ZhMlzwx/U=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY=
github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
github.com/timandy/routine v1.1.4 h1:L9eAli/ROJcW6LhmwZcusYQcdAqxAXGOQhEXLQSNWOA=
github.com/timandy/routine v1.1.4/go.mod h1:siBcl8iIsGmhLCajRGRcy7Y7FVcicNXkr97JODdt9fc=
github.com/yargevad/filepathx v1.0.0 h1:SYcT+N3tYGi+NvazubCNlvgIPbzAk7i7y2dwg3I5FYc=
github.com/yargevad/filepathx v1.0.0/go.mod h1:BprfX/gpYNJHJfc35GjRRpVcwWXS89gGulUIU5tK3tA=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
@@ -97,3 +105,5 @@ golang.org/x/tools v0.0.0-20191203134012-c197fd4bf371/go.mod h1:b+2E5dAYhXwXZwtn
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+15 -5
View File
@@ -3,26 +3,36 @@ package i18n
import (
"errors"
"fmt"
"github.com/timandy/routine"
)
var GlobalLocale string = "en"
var Locale = routine.NewInheritableThreadLocal[string]()
func getLocalizer() Localizer {
locale := Locale.Get()
if locale == "" {
locale = "en"
}
return LocalizerOf(locale)
}
func Error(text string) error {
text = LocalizerOf(GlobalLocale).lookup(text)
text = getLocalizer().lookup(text)
return errors.New(text)
}
func Errorf(format string, a ...any) error {
format = LocalizerOf(GlobalLocale).lookup(format)
format = getLocalizer().lookup(format)
return fmt.Errorf(format, a...)
}
func Sprintf(format string, a ...any) string {
format = LocalizerOf(GlobalLocale).lookup(format)
format = getLocalizer().lookup(format)
return fmt.Sprintf(format, a...)
}
// translate string
func Tr(text string) string {
return LocalizerOf(GlobalLocale).lookup(text)
return getLocalizer().lookup(text)
}
+1 -1
View File
@@ -22,7 +22,7 @@ func LocalizerOf(locale string) Localizer {
return Localizer{locale: locale}
}
// translate string
// lookup string in the database
func (l Localizer) lookup(text string) string {
translation_map, exist := locales[l.locale]
if !exist {
+27 -24
View File
@@ -30,28 +30,30 @@ func main() {
// Conditionally initialize and start the proxy checker
if config.GlobalConfig.ProxyCheckEnabled {
var wg_firstCheck sync.WaitGroup
wg_firstCheck.Add(1)
go func() {
ctx, cancel := context.WithTimeout(context.Background(), config.GlobalConfig.ProxyCheckTimeout)
proxy_checker.CheckProxies(ctx)
cancel()
wg_firstCheck.Done()
if config.GlobalConfig.ProxyCheckInterval != 0 {
for {
time.Sleep(config.GlobalConfig.ProxyCheckInterval)
ctx, cancel := context.WithTimeout(context.Background(), config.GlobalConfig.ProxyCheckTimeout)
proxy_checker.CheckProxies(ctx)
cancel()
}
}
}()
var wg_firstCheck sync.WaitGroup
wg_firstCheck.Add(1)
// Wait for the first proxy check to complete
log.Println("Waiting for initial proxy check to complete...")
wg_firstCheck.Wait()
log.Println("Initial proxy check completed.")
go func() {
ctx, cancel := context.WithTimeout(context.Background(), config.GlobalConfig.ProxyCheckTimeout)
proxy_checker.CheckProxies(ctx)
cancel()
wg_firstCheck.Done()
if config.GlobalConfig.ProxyCheckInterval != 0 {
for {
time.Sleep(config.GlobalConfig.ProxyCheckInterval)
ctx, cancel := context.WithTimeout(context.Background(), config.GlobalConfig.ProxyCheckTimeout)
proxy_checker.CheckProxies(ctx)
cancel()
}
}
}()
// Wait for the first proxy check to complete
log.Println("Waiting for initial proxy check to complete...")
wg_firstCheck.Wait()
log.Println("Initial proxy check completed.")
}()
} else {
log.Println("Skipping proxy checker initialization.")
}
@@ -60,10 +62,11 @@ func main() {
router := middleware.DefineRoutes()
// the first middleware is the most outer / first executed one
router.Use(middleware.ProvideUserContext) // needed for everything else
router.Use(middleware.LogRequest) // all pages need this
router.Use(middleware.SetPrivacyHeaders) // all pages need this
router.Use(middleware.HandleError) // if the inner handler fails, this shows the error page instead
router.Use(middleware.ProvideUserContext) // needed for everything else
router.Use(middleware.SetLocaleFromCookie) // needed for i18n.*()
router.Use(middleware.LogRequest) // all pages need this
router.Use(middleware.SetPrivacyHeaders) // all pages need this
router.Use(middleware.HandleError) // if the inner handler fails, this shows the error page instead
router.Use(middleware.InitializeRateLimiter())
// watch and compile sass when in development mode
+17
View File
@@ -0,0 +1,17 @@
package middleware
import (
"net/http"
"codeberg.org/vnpower/pixivfe/v2/i18n"
"codeberg.org/vnpower/pixivfe/v2/server/session"
)
// ProvideUserContext is a middleware that wraps an http.Handler
// to inject a user context into each incoming request.
func SetLocaleFromCookie(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
i18n.Locale.Set(session.GetCookie(r, session.Cookie_Locale))
h.ServeHTTP(w, r)
})
}
+2
View File
@@ -21,6 +21,7 @@ const ( // the __Host thing force it to be secure and same-origin (no subdomain)
Cookie_HideArtR18 CookieName = "pixivfe-HideArtR18"
Cookie_HideArtR18G CookieName = "pixivfe-HideArtR18G"
Cookie_HideArtAI CookieName = "pixivfe-HideArtAI"
Cookie_Locale CookieName = "pixivfe-Locale"
)
// Go can't make this a const...
@@ -35,6 +36,7 @@ var AllCookieNames []CookieName = []CookieName{
Cookie_HideArtR18,
Cookie_HideArtR18G,
Cookie_HideArtAI,
Cookie_Locale,
}
func GetCookie(r *http.Request, name CookieName) string {