mirror of
https://github.com/kataras/iris.git
synced 2025-01-23 10:41:03 +01:00
add support for the go standard embed tag for locale files
This commit is contained in:
parent
fd1db640a0
commit
4cd0621018
|
@ -28,6 +28,7 @@ The codebase for Dependency Injection, Internationalization and localization and
|
||||||
|
|
||||||
## Fixes and Improvements
|
## Fixes and Improvements
|
||||||
|
|
||||||
|
- Support of embedded [locale files](https://github.com/kataras/iris/blob/master/_examples/i18n/template-embedded/main.go) using standard `embed.FS` with the new `LoadFS` function.
|
||||||
- Support of direct embedded view templates with `embed.FS` or `fs.FS` (in addition to `string` and `http.FileSystem` types).
|
- Support of direct embedded view templates with `embed.FS` or `fs.FS` (in addition to `string` and `http.FileSystem` types).
|
||||||
|
|
||||||
- Add `iris.Patches()` package-level function to customize Iris Request Context REST (and more to come) behavior.
|
- Add `iris.Patches()` package-level function to customize Iris Request Context REST (and more to come) behavior.
|
||||||
|
|
|
@ -218,6 +218,7 @@
|
||||||
* Localization and Internationalization
|
* Localization and Internationalization
|
||||||
* [Basic](i18n/basic)
|
* [Basic](i18n/basic)
|
||||||
* [Ttemplates and Functions](i18n/template)
|
* [Ttemplates and Functions](i18n/template)
|
||||||
|
* [Ttemplates and Functions (Embedded)](i18n/template-embedded)
|
||||||
* [Pluralization and Variables](i18n/plurals)
|
* [Pluralization and Variables](i18n/plurals)
|
||||||
* Authentication, Authorization & Bot Detection
|
* Authentication, Authorization & Bot Detection
|
||||||
* [Recommended: Auth package and Single-Sign-On](auth/auth) **NEW (GO 1.18 Generics required)**
|
* [Recommended: Auth package and Single-Sign-On](auth/auth) **NEW (GO 1.18 Generics required)**
|
||||||
|
|
10
_examples/i18n/template-embedded/locales/el-GR/other.ini
Normal file
10
_examples/i18n/template-embedded/locales/el-GR/other.ini
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
[nav]
|
||||||
|
User = Λογαριασμός
|
||||||
|
|
||||||
|
[debug]
|
||||||
|
Title = Μενού προγραμματιστή
|
||||||
|
AccessLog = Πρόσβαση στο αρχείο καταγραφής
|
||||||
|
AccessLogClear = Καθαρισμός {{tr "debug.AccessLog"}}
|
||||||
|
|
||||||
|
[user.connections]
|
||||||
|
Title = {{tr "nav.User"}} Συνδέσεις
|
4
_examples/i18n/template-embedded/locales/el-GR/user.ini
Normal file
4
_examples/i18n/template-embedded/locales/el-GR/user.ini
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
[forms]
|
||||||
|
member = μέλος
|
||||||
|
register = Γίνε {{uppercase (tr "forms.member") }}
|
||||||
|
registered = εγγεγραμμένοι
|
12
_examples/i18n/template-embedded/locales/en-US/other.ini
Normal file
12
_examples/i18n/template-embedded/locales/en-US/other.ini
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
# just an example of some more nested keys,
|
||||||
|
# see /other endpoint.
|
||||||
|
[nav]
|
||||||
|
User = Account
|
||||||
|
|
||||||
|
[debug]
|
||||||
|
Title = Developer Menu
|
||||||
|
AccessLog = Access Log
|
||||||
|
AccessLogClear = Clear {{tr "debug.AccessLog"}}
|
||||||
|
|
||||||
|
[user.connections]
|
||||||
|
Title = {{tr "nav.User"}} Connections
|
4
_examples/i18n/template-embedded/locales/en-US/user.ini
Normal file
4
_examples/i18n/template-embedded/locales/en-US/user.ini
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
[forms]
|
||||||
|
member = member
|
||||||
|
register = Become a {{uppercase (tr "forms.member") }}
|
||||||
|
registered = registered
|
50
_examples/i18n/template-embedded/main.go
Normal file
50
_examples/i18n/template-embedded/main.go
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"embed"
|
||||||
|
"strings"
|
||||||
|
"text/template"
|
||||||
|
|
||||||
|
"github.com/kataras/iris/v12"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:embed locales/*
|
||||||
|
var filesystem embed.FS
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
app := newApp()
|
||||||
|
app.Listen(":8080")
|
||||||
|
}
|
||||||
|
|
||||||
|
func newApp() *iris.Application {
|
||||||
|
app := iris.New()
|
||||||
|
|
||||||
|
// Set custom functions per locale!
|
||||||
|
app.I18n.Loader.Funcs = func(current iris.Locale) template.FuncMap {
|
||||||
|
return template.FuncMap{
|
||||||
|
"uppercase": func(word string) string {
|
||||||
|
return strings.ToUpper(word)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Instead of:
|
||||||
|
// err := app.I18n.Load("./locales/*/*.ini", "en-US", "el-GR")
|
||||||
|
// Apply the below in order to build with embedded locales inside your executable binary.
|
||||||
|
err := app.I18n.LoadFS(filesystem, ".", "en-US", "el-GR")
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
app.Get("/", func(ctx iris.Context) {
|
||||||
|
text := ctx.Tr("forms.register") // en-US: prints "Become a MEMBER".
|
||||||
|
ctx.WriteString(text)
|
||||||
|
})
|
||||||
|
|
||||||
|
app.Get("/title", func(ctx iris.Context) {
|
||||||
|
text := ctx.Tr("user.connections.Title") // en-US: prints "Accounts Connections".
|
||||||
|
ctx.WriteString(text)
|
||||||
|
})
|
||||||
|
|
||||||
|
return app
|
||||||
|
}
|
21
_examples/i18n/template-embedded/main_test.go
Normal file
21
_examples/i18n/template-embedded/main_test.go
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/kataras/iris/v12/httptest"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestI18nLoaderFuncMap(t *testing.T) {
|
||||||
|
app := newApp()
|
||||||
|
|
||||||
|
e := httptest.New(t, app)
|
||||||
|
e.GET("/").Expect().Status(httptest.StatusOK).
|
||||||
|
Body().Equal("Become a MEMBER")
|
||||||
|
e.GET("/title").Expect().Status(httptest.StatusOK).
|
||||||
|
Body().Equal("Account Connections")
|
||||||
|
e.GET("/").WithHeader("Accept-Language", "el").Expect().Status(httptest.StatusOK).
|
||||||
|
Body().Equal("Γίνε ΜΈΛΟΣ")
|
||||||
|
e.GET("/title").WithHeader("Accept-Language", "el").Expect().Status(httptest.StatusOK).
|
||||||
|
Body().Equal("Λογαριασμός Συνδέσεις")
|
||||||
|
}
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"path"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ResolveFS accepts a single input argument of any type
|
// ResolveFS accepts a single input argument of any type
|
||||||
|
@ -44,3 +45,67 @@ var ResolveFS = func(fsOrDir interface{}) http.FileSystem {
|
||||||
|
|
||||||
return fileSystem
|
return fileSystem
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FindNames accepts a "http.FileSystem" and a root name and returns
|
||||||
|
// the list containg its file names.
|
||||||
|
func FindNames(fileSystem http.FileSystem, name string) ([]string, error) {
|
||||||
|
f, err := fileSystem.Open(name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
fi, err := f.Stat()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !fi.IsDir() {
|
||||||
|
return []string{name}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
fileinfos, err := f.Readdir(-1)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
files := make([]string, 0)
|
||||||
|
|
||||||
|
for _, info := range fileinfos {
|
||||||
|
// Note:
|
||||||
|
// go-bindata has absolute names with os.Separator,
|
||||||
|
// http.Dir the basename.
|
||||||
|
filename := toBaseName(info.Name())
|
||||||
|
fullname := path.Join(name, filename)
|
||||||
|
if fullname == name { // prevent looping through itself.
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
rfiles, err := FindNames(fileSystem, fullname)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
files = append(files, rfiles...)
|
||||||
|
}
|
||||||
|
|
||||||
|
return files, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Instead of path.Base(filepath.ToSlash(s))
|
||||||
|
// let's do something like that, it is faster
|
||||||
|
// (used to list directories on serve-time too):
|
||||||
|
func toBaseName(s string) string {
|
||||||
|
n := len(s) - 1
|
||||||
|
for i := n; i >= 0; i-- {
|
||||||
|
if c := s[i]; c == '/' || c == '\\' {
|
||||||
|
if i == n {
|
||||||
|
// "s" ends with a slash, remove it and retry.
|
||||||
|
return toBaseName(s[:n])
|
||||||
|
}
|
||||||
|
|
||||||
|
return s[i+1:] // return the rest, trimming the slash.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
|
@ -372,7 +372,7 @@ func FileServer(fs http.FileSystem, options DirOptions) context.Handler {
|
||||||
}
|
}
|
||||||
|
|
||||||
prefixURL := strings.TrimSuffix(r.RequestURI, name)
|
prefixURL := strings.TrimSuffix(r.RequestURI, name)
|
||||||
names, err := findNames(fs, name)
|
names, err := context.FindNames(fs, name)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
for _, indexAsset := range names {
|
for _, indexAsset := range names {
|
||||||
// it's an index file, do not pushed that.
|
// it's an index file, do not pushed that.
|
||||||
|
@ -858,7 +858,7 @@ func fsOpener(fs http.FileSystem, options DirCacheOptions) func(name string, r *
|
||||||
func cache(fs http.FileSystem, options DirCacheOptions) (*cacheFS, error) {
|
func cache(fs http.FileSystem, options DirCacheOptions) (*cacheFS, error) {
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
|
|
||||||
names, err := findNames(fs, "/")
|
names, err := context.FindNames(fs, "/")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -1175,49 +1175,6 @@ func (f *file) Get(alg string) (http.File, error) {
|
||||||
return f.Get("")
|
return f.Get("")
|
||||||
}
|
}
|
||||||
|
|
||||||
func findNames(fs http.FileSystem, name string) ([]string, error) {
|
|
||||||
f, err := fs.Open(name)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer f.Close()
|
|
||||||
|
|
||||||
fi, err := f.Stat()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if !fi.IsDir() {
|
|
||||||
return []string{name}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
fileinfos, err := f.Readdir(-1)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
files := make([]string, 0)
|
|
||||||
|
|
||||||
for _, info := range fileinfos {
|
|
||||||
// Note:
|
|
||||||
// go-bindata has absolute names with os.Separator,
|
|
||||||
// http.Dir the basename.
|
|
||||||
filename := toBaseName(info.Name())
|
|
||||||
fullname := path.Join(name, filename)
|
|
||||||
if fullname == name { // prevent looping through itself when fs is cacheFS.
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
rfiles, err := findNames(fs, fullname)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
files = append(files, rfiles...)
|
|
||||||
}
|
|
||||||
|
|
||||||
return files, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type fileInfo struct {
|
type fileInfo struct {
|
||||||
baseName string
|
baseName string
|
||||||
modTime time.Time
|
modTime time.Time
|
||||||
|
|
8
go.mod
8
go.mod
|
@ -2,7 +2,7 @@ module github.com/kataras/iris/v12
|
||||||
|
|
||||||
go 1.19
|
go 1.19
|
||||||
|
|
||||||
// retract v12.1.8 // please update to @master
|
retract v12.1.8 // Please update to @master
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/BurntSushi/toml v1.2.0
|
github.com/BurntSushi/toml v1.2.0
|
||||||
|
@ -40,11 +40,11 @@ require (
|
||||||
github.com/vmihailenco/msgpack/v5 v5.3.5
|
github.com/vmihailenco/msgpack/v5 v5.3.5
|
||||||
github.com/yosssi/ace v0.0.5
|
github.com/yosssi/ace v0.0.5
|
||||||
go.etcd.io/bbolt v1.3.6
|
go.etcd.io/bbolt v1.3.6
|
||||||
golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90
|
golang.org/x/crypto v0.0.0-20220919173607-35f4265a4bc0
|
||||||
golang.org/x/net v0.0.0-20220909164309-bea034e7d591
|
golang.org/x/net v0.0.0-20220921203646-d300de134e69
|
||||||
golang.org/x/sys v0.0.0-20220919091848-fb04ddd9f9c8
|
golang.org/x/sys v0.0.0-20220919091848-fb04ddd9f9c8
|
||||||
golang.org/x/text v0.3.7
|
golang.org/x/text v0.3.7
|
||||||
golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9
|
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af
|
||||||
google.golang.org/protobuf v1.28.1
|
google.golang.org/protobuf v1.28.1
|
||||||
gopkg.in/ini.v1 v1.67.0
|
gopkg.in/ini.v1 v1.67.0
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
|
|
12
go.sum
generated
12
go.sum
generated
|
@ -245,13 +245,13 @@ go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4=
|
||||||
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20210314154223-e6e6c4f2bb5b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
golang.org/x/crypto v0.0.0-20210314154223-e6e6c4f2bb5b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||||
golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 h1:Y/gsMcFOcR+6S6f3YeMKl5g+dZMEWqcz5Czj/GWYbkM=
|
golang.org/x/crypto v0.0.0-20220919173607-35f4265a4bc0 h1:a5Yg6ylndHHYJqIPrdq0AhvR6KTvDTAvgBtaidhEevY=
|
||||||
golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
golang.org/x/crypto v0.0.0-20220919173607-35f4265a4bc0/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
golang.org/x/net v0.0.0-20190327091125-710a502c58a2/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190327091125-710a502c58a2/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
golang.org/x/net v0.0.0-20220909164309-bea034e7d591 h1:D0B/7al0LLrVC8aWF4+oxpv/m8bc7ViFfVS8/gXGdqI=
|
golang.org/x/net v0.0.0-20220921203646-d300de134e69 h1:hUJpGDpnfwdJW8iNypFjmSY0sCBEL+spFTZ2eO+Sfps=
|
||||||
golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
golang.org/x/net v0.0.0-20220921203646-d300de134e69/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
||||||
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f h1:Ax0t5p6N38Ga0dThY21weqDEyz2oklo4IvDkpigvkD8=
|
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f h1:Ax0t5p6N38Ga0dThY21weqDEyz2oklo4IvDkpigvkD8=
|
||||||
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190130150945-aca44879d564/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190130150945-aca44879d564/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
@ -274,8 +274,8 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
|
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
|
||||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9 h1:ftMN5LMiBFjbzleLqtoBZk7KdJwhuybIU+FckUHgoyQ=
|
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af h1:Yx9k8YCG3dvF87UAn2tu2HQLf2dt/eR1bXxpLMWeH+Y=
|
||||||
golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
|
19
i18n/i18n.go
19
i18n/i18n.go
|
@ -140,6 +140,21 @@ func (i *I18n) LoadAssets(assetNames func() []string, asset func(string) ([]byte
|
||||||
return i.Reset(Assets(assetNames, asset, i.Loader), languages...)
|
return i.Reset(Assets(assetNames, asset, i.Loader), languages...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LoadFS is a method shortcut to load files using `embed.FS` or `fs.FS` or
|
||||||
|
// `http.FileSystem` or `string` (local directory).
|
||||||
|
// With this method, all the embedded files into "sub" MUST be locale files.
|
||||||
|
//
|
||||||
|
// See `New` and `FS` package-level functions for more.
|
||||||
|
// Example: https://github.com/kataras/iris/blob/master/_examples/i18n/template-embedded/main.go.
|
||||||
|
func (i *I18n) LoadFS(fsOrDir interface{}, sub string, languages ...string) error {
|
||||||
|
loader, err := FS(fsOrDir, sub, i.Loader)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return i.Reset(loader, languages...)
|
||||||
|
}
|
||||||
|
|
||||||
// Reset sets the locales loader and languages.
|
// Reset sets the locales loader and languages.
|
||||||
// It is not meant to be used by users unless
|
// It is not meant to be used by users unless
|
||||||
// a custom `Loader` must be used instead of the default one.
|
// a custom `Loader` must be used instead of the default one.
|
||||||
|
@ -474,7 +489,9 @@ func (i *I18n) setLangWithoutContext(w http.ResponseWriter, r *http.Request, lan
|
||||||
SameSite: http.SameSiteLaxMode,
|
SameSite: http.SameSiteLaxMode,
|
||||||
})
|
})
|
||||||
} else if i.URLParameter != "" {
|
} else if i.URLParameter != "" {
|
||||||
r.URL.Query().Set(i.URLParameter, lang)
|
q := r.URL.Query()
|
||||||
|
q.Set(i.URLParameter, lang)
|
||||||
|
r.URL.RawQuery = q.Encode()
|
||||||
}
|
}
|
||||||
|
|
||||||
r.Header.Set(acceptLanguageHeaderKey, lang)
|
r.Header.Set(acceptLanguageHeaderKey, lang)
|
||||||
|
|
|
@ -3,10 +3,12 @@ package i18n
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/kataras/iris/v12/context"
|
||||||
"github.com/kataras/iris/v12/i18n/internal"
|
"github.com/kataras/iris/v12/i18n/internal"
|
||||||
|
|
||||||
"github.com/BurntSushi/toml"
|
"github.com/BurntSushi/toml"
|
||||||
|
@ -41,11 +43,40 @@ func Glob(globPattern string, options LoaderConfig) Loader {
|
||||||
// and any Loader options. Go-bindata usage.
|
// and any Loader options. Go-bindata usage.
|
||||||
// It returns a valid `Loader` which loads and maps the locale files.
|
// It returns a valid `Loader` which loads and maps the locale files.
|
||||||
//
|
//
|
||||||
// See `Glob`, `Assets`, `New` and `LoaderConfig` too.
|
// See `Glob`, `FS`, `New` and `LoaderConfig` too.
|
||||||
func Assets(assetNames func() []string, asset func(string) ([]byte, error), options LoaderConfig) Loader {
|
func Assets(assetNames func() []string, asset func(string) ([]byte, error), options LoaderConfig) Loader {
|
||||||
return load(assetNames(), asset, options)
|
return load(assetNames(), asset, options)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LoadFS loads the files using embed.FS or fs.FS or
|
||||||
|
// http.FileSystem or string (local directory).
|
||||||
|
// With this method, all the embedded files into "sub" MUST be locale files.
|
||||||
|
//
|
||||||
|
// See `Glob`, `Assets`, `New` and `LoaderConfig` too.
|
||||||
|
func FS(fsOrDir interface{}, sub string, options LoaderConfig) (Loader, error) {
|
||||||
|
if sub == "" {
|
||||||
|
sub = "."
|
||||||
|
}
|
||||||
|
|
||||||
|
fileSystem := context.ResolveFS(fsOrDir)
|
||||||
|
|
||||||
|
assetNames, err := context.FindNames(fileSystem, sub)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
assetFunc := func(name string) ([]byte, error) {
|
||||||
|
f, err := fileSystem.Open(name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return io.ReadAll(f)
|
||||||
|
}
|
||||||
|
|
||||||
|
return load(assetNames, assetFunc, options), nil
|
||||||
|
}
|
||||||
|
|
||||||
// DefaultLoaderConfig represents the default loader configuration.
|
// DefaultLoaderConfig represents the default loader configuration.
|
||||||
var DefaultLoaderConfig = LoaderConfig{
|
var DefaultLoaderConfig = LoaderConfig{
|
||||||
Left: "{{",
|
Left: "{{",
|
||||||
|
|
Loading…
Reference in New Issue
Block a user