mirror of
https://github.com/kataras/iris.git
synced 2025-02-02 07:20:35 +01:00
implement path prefx for i18n middleware, as requested at: #1369
Former-commit-id: b0d6b6e7f368e710b01faad9b70dfa4cebdd8c4d
This commit is contained in:
parent
1faea8b2e8
commit
0844c109d9
|
@ -81,3 +81,7 @@ If you discover a security vulnerability within Iris, please send an e-mail to [
|
|||
The project name "Iris" was inspired by the Greek mythology.
|
||||
|
||||
Iris Web Framework is free and open-source software licensed under the [3-Clause BSD License](LICENSE).
|
||||
|
||||
## Stargazers over time
|
||||
|
||||
[![Stargazers over time](https://starchart.cc/kataras/iris.svg)](https://starchart.cc/kataras/iris)
|
||||
|
|
|
@ -8,7 +8,7 @@ Iris es un framework web rápido, simple pero con muchas funcionalidades y muy e
|
|||
|
||||
Descubra lo que [otros dicen sobre Iris](https://iris-go.com/testimonials/) y **siga** :star: este repositorio github.
|
||||
|
||||
> Iris **version 12 liberado**. Lea mas [aquí](HISTORY_ES.md#sábado-26-de-octubre-2019--v1200).
|
||||
[![](https://media.giphy.com/media/eGku4UbilECflFjcNj/giphy.gif)](https://iris-go.com/testimonials/)
|
||||
|
||||
## Aprende Iris
|
||||
|
||||
|
|
|
@ -11,13 +11,7 @@
|
|||
|
||||
برای این که بدانید دیگران در مورد آیریس چه می گویند لطفا در این لینک کلیک کنید [دیگران در مورد آیریس چه می گویند](https://iris-go.com/testimonials/) لطفا این پروژه را در گیتاب **استار** کنید.
|
||||
|
||||
|
||||
> نسخه 11.2 **آماده شد**
|
||||
|
||||
<div dir="ltr" align="left">
|
||||
|
||||
[![https://www.facebook.com/iris.framework/posts/3276606095684693](https://iris-go.com/images/iris-112-released.png)](https://www.facebook.com/iris.framework/posts/3276606095684693)
|
||||
</div>
|
||||
[![](https://media.giphy.com/media/eGku4UbilECflFjcNj/giphy.gif)](https://iris-go.com/testimonials/)
|
||||
|
||||
## آموزش آیریس
|
||||
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
|
||||
Μάθετε τι [λένε οι άλλοι για το Iris](https://iris-go.com/testimonials/) και δώστε ένα **αστεράκι** στο GitHub.
|
||||
|
||||
[![](https://media.giphy.com/media/eGku4UbilECflFjcNj/giphy.gif)](https://iris-go.com/testimonials/)
|
||||
|
||||
## Μαθαίνοντας το Iris
|
||||
|
||||
<details>
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
<!-- # Iris Web Framework <a href="README_ZH.md"> <img width="20px" src="https://iris-go.com/images/flag-china.svg?v=10" /></a> <a href="README_RU.md"><img width="20px" src="https://iris-go.com/images/flag-russia.svg?v=10" /></a> <a href="README_ID.md"> <img width="20px" src="https://iris-go.com/images/flag-indonesia.svg?v=10" /></a> <a href="README_GR.md"><img width="20px" src="https://iris-go.com/images/flag-greece.svg?v=10" /></a> <a href="README_PT_BR.md"><img width="20px" src="https://iris-go.com/images/flag-pt-br.svg?v=10" /></a> <a href="README_JPN.md"><img width="20px" src="https://iris-go.com/images/flag-japan.svg?v=10" /></a> -->
|
||||
|
||||
# Iris <a href="README.md"> <img width="20px" src="https://iris-go.com/images/flag-unitedkingdom.svg?v=10" /></a> <a href="README_ZH.md"><img width="20px" src="https://iris-go.com/images/flag-china.svg?v=10" /></a> <a href="README_GR.md"><img width="20px" src="https://iris-go.com/images/flag-greece.svg?v=10" /></a> <a href="README_ES.md"><img width="20px" src="https://iris-go.com/images/flag-spain.png" /></a> <a href="README_FA.md"><img width="20px" src="https://iris-go.com/images/flag-iran.svg" /></a>
|
||||
|
||||
[![build status](https://img.shields.io/travis/kataras/iris/master.svg?style=for-the-badge)](https://travis-ci.org/kataras/iris) [![report card](https://img.shields.io/badge/report%20card-a%2B-ff3333.svg?style=for-the-badge)](https://goreportcard.com/report/github.com/kataras/iris)<!--[![godocs](https://img.shields.io/badge/go-%20docs-488AC7.svg?style=for-the-badge)](https://godoc.org/github.com/kataras/iris)--> [![view examples](https://img.shields.io/badge/learn%20by-examples-0077b3.svg?style=for-the-badge)](https://github.com/kataras/iris/tree/master/_examples) [![chat](https://img.shields.io/gitter/room/iris_go/community.svg?color=blue&logo=gitter&style=for-the-badge)](https://gitter.im/iris_go/community) [![release](https://img.shields.io/badge/release%20-v11.2-0077b3.svg?style=for-the-badge)](https://github.com/kataras/iris/releases)
|
||||
|
@ -8,9 +6,7 @@ Iris는 단순하고 빠르며 좋은 성능과 모든 기능을 갖춘 Go언어
|
|||
|
||||
[여러 사람들의 의견](https://iris-go.com/testimonials/)을 둘러보세요. 그리고 이 github repository을 **star**하세요.
|
||||
|
||||
> Version 11.2가 **릴리스되었습니다!**
|
||||
|
||||
[![https://www.facebook.com/iris.framework/posts/3276606095684693](https://iris-go.com/images/iris-112-released.png)](https://www.facebook.com/iris.framework/posts/3276606095684693)
|
||||
[![](https://media.giphy.com/media/eGku4UbilECflFjcNj/giphy.gif)](https://iris-go.com/testimonials/)
|
||||
|
||||
## Iris 배우기
|
||||
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
<!-- # Iris Web Framework <a href="README_ZH.md"> <img width="20px" src="https://iris-go.com/images/flag-china.svg?v=10" /></a> <a href="README_RU.md"><img width="20px" src="https://iris-go.com/images/flag-russia.svg?v=10" /></a> <a href="README_ID.md"> <img width="20px" src="https://iris-go.com/images/flag-indonesia.svg?v=10" /></a> <a href="README_GR.md"><img width="20px" src="https://iris-go.com/images/flag-greece.svg?v=10" /></a> <a href="README_PT_BR.md"><img width="20px" src="https://iris-go.com/images/flag-pt-br.svg?v=10" /></a> <a href="README_JPN.md"><img width="20px" src="https://iris-go.com/images/flag-japan.svg?v=10" /></a> -->
|
||||
|
||||
# Iris <a href="README.md"> <img width="20px" src="https://iris-go.com/images/flag-unitedkingdom.svg?v=10" /></a> <a href="README_GR.md"><img width="20px" src="https://iris-go.com/images/flag-greece.svg?v=10" /></a> <a href="README_ES.md"><img width="20px" src="https://iris-go.com/images/flag-spain.png" /></a> <a href="README_KO.md"><img width="20px" src="https://iris-go.com/images/flag-south-korea.svg" /></a> <a href="README_FA.md"><img width="20px" src="https://iris-go.com/images/flag-iran.svg" /></a>
|
||||
|
||||
[![build status](https://img.shields.io/travis/kataras/iris/master.svg?style=for-the-badge)](https://travis-ci.org/kataras/iris) [![report card](https://img.shields.io/badge/report%20card-a%2B-ff3333.svg?style=for-the-badge)](https://goreportcard.com/report/github.com/kataras/iris)<!--[![godocs](https://img.shields.io/badge/go-%20docs-488AC7.svg?style=for-the-badge)](https://godoc.org/github.com/kataras/iris)--> [![view examples](https://img.shields.io/badge/learn%20by-examples-0077b3.svg?style=for-the-badge)](https://github.com/kataras/iris/tree/master/_examples) [![chat](https://img.shields.io/gitter/room/iris_go/community.svg?color=blue&logo=gitter&style=for-the-badge)](https://gitter.im/iris_go/community) [![release](https://img.shields.io/badge/release%20-v11.2-0077b3.svg?style=for-the-badge)](https://github.com/kataras/iris/releases)
|
||||
|
@ -8,7 +6,7 @@ Iris 是基于 Go 编写的一个快速,简单但功能齐全且非常高效
|
|||
|
||||
看看 [其他人如何评价 Iris](https://iris-go.com/testimonials/),同时欢迎各位点亮 **star**。
|
||||
|
||||
> 新版本 11.2 发布! [散布消息](https://www.facebook.com/iris.framework/posts/3276606095684693).
|
||||
[![](https://media.giphy.com/media/eGku4UbilECflFjcNj/giphy.gif)](https://iris-go.com/testimonials/)
|
||||
|
||||
## 学习 Iris
|
||||
|
||||
|
|
2
VERSION
2
VERSION
|
@ -1 +1 @@
|
|||
12.0.1:https://github.com/kataras/iris/releases/tag/v12.0.1
|
||||
12.0.2:https://github.com/kataras/iris/releases/tag/v12.0.2
|
|
@ -7,20 +7,29 @@ import (
|
|||
|
||||
func newApp() *iris.Application {
|
||||
app := iris.New()
|
||||
app.Logger().SetLevel("debug")
|
||||
|
||||
globalLocale := i18n.New(i18n.Config{
|
||||
Default: "en-US",
|
||||
URLParameter: "lang",
|
||||
i18nConfig := i18n.Config{
|
||||
Default: "en-US",
|
||||
URLParameter: "lang",
|
||||
PathParameter: "lang",
|
||||
Languages: map[string]string{
|
||||
"en-US": "./locales/locale_en-US.ini",
|
||||
"el-GR": "./locales/locale_el-GR.ini",
|
||||
"zh-CN": "./locales/locale_zh-CN.ini",
|
||||
},
|
||||
})
|
||||
app.Use(globalLocale)
|
||||
Alternatives: map[string]string{"greek": "el-GR"},
|
||||
}
|
||||
|
||||
// See https://github.com/kataras/iris/issues/1369
|
||||
// if you want to enable this (SEO) feature.
|
||||
app.WrapRouter(i18n.NewWrapper(i18nConfig))
|
||||
|
||||
i18nMiddleware := i18n.New(i18nConfig)
|
||||
app.Use(i18nMiddleware)
|
||||
|
||||
app.Get("/", func(ctx iris.Context) {
|
||||
// it tries to find the language by:
|
||||
// Ir tries to find the language by:
|
||||
// ctx.Values().GetString("language")
|
||||
// if that was empty then
|
||||
// it tries to find from the URLParameter set on the configuration
|
||||
|
@ -35,14 +44,23 @@ func newApp() *iris.Application {
|
|||
// or:
|
||||
hi := i18n.Translate(ctx, "hi", "iris")
|
||||
|
||||
// GetTranslateLanguageContextKey() == "language"
|
||||
language := ctx.Values().GetString(ctx.Application().ConfigurationReadOnly().GetTranslateLanguageContextKey())
|
||||
// return is form of 'en-US'
|
||||
|
||||
// The first succeed language found saved at the cookie with name ("language"),
|
||||
// you can change that by changing the value of the: iris.TranslateLanguageContextKey
|
||||
// you can change that by changing the value of the: iris.TranslateLanguageContextKey
|
||||
ctx.Writef("From the language %s translated output: %s", language, hi)
|
||||
})
|
||||
|
||||
app.Get("/some-path", func(ctx iris.Context) {
|
||||
ctx.Writef("%s", ctx.Translate("hi", "iris"))
|
||||
})
|
||||
|
||||
app.Get("/sitemap.xml", func(ctx iris.Context) {
|
||||
ctx.WriteString("sitemap")
|
||||
})
|
||||
|
||||
multiLocale := i18n.New(i18n.Config{
|
||||
Default: "en-US",
|
||||
URLParameter: "lang",
|
||||
|
@ -68,7 +86,8 @@ func newApp() *iris.Application {
|
|||
|
||||
app.Get("/templates", func(ctx iris.Context) {
|
||||
ctx.View("index.html", iris.Map{
|
||||
"tr": ctx.Translate,
|
||||
"tr": ctx.Translate, // word, arguments...
|
||||
"trLang": ctx.TranslateLang, // locale, word, arguments...
|
||||
})
|
||||
// it will return "hello, iris"
|
||||
// when {{call .tr "hi" "iris"}}
|
||||
|
@ -81,7 +100,9 @@ func newApp() *iris.Application {
|
|||
func main() {
|
||||
app := newApp()
|
||||
|
||||
// go to http://localhost:8080/?lang=el-GR
|
||||
// go to http://localhost:8080/el-GR/some-path
|
||||
// or http://localhost:8080/zh-cn/templates
|
||||
// or http://localhost:8080/some-path?lang=el-GR
|
||||
// or http://localhost:8080 (default is en-US)
|
||||
// or http://localhost:8080/?lang=zh-CN
|
||||
//
|
||||
|
@ -90,5 +111,6 @@ func main() {
|
|||
// or http://localhost:8080/multi?lang=en-US
|
||||
//
|
||||
// or use cookies to set the language.
|
||||
//
|
||||
app.Run(iris.Addr(":8080"))
|
||||
}
|
||||
|
|
|
@ -1 +1,9 @@
|
|||
{{call .tr "hi" "iris"}}
|
||||
<h3>Test translate current locale template function <i>[dynamic]</i> ("word", arguments...) <br/> <code>call .tr "hi" "iris"</code></h3>
|
||||
|
||||
{{call .tr "hi" "iris"}}
|
||||
|
||||
<hr/>
|
||||
|
||||
<h3>Test translate of any language template function <i>[static]</i> ("language", "word", arguments...) <br/> <code>call .trLang "zh-CN" "hi" "iris"</code></h3>
|
||||
|
||||
{{call .trLang "zh-CN" "hi" "iris"}}
|
||||
|
|
|
@ -705,14 +705,17 @@ type Configuration struct {
|
|||
|
||||
// Context values' keys for various features.
|
||||
//
|
||||
// TranslateLanguageContextKey & TranslateFunctionContextKey are used by i18n handlers/middleware
|
||||
// currently we have only one: https://github.com/kataras/iris/tree/master/middleware/i18n.
|
||||
// TranslateLanguageContextKey & TranslateLangFunctionContextKey & TranslateFunctionContextKey are used by i18n handlers/middleware to set the selected locale's translate function.
|
||||
//
|
||||
// Defaults to "iris.translate" and "iris.language"
|
||||
// Defaults to "iris.translate".
|
||||
TranslateFunctionContextKey string `json:"translateFunctionContextKey,omitempty" yaml:"TranslateFunctionContextKey" toml:"TranslateFunctionContextKey"`
|
||||
// TranslateLanguageContextKey used for i18n.
|
||||
// TranslateLangFunctionContextKey & TranslateFunctionContextKey & TranslateLanguageContextKey are used by i18n handlers/middleware to set the global translate function.
|
||||
//
|
||||
// Defaults to "iris.language"
|
||||
// Defaults to "iris.languageGlobal".
|
||||
TranslateLangFunctionContextKey string `json:"translateLangFunctionContextKey,omitempty" yaml:"TranslateLangFunctionContextKey" toml:"TranslateLangFunctionContextKey"`
|
||||
// TranslateLanguageContextKey used to report the i18n selected locale.
|
||||
//
|
||||
// Defaults to "iris.language".
|
||||
TranslateLanguageContextKey string `json:"translateLanguageContextKey,omitempty" yaml:"TranslateLanguageContextKey" toml:"TranslateLanguageContextKey"`
|
||||
|
||||
// GetViewLayoutContextKey is the key of the context's user values' key
|
||||
|
@ -842,11 +845,17 @@ func (c Configuration) GetPostMaxMemory() int64 {
|
|||
}
|
||||
|
||||
// GetTranslateFunctionContextKey returns the configuration's TranslateFunctionContextKey value,
|
||||
// used for i18n.
|
||||
// used for i18n inside templates.
|
||||
func (c Configuration) GetTranslateFunctionContextKey() string {
|
||||
return c.TranslateFunctionContextKey
|
||||
}
|
||||
|
||||
// GetTranslateLangFunctionContextKey returns the configuration's TranslateLangFunctionContextKey value,
|
||||
// used for i18n inside templates.
|
||||
func (c Configuration) GetTranslateLangFunctionContextKey() string {
|
||||
return c.TranslateLangFunctionContextKey
|
||||
}
|
||||
|
||||
// GetTranslateLanguageContextKey returns the configuration's TranslateLanguageContextKey value,
|
||||
// used for i18n.
|
||||
func (c Configuration) GetTranslateLanguageContextKey() string {
|
||||
|
@ -1017,13 +1026,14 @@ func DefaultConfiguration() Configuration {
|
|||
// The request body the size limit
|
||||
// can be set by the middleware `LimitRequestBodySize`
|
||||
// or `context#SetMaxRequestBodySize`.
|
||||
PostMaxMemory: 32 << 20, // 32MB
|
||||
TranslateFunctionContextKey: "iris.translate",
|
||||
TranslateLanguageContextKey: "iris.language",
|
||||
ViewLayoutContextKey: "iris.viewLayout",
|
||||
ViewDataContextKey: "iris.viewData",
|
||||
RemoteAddrHeaders: make(map[string]bool),
|
||||
EnableOptimizations: false,
|
||||
Other: make(map[string]interface{}),
|
||||
PostMaxMemory: 32 << 20, // 32MB
|
||||
TranslateFunctionContextKey: "iris.translate",
|
||||
TranslateLangFunctionContextKey: "iris.translateLang",
|
||||
TranslateLanguageContextKey: "iris.language",
|
||||
ViewLayoutContextKey: "iris.viewLayout",
|
||||
ViewDataContextKey: "iris.viewData",
|
||||
RemoteAddrHeaders: make(map[string]bool),
|
||||
EnableOptimizations: false,
|
||||
Other: make(map[string]interface{}),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -68,9 +68,11 @@ type ConfigurationReadOnly interface {
|
|||
GetPostMaxMemory() int64
|
||||
|
||||
// GetTranslateLanguageContextKey returns the configuration's TranslateFunctionContextKey value,
|
||||
// used for i18n.
|
||||
// used for i18n inside templates.
|
||||
GetTranslateFunctionContextKey() string
|
||||
|
||||
// GetTranslateLangFunctionContextKey returns the configuration's TranslateLangFunctionContextKey value,
|
||||
// used for i18n inside templates.
|
||||
GetTranslateLangFunctionContextKey() string
|
||||
// GetTranslateLanguageContextKey returns the configuration's TranslateLanguageContextKey value,
|
||||
// used for i18n.
|
||||
GetTranslateLanguageContextKey() string
|
||||
|
|
|
@ -294,10 +294,16 @@ type Context interface {
|
|||
Values() *memstore.Store
|
||||
// Translate is the i18n (localization) middleware's function,
|
||||
// it calls the Values().Get(ctx.Application().ConfigurationReadOnly().GetTranslateFunctionContextKey())
|
||||
// to execute the translate function and return the localized text value.
|
||||
// to execute the translate function and returns the current localized text value.
|
||||
//
|
||||
// Example: https://github.com/kataras/iris/tree/master/_examples/miscellaneous/i18n
|
||||
Translate(format string, args ...interface{}) string
|
||||
// TranslateLang is the i18n (localization) middleware's function,
|
||||
// it calls the Values().Get(ctx.Application().ConfigurationReadOnly().GetTranslateLangFunctionContextKey())
|
||||
// to execute the translate function and returns the localized text value based on the "lang".
|
||||
//
|
||||
// Example: https://github.com/kataras/iris/tree/master/_examples/miscellaneous/i18n
|
||||
TranslateLang(lang, format string, args ...interface{}) string
|
||||
|
||||
// +------------------------------------------------------------+
|
||||
// | Path, Host, Subdomain, IP, Headers etc... |
|
||||
|
@ -1499,17 +1505,30 @@ func (ctx *context) Values() *memstore.Store {
|
|||
|
||||
// Translate is the i18n (localization) middleware's function,
|
||||
// it calls the Values().Get(ctx.Application().ConfigurationReadOnly().GetTranslateFunctionContextKey())
|
||||
// to execute the translate function and return the localized text value.
|
||||
// to execute the translate function and return the current localized text value.
|
||||
//
|
||||
// Example: https://github.com/kataras/iris/tree/master/_examples/miscellaneous/i18n
|
||||
func (ctx *context) Translate(format string, args ...interface{}) string {
|
||||
if cb, ok := ctx.values.Get(ctx.Application().ConfigurationReadOnly().GetTranslateFunctionContextKey()).(func(format string, args ...interface{}) string); ok {
|
||||
if cb, ok := ctx.values.Get(ctx.Application().ConfigurationReadOnly().GetTranslateFunctionContextKey()).(func(string, ...interface{}) string); ok {
|
||||
return cb(format, args...)
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
// TranslateLang is the i18n (localization) middleware's function,
|
||||
// it calls the Values().Get(ctx.Application().ConfigurationReadOnly().GetTranslateLangFunctionContextKey())
|
||||
// to execute the translate function and returns the localized text value based on the "lang".
|
||||
//
|
||||
// Example: https://github.com/kataras/iris/tree/master/_examples/miscellaneous/i18n
|
||||
func (ctx *context) TranslateLang(lang, format string, args ...interface{}) string {
|
||||
if cb, ok := ctx.values.Get(ctx.Application().ConfigurationReadOnly().GetTranslateLangFunctionContextKey()).(func(string, string, ...interface{}) string); ok {
|
||||
return cb(lang, format, args...)
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
// +------------------------------------------------------------+
|
||||
// | Path, Host, Subdomain, IP, Headers etc... |
|
||||
// +------------------------------------------------------------+
|
||||
|
|
|
@ -397,6 +397,9 @@ func (api *APIBuilder) Handle(method string, relativePath string, handlers ...co
|
|||
|
||||
var route *Route // the last one is returned.
|
||||
for _, route = range routes {
|
||||
if route == nil {
|
||||
break
|
||||
}
|
||||
// global
|
||||
|
||||
route.topLink = api.routes.getRelative(route)
|
||||
|
|
2
doc.go
2
doc.go
|
@ -38,7 +38,7 @@ Source code and other details for the project are available at GitHub:
|
|||
|
||||
Current Version
|
||||
|
||||
12.0.1
|
||||
12.0.2
|
||||
|
||||
Installation
|
||||
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
package i18n
|
||||
|
||||
// Config the i18n options
|
||||
type Config struct {
|
||||
// Default set it if you want a default language
|
||||
//
|
||||
// Checked: Configuration state, not at runtime
|
||||
Default string
|
||||
// URLParameter is the name of the url parameter which the language can be indentified
|
||||
//
|
||||
// Checked: Serving state, runtime
|
||||
URLParameter string
|
||||
// Languages is a map[string]string which the key is the language i81n and the value is the file location
|
||||
//
|
||||
// Example of key is: 'en-US'
|
||||
// Example of value is: './locales/en-US.ini'
|
||||
Languages map[string]string
|
||||
}
|
|
@ -3,6 +3,8 @@
|
|||
package i18n
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
|
@ -10,80 +12,84 @@ import (
|
|||
"github.com/kataras/iris/v12/context"
|
||||
)
|
||||
|
||||
// test file: ../../_examples/miscellaneous/i18n/main_test.go
|
||||
type i18nMiddleware struct {
|
||||
config Config
|
||||
// Config the i18n options.
|
||||
type Config struct {
|
||||
// Default set it if you want a default language.
|
||||
//
|
||||
// Checked: Configuration state, not at runtime.
|
||||
Default string
|
||||
// URLParameter is the name of the url parameter which the language can be indentified,
|
||||
// e.g. "lang" for ?lang=.
|
||||
//
|
||||
// Checked: Serving state, runtime.
|
||||
URLParameter string
|
||||
// PathParameter is the name of the path parameter which the language can be indentified,
|
||||
// e.g. "lang" for "{lang:string}".
|
||||
//
|
||||
// Checked: Serving state, runtime.
|
||||
//
|
||||
// You can set custom handler to set the language too.
|
||||
// Example:
|
||||
// setLangMiddleware := func(ctx iris.Context){
|
||||
// langKey := ctx.Application().ConfigurationReadOnly().GetTranslateLanguageContextKey()
|
||||
// languageByPath := ctx.Params().Get("lang") // see {lang}
|
||||
// ctx.Values().Set(langKey, languageByPath)
|
||||
// ctx.Next()
|
||||
// }
|
||||
// app.Use(setLangMiddleware)
|
||||
// app.Use(theI18nMiddlewareInstance)
|
||||
PathParameter string
|
||||
|
||||
// Languages is a map[string]string which the key is the language i81n and the value is the file location.
|
||||
//
|
||||
// Example of key is: 'en-US'.
|
||||
// Example of value is: './locales/en-US.ini'.
|
||||
Languages map[string]string
|
||||
// Alternatives is a language map which if it's filled,
|
||||
// it tries to associate its keys with a value of "Languages" field when a possible value of "Language" was not present.
|
||||
// Example of
|
||||
// Languages: map[string]string{"en-US": "./locales/en-US.ini"} set
|
||||
// Alternatives: map[string]string{ "en":"en-US", "english": "en-US"}.
|
||||
Alternatives map[string]string
|
||||
|
||||
// If SetCookie is true then it will set the cookie to the language found by URLParameter, PathParameter or by Context's Value's "lang" key.
|
||||
// Defaults to false.
|
||||
SetCookie bool
|
||||
}
|
||||
|
||||
// ServeHTTP serves the request, the actual middleware's job is here
|
||||
func (i *i18nMiddleware) ServeHTTP(ctx context.Context) {
|
||||
wasByCookie := false
|
||||
|
||||
langKey := ctx.Application().ConfigurationReadOnly().GetTranslateLanguageContextKey()
|
||||
language := ctx.Values().GetString(langKey)
|
||||
if language == "" {
|
||||
// try to get by url parameter
|
||||
language = ctx.URLParam(i.config.URLParameter)
|
||||
if language == "" {
|
||||
// then try to take the lang field from the cookie
|
||||
language = ctx.GetCookie(langKey)
|
||||
|
||||
if len(language) > 0 {
|
||||
wasByCookie = true
|
||||
} else {
|
||||
// try to get by the request headers.
|
||||
langHeader := ctx.GetHeader("Accept-Language")
|
||||
if len(langHeader) > 0 {
|
||||
for _, langEntry := range strings.Split(langHeader, ",") {
|
||||
lc := strings.Split(langEntry, ";")[0]
|
||||
if lc, ok := i18n.IsExistSimilar(lc); ok {
|
||||
language = lc
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Exists returns true if the language, or something similar
|
||||
// exists (e.g. en-US maps to en or Alternatives[key] == lang).
|
||||
// it returns the found name and whether it was able to match something.
|
||||
func (c *Config) Exists(lang string) (string, bool) {
|
||||
for k, v := range c.Alternatives {
|
||||
if k == lang {
|
||||
lang = v
|
||||
break
|
||||
}
|
||||
// if it was not taken by the cookie, then set the cookie in order to have it
|
||||
if !wasByCookie {
|
||||
ctx.SetCookieKV(langKey, language)
|
||||
}
|
||||
|
||||
if language == "" {
|
||||
language = i.config.Default
|
||||
}
|
||||
|
||||
ctx.Values().Set(langKey, language)
|
||||
}
|
||||
locale := i18n.Locale{Lang: language}
|
||||
|
||||
// if unexpected language given, the middleware will transtlate to the default language, the language key should be
|
||||
// also this language instead of the user-given
|
||||
if indexLang := locale.Index(); indexLang == -1 {
|
||||
locale.Lang = i.config.Default
|
||||
}
|
||||
|
||||
translateFuncKey := ctx.Application().ConfigurationReadOnly().GetTranslateFunctionContextKey()
|
||||
ctx.Values().Set(translateFuncKey, locale.Tr)
|
||||
ctx.Next()
|
||||
return i18n.IsExistSimilar(lang)
|
||||
}
|
||||
|
||||
// Translate returns the translated word from a context
|
||||
// the second parameter is the key of the world or line inside the .ini file
|
||||
// the third parameter is the '%s' of the world or line inside the .ini file
|
||||
func Translate(ctx context.Context, format string, args ...interface{}) string {
|
||||
return ctx.Translate(format, args...)
|
||||
}
|
||||
|
||||
// New returns a new i18n middleware
|
||||
func New(c Config) context.Handler {
|
||||
func (c *Config) loadLanguages() {
|
||||
if len(c.Languages) == 0 {
|
||||
panic("You cannot use this middleware without set the Languages option, please try again and read the _example.")
|
||||
panic("field Languages is empty")
|
||||
}
|
||||
i := &i18nMiddleware{config: c}
|
||||
|
||||
for k, v := range c.Alternatives {
|
||||
if _, ok := c.Languages[v]; !ok {
|
||||
panic(fmt.Sprintf("language alternative '%s' does not map to a valid language '%s'", k, v))
|
||||
}
|
||||
}
|
||||
|
||||
firstlanguage := ""
|
||||
// load the files
|
||||
for k, langFileOrFiles := range c.Languages {
|
||||
if i18n.IsExist(k) {
|
||||
// if it is already stored through middleware (`New`) then skip it.
|
||||
continue
|
||||
}
|
||||
|
||||
// remove all spaces.
|
||||
langFileOrFiles = strings.Replace(langFileOrFiles, " ", "", -1)
|
||||
// note: if only one, then the first element is the "v".
|
||||
|
@ -93,24 +99,152 @@ func New(c Config) context.Handler {
|
|||
if !strings.HasSuffix(v, ".ini") {
|
||||
v += ".ini"
|
||||
}
|
||||
|
||||
err := i18n.SetMessage(k, v)
|
||||
if err != nil && err != i18n.ErrLangAlreadyExist {
|
||||
panic("Failed to set locale file'" + k + "' Error:" + err.Error())
|
||||
panic(fmt.Sprintf("Failed to set locale file' %s' with error: %v", k, err))
|
||||
}
|
||||
if firstlanguage == "" {
|
||||
firstlanguage = k
|
||||
}
|
||||
}
|
||||
}
|
||||
// if not default language set then set to the first of the i.config.Languages
|
||||
// if not default language set then set to the first of the "Languages".
|
||||
if c.Default == "" {
|
||||
c.Default = firstlanguage
|
||||
}
|
||||
|
||||
i18n.SetDefaultLang(i.config.Default)
|
||||
i18n.SetDefaultLang(c.Default)
|
||||
}
|
||||
|
||||
// test file: ../../_examples/miscellaneous/i18n/main_test.go
|
||||
type i18nMiddleware struct {
|
||||
config Config
|
||||
}
|
||||
|
||||
// New returns a new i18n middleware.
|
||||
func New(c Config) context.Handler {
|
||||
c.loadLanguages()
|
||||
i := &i18nMiddleware{config: c}
|
||||
return i.ServeHTTP
|
||||
}
|
||||
|
||||
// ServeHTTP serves the request, the actual middleware's job is located here.
|
||||
func (i *i18nMiddleware) ServeHTTP(ctx context.Context) {
|
||||
wasByCookie := false
|
||||
|
||||
langKey := ctx.Application().ConfigurationReadOnly().GetTranslateLanguageContextKey()
|
||||
language := ctx.Values().GetString(langKey)
|
||||
if language == "" {
|
||||
// try to get by path parameter
|
||||
if i.config.PathParameter != "" {
|
||||
language = ctx.Params().Get(i.config.PathParameter)
|
||||
}
|
||||
|
||||
if language == "" {
|
||||
// try to get by url parameter
|
||||
language = ctx.URLParam(i.config.URLParameter)
|
||||
|
||||
if language == "" {
|
||||
// then try to take the lang field from the cookie
|
||||
language = ctx.GetCookie(langKey)
|
||||
|
||||
if len(language) > 0 {
|
||||
wasByCookie = true
|
||||
} else {
|
||||
// try to get by the request headers.
|
||||
langHeader := ctx.GetHeader("Accept-Language")
|
||||
if len(langHeader) > 0 {
|
||||
for _, langEntry := range strings.Split(langHeader, ",") {
|
||||
lc := strings.Split(langEntry, ";")[0]
|
||||
if lc, ok := i.config.Exists(lc); ok {
|
||||
language = lc
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// returns the original key of the language and true
|
||||
// when the language, or something similar exists (e.g. en-US maps to en).
|
||||
if lc, ok := i.config.Exists(language); ok {
|
||||
language = lc
|
||||
} else {
|
||||
// if unexpected language given, the middleware will translate to the default language,
|
||||
// the language key should be also this language instead of the user-given.
|
||||
language = i.config.Default
|
||||
}
|
||||
|
||||
// if it was not taken by the cookie, then set the cookie in order to have it.
|
||||
if !wasByCookie && i.config.SetCookie {
|
||||
ctx.SetCookieKV(langKey, language)
|
||||
}
|
||||
|
||||
ctx.Values().Set(langKey, language)
|
||||
|
||||
// Set iris.translate and iris.translateLang functions (they can be passed to templates as they are later on).
|
||||
ctx.Values().Set(ctx.Application().ConfigurationReadOnly().GetTranslateFunctionContextKey(), getTranslateFunction(language))
|
||||
// Note: translate (global) language function input argument should match exactly, case-sensitive and "Alternatives" field is not part of the fetch progress.
|
||||
ctx.Values().Set(ctx.Application().ConfigurationReadOnly().GetTranslateLangFunctionContextKey(), i18n.Tr)
|
||||
|
||||
ctx.Next()
|
||||
}
|
||||
|
||||
func getTranslateFunction(lang string) func(string, ...interface{}) string {
|
||||
return func(format string, args ...interface{}) string {
|
||||
return i18n.Tr(lang, format, args...)
|
||||
}
|
||||
}
|
||||
|
||||
// NewWrapper accepts a Config and returns a new router wrapper.
|
||||
// The result function can be passed on `Application.WrapRouter`.
|
||||
// It compares the path prefix for translated language and
|
||||
// local redirects the requested path with the selected (from the path) language to the router.
|
||||
//
|
||||
// In order this to work as expected, it should be combined with `Application.Use(New)`
|
||||
// which registers the i18n middleware itself.
|
||||
func NewWrapper(c Config) func(http.ResponseWriter, *http.Request, http.HandlerFunc) {
|
||||
c.loadLanguages()
|
||||
|
||||
return func(w http.ResponseWriter, r *http.Request, routerHandler http.HandlerFunc) {
|
||||
path := r.URL.Path[1:]
|
||||
|
||||
if idx := strings.IndexRune(path, '/'); idx > 0 {
|
||||
path = path[:idx]
|
||||
}
|
||||
|
||||
if lang, ok := c.Exists(path); ok {
|
||||
path = r.URL.Path[len(path)+1:]
|
||||
if path == "" {
|
||||
path = "/"
|
||||
}
|
||||
r.RequestURI = path
|
||||
r.URL.Path = path
|
||||
r.Header.Set("Accept-Language", lang)
|
||||
}
|
||||
|
||||
routerHandler(w, r)
|
||||
}
|
||||
}
|
||||
|
||||
// Translate returns the translated word from a context based on the current selected locale.
|
||||
// The second parameter is the key of the world or line inside the .ini file and
|
||||
// the third parameter is the '%s' of the world or line inside the .ini file
|
||||
func Translate(ctx context.Context, format string, args ...interface{}) string {
|
||||
return ctx.Translate(format, args...)
|
||||
}
|
||||
|
||||
// TranslateLang returns the translated word from a context based on the given "lang".
|
||||
// The second parameter is the language key which the word "format" is translated to and
|
||||
// the third parameter is the key of the world or line inside the .ini file and
|
||||
// the forth parameter is the '%s' of the world or line inside the .ini file
|
||||
func TranslateLang(ctx context.Context, lang, format string, args ...interface{}) string {
|
||||
return ctx.TranslateLang(lang, format, args...)
|
||||
}
|
||||
|
||||
// TranslatedMap returns translated map[string]interface{} from i18n structure.
|
||||
func TranslatedMap(ctx context.Context, sourceInterface interface{}) map[string]interface{} {
|
||||
iType := reflect.TypeOf(sourceInterface).Elem()
|
||||
|
|
Loading…
Reference in New Issue
Block a user