@@ -12,6 +12,16 @@ import (
1212//go:embed lang
1313var fs embed.FS
1414
15+ // localeCache stores parsed locale resources keyed by the embedded file path.
16+ var localeCache sync.Map
17+
18+ // localeEntry caches the parsed resources of a locale file.
19+ type localeEntry struct {
20+ once sync.Once
21+ resources map [string ]string
22+ err error
23+ }
24+
1525// Language defines a Language struct.
1626type Language struct {
1727 dir string
@@ -68,20 +78,34 @@ func (lang *Language) SetLocale(locale string) *Language {
6878 }
6979
7080 fileName := fmt .Sprintf ("%s/%s.json" , lang .dir , locale )
71- bs , err := fs .ReadFile (fileName )
72- if err != nil {
73- lang .Error = fmt .Errorf ("%w: %w" , ErrNotExistLocale (fileName ), err )
81+ entryIface , _ := localeCache .LoadOrStore (fileName , new (localeEntry ))
82+ entry := entryIface .(* localeEntry )
83+
84+ entry .once .Do (func () {
85+ bs , err := fs .ReadFile (fileName )
86+ if err != nil {
87+ entry .err = fmt .Errorf ("%w: %w" , ErrNotExistLocale (fileName ), err )
88+ return
89+ }
90+
91+ var resources map [string ]string
92+ if err := json .Unmarshal (bs , & resources ); err != nil {
93+ entry .err = fmt .Errorf ("failed to decode locale file %q: %w" , fileName , err )
94+ return
95+ }
96+ entry .resources = resources
97+ })
98+
99+ if entry .err != nil {
100+ lang .Error = entry .err
74101 return lang
75102 }
76103
77- var resources map [string ]string
78- _ = json .Unmarshal (bs , & resources )
79-
80104 lang .rw .Lock ()
81105 defer lang .rw .Unlock ()
82106
83107 lang .locale = locale
84- lang .resources = resources
108+ lang .resources = entry . resources
85109 return lang
86110}
87111
0 commit comments