Comments (17)
I vote for option 2, although we should rename the functions, they are too verbose.
From:
c.SendString(fiberi18n.MustGetMessage(c, "welcome"))
To:
c.SendString(fiberi18n.Get(c, "welcome"))
from contrib.
I've decided to give up appCfg.ctx = ctx
Use ctx.Local
to store configuration information, which not only binds to the ctx, but also avoids using appCfg
globally and reduces the risk of panic.
// New creates a new middleware handler
func New(config ...*Config) fiber.Handler {
appCfg := configDefault(config...)
// init bundle
bundle := i18n.NewBundle(appCfg.DefaultLanguage)
bundle.RegisterUnmarshalFunc(appCfg.FormatBundleFile, appCfg.UnmarshalFunc)
appCfg.bundle = bundle
appCfg.loadMessages().initLocalizerMap()
return func(c *fiber.Ctx) error {
if appCfg.Next != nil && appCfg.Next(c) {
return c.Next()
}
// appCfg.Ctx = c
c.Locals("fiberi18n", appCfg)
return c.Next()
}
}
func GetMessage(ctx *fiber.Ctx, params interface{}) (string, error) {
// lang := appCfg.LangHandler(appCfg.ctx, appCfg.DefaultLanguage.String()
appCfg := ctx.Locals("fiberi18n").(*Config)
lang := appCfg.LangHandler(ctx, appCfg.DefaultLanguage.String())
// ...
}
And I found out that the main cause of the panic is the defaultLangHandler
. Where *fiber.Ctx
is most possibly nil
.
So I think there needs to be a break change to the api, which is clearly a problem with the design I started with
func defaultLangHandler(c *fiber.Ctx, defaultLang string) string {
if c == nil || c.Request() == nil {
return defaultLang
}
var lang string
lang = utils.CopyString(c.Query("lang"))
if lang != "" {
return lang
}
lang = utils.CopyString(c.Get("Accept-Language"))
if lang != "" {
return lang
}
return defaultLang
}
from contrib.
Or just wait for a new version of middleware to be released?
we are currently working on a fix, this will unfortunately take a few days to ensure that this problem is completely solved this time
after that we will publish a new version and you will switch to this one
from contrib.
@Skyenought #594 was not the solution
Can you try to reproduce and fix again
from contrib.
My solution was to change LangHandler signature from:
LangHandler func(ctx *fiber.Ctx, defaultLang string) string
to
LangHandler func(langQuery, langHeader, defaultLang string) string
and to assign langQuery and langHeader before calling c.Next()
func New(config ...*Config) fiber.Handler {
appCfg = configDefault(config...)
// init bundle
bundle := i18n.NewBundle(appCfg.DefaultLanguage)
bundle.RegisterUnmarshalFunc(appCfg.FormatBundleFile, appCfg.UnmarshalFunc)
appCfg.bundle = bundle
appCfg.loadMessages().initLocalizerMap()
return func(c *fiber.Ctx) error {
if appCfg.Next != nil && appCfg.Next(c) {
return c.Next()
}
appCfg.reqHeader = utils.CopyString(c.Get("Accept-Language"))
appCfg.reqQuery = utils.CopyString(c.Query("lang"))
return c.Next()
}
}
I think that this approach is not idiomatic and perfect, but I can make a pr if it's good enough.
from contrib.
@Skyenought
have also just looked at the problem
exactly you need the information of the context and can't cache it, because with global access each one could be used
the right way would be to store the information in the local or to implement another parameter or methodic which takes it
possibility #1 - locals
func main() {
app := fiber.New()
app.Use(
fiberi18n.New(&fiberi18n.Config{
RootPath: "./localize",
AcceptLanguages: []language.Tag{language.Chinese, language.English},
DefaultLanguage: language.Chinese,
}),
)
app.Get("/", func(c *fiber.Ctx) error {
i18n := c.Locals("i18n").(fiberi18n)
return c.SendString(i18n.MustGetMessage("welcome"))
})
log.Fatal(app.Listen(":3000"))
}
possibility #2 - ctx as parameter
func main() {
app := fiber.New()
app.Use(
fiberi18n.New(&fiberi18n.Config{
RootPath: "./localize",
AcceptLanguages: []language.Tag{language.Chinese, language.English},
DefaultLanguage: language.Chinese,
}),
)
app.Get("/", func(c *fiber.Ctx) error {
return c.SendString(fiberi18n.MustGetMessage(c, "welcome")))
})
log.Fatal(app.Listen(":3000"))
}
possibility #3 - wrapper
func main() {
app := fiber.New()
app.Use(
fiberi18n.New(&fiberi18n.Config{
RootPath: "./localize",
AcceptLanguages: []language.Tag{language.Chinese, language.English},
DefaultLanguage: language.Chinese,
}),
)
app.Get("/", func(c *fiber.Ctx) error {
return c.SendString(fiberi18n.withCtx(c).MustGetMessage("welcome")))
})
log.Fatal(app.Listen(":3000"))
}
can you please adjust this so that the error does not occur anymore (i am aware of the breaking change)
from contrib.
@gaby @efectn which one looks best for you?
from contrib.
ok, Any other ideas for improvement?
There are actually two versions of this api, MustGetMessage() string
and GetMessage() (string, error)
.
So it should be changed to MustGet
and Get
?
from contrib.
ok, Any other ideas for improvement?
- Rename
MustGetMessage
toGet()
- Add Fiber Context as param to
Get()
- Rename
appCfg
tocfg
.
Not sure what to do/how to rename GetMessage
. The only difference is that it returns two fields, one of them being Error.
from contrib.
Does it make sense that we return an empty string on failure?
It may make more sense to return the Original string if it can't be translate/or nil
, thoughts? That way we could get rid of the funct returning the Error field, and just log it.
from contrib.
Does it make sense that we return an empty string on failure?
It may make more sense to return the Original string if it can't be translate/or
nil
, thoughts? That way we could get rid of the funct returning the Error field, and just log it.
like this ?
func Get(ctx *fiber.Ctx, params interface{}) string {
appCfg := ctx.Locals("fiberi18n").(*Config)
lang := appCfg.LangHandler(ctx, appCfg.DefaultLanguage.String())
localizer, _ := appCfg.localizerMap.Load(lang)
if localizer == nil {
defaultLang := appCfg.DefaultLanguage.String()
localizer, _ = appCfg.localizerMap.Load(defaultLang)
}
var localizeConfig *i18n.LocalizeConfig
switch paramValue := params.(type) {
case string:
localizeConfig = &i18n.LocalizeConfig{MessageID: paramValue}
case *i18n.LocalizeConfig:
localizeConfig = paramValue
}
message, err := localizer.(*i18n.Localizer).Localize(localizeConfig)
if err != nil {
log.Errorf("i18n.Localize error: %v", err)
return ""
}
return message
}
from contrib.
Does it make sense that we return an empty string on failure?
It may make more sense to return the Original string if it can't be translate/ornil
, thoughts? That way we could get rid of the funct returning the Error field, and just log it.like this ?
func Get(ctx *fiber.Ctx, params interface{}) string { appCfg := ctx.Locals("fiberi18n").(*Config) lang := appCfg.LangHandler(ctx, appCfg.DefaultLanguage.String()) localizer, _ := appCfg.localizerMap.Load(lang) if localizer == nil { defaultLang := appCfg.DefaultLanguage.String() localizer, _ = appCfg.localizerMap.Load(defaultLang) } var localizeConfig *i18n.LocalizeConfig switch paramValue := params.(type) { case string: localizeConfig = &i18n.LocalizeConfig{MessageID: paramValue} case *i18n.LocalizeConfig: localizeConfig = paramValue } message, err := localizer.(*i18n.Localizer).Localize(localizeConfig) if err != nil { log.Errorf("i18n.Localize error: %v", err) return "" } return message }
Yes, only thing i'm not sure is during a failure:
- Return ""
- Return nil
- Return original "message" field.
Thoughts @ReneWerner87 @Skyenought @efectn ?
from contrib.
Two methods would probably be better for the user
The one with the "must" keyword could then always render a string, even in case of error with the original translation
And the other method would be for the users who are interested in error evaluations, there then nil and error
from contrib.
Okay, how about changing the api to MustGet
and Get
?
Or, as with github.com/nicksnyder/go-i18n/v2
, use Localize
and MustLocalize
.
from contrib.
Okay, how about changing the api to
MustGet
andGet
?Or, as with
github.com/nicksnyder/go-i18n/v2
, useLocalize
andMustLocalize
.
That works for me, it's simple
from contrib.
I have finished reading it, so how to solve this problem in the project now?
Or just wait for a new version of middleware to be released?
from contrib.
Or just wait for a new version of middleware to be released?
we are currently working on a fix, this will unfortunately take a few days to ensure that this problem is completely solved this time after that we will publish a new version and you will switch to this one
That's great. I will pay attention to the version update of the current warehouse. Thank you and the development team for your efforts and respect!
from contrib.
Related Issues (20)
- π [Feature]: My (simple) SSEFiber Package HOT 1
- π€ [Question]: Could you mint a new release? HOT 3
- π€ [Question]: Not sure how the socket.io requests are being handled HOT 5
- π [Bug]: Websocket write tcp4 127.0.0.1:8001->127.0.0.1:59510: write: broken pipe HOT 3
- π€ [Question]: websocket.Conn.Locals vs fiber.Ctx.Locals signature difference
- π€ [Question]: How does socketio differentiate between TextMessage and BinaryMessage? HOT 4
- π [Feature]: JWT unsupport fiber v3 HOT 5
- π [Feature]: contrib/swagger.go exposes internal adresses. There should be a possibility to self-host
- π [Bug]: Otelfiber blocks stream writers HOT 1
- π€ [Question]: When use `fiberzap` with `WithContext`, caller maybe not show properly. How do I change itοΌ HOT 3
- π [Bug]: OTeL duplicate and wrong counter metrics are generated infinitely HOT 7
- π€ [Question]: Otelfiber - How to set span status to Error on panic?
- π [Feature]: otelfiber - Propergate tracing headers in outbound response HOT 6
- π [Bug]: Swagger - not test-able (`./swagger.json` file does not exist) HOT 5
- π€ [Question]: is it possible to get the file descriptor from fiber websocket? HOT 1
- π [Bug]: error occored when import github.com/gofiber/contrib/websocket HOT 7
- π [Feature]: Otelfiber allow for manual cancellation of c.UserContext() in otelfiber.Middleware() HOT 1
- π [Bug]: FiberSentry: GetHubFromContext() never returns nil
- π [Feature]: Add golangci-lint
- π€ [Question]: fiberzerolog the banner is not printed. HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
π Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. πππ
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google β€οΈ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from contrib.