GithubHelp home page GithubHelp logo

Comments (17)

gaby avatar gaby commented on August 11, 2024 3

@gaby @efectn which one looks best for you?

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.

Skyenought avatar Skyenought commented on August 11, 2024 1

@ReneWerner87 @KompocikDot

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.

ReneWerner87 avatar ReneWerner87 commented on August 11, 2024 1

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.

ReneWerner87 avatar ReneWerner87 commented on August 11, 2024

@Skyenought #594 was not the solution
Can you try to reproduce and fix again

from contrib.

KompocikDot avatar KompocikDot commented on August 11, 2024

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.

ReneWerner87 avatar ReneWerner87 commented on August 11, 2024

@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.

ReneWerner87 avatar ReneWerner87 commented on August 11, 2024

@gaby @efectn which one looks best for you?

from contrib.

Skyenought avatar Skyenought commented on August 11, 2024

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.

gaby avatar gaby commented on August 11, 2024

ok, Any other ideas for improvement?

  • Rename MustGetMessage to Get()
  • Add Fiber Context as param to Get()
  • Rename appCfg to cfg.

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.

gaby avatar gaby commented on August 11, 2024

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.

Skyenought avatar Skyenought commented on August 11, 2024

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.

gaby avatar gaby commented on August 11, 2024

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
}

Yes, only thing i'm not sure is during a failure:

  • Return ""
  • Return nil
  • Return original "message" field.

Thoughts @ReneWerner87 @Skyenought @efectn ?

from contrib.

ReneWerner87 avatar ReneWerner87 commented on August 11, 2024

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.

Skyenought avatar Skyenought commented on August 11, 2024

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.

gaby avatar gaby commented on August 11, 2024

Okay, how about changing the api to MustGet and Get?

Or, as with github.com/nicksnyder/go-i18n/v2, use Localize and MustLocalize.

That works for me, it's simple

from contrib.

biuaxia avatar biuaxia commented on August 11, 2024

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?

@ReneWerner87 @gaby

from contrib.

biuaxia avatar biuaxia commented on August 11, 2024

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)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.