From 5c674a045f46302e862539ab2ed0e537a180f27a Mon Sep 17 00:00:00 2001 From: Skyenought <1808644906@qq.com> Date: Tue, 16 May 2023 19:38:45 +0800 Subject: [PATCH 1/2] fix fiberi18n error on concurrent requests --- fiberi18n/config.go | 29 +++++++++++--------- fiberi18n/i18n.go | 67 +++++++++++++++++++++++++++------------------ 2 files changed, 57 insertions(+), 39 deletions(-) diff --git a/fiberi18n/config.go b/fiberi18n/config.go index a3c7b283..1906a90d 100644 --- a/fiberi18n/config.go +++ b/fiberi18n/config.go @@ -72,20 +72,23 @@ var ConfigDefault = &Config{ FormatBundleFile: "yaml", UnmarshalFunc: yaml.Unmarshal, Loader: LoaderFunc(os.ReadFile), - LangHandler: func(c *fiber.Ctx, defaultLang string) string { - if c == nil { - return defaultLang - } - lang := c.Get("Accept-Language") - if lang != "" { - return lang - } - lang = c.Query("lang") - if lang == "" { - return defaultLang - } + LangHandler: defaultLangHandler, +} + +func defaultLangHandler(c *fiber.Ctx, defaultLang string) string { + var lang string + lang = c.Query("lang") + if lang != "" { + return lang + } + + lang = c.Get("Accept-Language") + if lang != "" { return lang - }, + } + + return defaultLang + } func configDefault(config ...*Config) *Config { diff --git a/fiberi18n/i18n.go b/fiberi18n/i18n.go index 44026ef8..ca5b4164 100644 --- a/fiberi18n/i18n.go +++ b/fiberi18n/i18n.go @@ -13,44 +13,59 @@ var appCfg *Config // New creates a new middleware handler func New(config ...*Config) fiber.Handler { appCfg = configDefault(config...) + appCfg.bundle = initBundle() + loadMessages() + appCfg.localizerMap = initLocalizerMap() + + return func(c *fiber.Ctx) error { + if appCfg.Next != nil && appCfg.Next(c) { + return c.Next() + } + appCfg.ctx = c + return c.Next() + } +} + +func initBundle() *i18n.Bundle { bundle := i18n.NewBundle(appCfg.DefaultLanguage) bundle.RegisterUnmarshalFunc(appCfg.FormatBundleFile, appCfg.UnmarshalFunc) - appCfg.bundle = bundle + return bundle +} + +func loadMessage(filepath string) { + buf, err := appCfg.Loader.LoadMessage(filepath) + if err != nil { + panic(err) + } + if _, err := appCfg.bundle.ParseMessageFileBytes(buf, filepath); err != nil { + panic(err) + } +} + +func loadMessages() { for _, lang := range appCfg.AcceptLanguages { bundleFile := fmt.Sprintf("%s.%s", lang.String(), appCfg.FormatBundleFile) filepath := path.Join(appCfg.RootPath, bundleFile) - buf, err := appCfg.Loader.LoadMessage(filepath) - if err != nil { - panic(err) - } - if _, err := appCfg.bundle.ParseMessageFileBytes(buf, filepath); err != nil { - panic(err) - } + loadMessage(filepath) } +} - return func(c *fiber.Ctx) error { - if appCfg.Next != nil && appCfg.Next(c) { - return c.Next() - } - - appCfg.ctx = c - appCfg.localizerMap = map[string]*i18n.Localizer{} - for _, lang := range appCfg.AcceptLanguages { - s := lang.String() - appCfg.localizerMap[s] = i18n.NewLocalizer(appCfg.bundle, s) - } - - // dataPool.Put(appCfg) +func initLocalizerMap() map[string]*i18n.Localizer { + localizerMap := map[string]*i18n.Localizer{} - lang := appCfg.DefaultLanguage.String() - if _, ok := appCfg.localizerMap[lang]; !ok { - appCfg.localizerMap[lang] = i18n.NewLocalizer(appCfg.bundle, lang) - } + for _, lang := range appCfg.AcceptLanguages { + s := lang.String() + localizerMap[s] = i18n.NewLocalizer(appCfg.bundle, s) + } - return c.Next() + lang := appCfg.DefaultLanguage.String() + if _, ok := localizerMap[lang]; !ok { + localizerMap[lang] = i18n.NewLocalizer(appCfg.bundle, lang) } + + return localizerMap } /* From 9b76010d2c68692c59279a88a9b1a8e972dff25b Mon Sep 17 00:00:00 2001 From: Skyenought <1808644906@qq.com> Date: Wed, 17 May 2023 14:06:37 +0800 Subject: [PATCH 2/2] add parallel unittest for fiberi18n --- fiberi18n/i18n_test.go | 47 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/fiberi18n/i18n_test.go b/fiberi18n/i18n_test.go index 5711b947..ca442bdf 100644 --- a/fiberi18n/i18n_test.go +++ b/fiberi18n/i18n_test.go @@ -116,3 +116,50 @@ func TestI18nZH(t *testing.T) { }) } } + +func TestParallelI18n(t *testing.T) { + type args struct { + lang language.Tag + name string + } + tests := []struct { + name string + args args + want string + }{ + { + name: "hello world", + args: args{ + name: "", + lang: language.Chinese, + }, + want: "你好", + }, + { + name: "hello alex", + args: args{ + name: "alex", + lang: language.Chinese, + }, + want: "你好 alex", + }, + { + name: "hello peter", + args: args{ + name: "peter", + lang: language.English, + }, + want: "hello peter", + }, + } + t.Parallel() + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := makeRequest(tt.args.lang, tt.args.name) + utils.AssertEqual(t, err, nil) + body, err := io.ReadAll(got.Body) + utils.AssertEqual(t, err, nil) + utils.AssertEqual(t, tt.want, string(body)) + }) + } +}