1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
|
package i18n
import (
"fmt"
"io/ioutil"
"github.com/nicksnyder/go-i18n/v2/internal"
"github.com/nicksnyder/go-i18n/v2/internal/plural"
"golang.org/x/text/language"
)
// UnmarshalFunc unmarshals data into v.
type UnmarshalFunc = internal.UnmarshalFunc
// Bundle stores a set of messages and pluralization rules.
// Most applications only need a single bundle
// that is initialized early in the application's lifecycle.
type Bundle struct {
// DefaultLanguage is the default language of the bundle.
DefaultLanguage language.Tag
// UnmarshalFuncs is a map of file extensions to UnmarshalFuncs.
UnmarshalFuncs map[string]UnmarshalFunc
messageTemplates map[language.Tag]map[string]*internal.MessageTemplate
pluralRules plural.Rules
tags []language.Tag
matcher language.Matcher
}
func (b *Bundle) init() {
if b.pluralRules == nil {
b.pluralRules = plural.DefaultRules()
}
b.addTag(b.DefaultLanguage)
}
// RegisterUnmarshalFunc registers an UnmarshalFunc for format.
func (b *Bundle) RegisterUnmarshalFunc(format string, unmarshalFunc UnmarshalFunc) {
if b.UnmarshalFuncs == nil {
b.UnmarshalFuncs = make(map[string]UnmarshalFunc)
}
b.UnmarshalFuncs[format] = unmarshalFunc
}
// LoadMessageFile loads the bytes from path
// and then calls ParseMessageFileBytes.
func (b *Bundle) LoadMessageFile(path string) (*MessageFile, error) {
buf, err := ioutil.ReadFile(path)
if err != nil {
return nil, err
}
return b.ParseMessageFileBytes(buf, path)
}
// MustLoadMessageFile is similar to LoadTranslationFile
// except it panics if an error happens.
func (b *Bundle) MustLoadMessageFile(path string) {
if _, err := b.LoadMessageFile(path); err != nil {
panic(err)
}
}
// MessageFile represents a parsed message file.
type MessageFile = internal.MessageFile
// ParseMessageFileBytes parses the bytes in buf to add translations to the bundle.
//
// The format of the file is everything after the last ".".
//
// The language tag of the file is everything after the second to last "." or after the last path separator, but before the format.
func (b *Bundle) ParseMessageFileBytes(buf []byte, path string) (*MessageFile, error) {
messageFile, err := internal.ParseMessageFileBytes(buf, path, b.UnmarshalFuncs)
if err != nil {
return nil, err
}
if err := b.AddMessages(messageFile.Tag, messageFile.Messages...); err != nil {
return nil, err
}
return messageFile, nil
}
// MustParseMessageFileBytes is similar to ParseMessageFileBytes
// except it panics if an error happens.
func (b *Bundle) MustParseMessageFileBytes(buf []byte, path string) {
if _, err := b.ParseMessageFileBytes(buf, path); err != nil {
panic(err)
}
}
// AddMessages adds messages for a language.
// It is useful if your messages are in a format not supported by ParseMessageFileBytes.
func (b *Bundle) AddMessages(tag language.Tag, messages ...*Message) error {
b.init()
pluralRule := b.pluralRules.Rule(tag)
if pluralRule == nil {
return fmt.Errorf("no plural rule registered for %s", tag)
}
if b.messageTemplates == nil {
b.messageTemplates = map[language.Tag]map[string]*internal.MessageTemplate{}
}
if b.messageTemplates[tag] == nil {
b.messageTemplates[tag] = map[string]*internal.MessageTemplate{}
b.addTag(tag)
}
for _, m := range messages {
b.messageTemplates[tag][m.ID] = internal.NewMessageTemplate(m)
}
return nil
}
// MustAddMessages is similar to AddMessages except it panics if an error happens.
func (b *Bundle) MustAddMessages(tag language.Tag, messages ...*Message) {
if err := b.AddMessages(tag, messages...); err != nil {
panic(err)
}
}
func (b *Bundle) addTag(tag language.Tag) {
for _, t := range b.tags {
if t == tag {
// Tag already exists
return
}
}
b.tags = append(b.tags, tag)
b.matcher = language.NewMatcher(b.tags)
}
|