-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathparser.go
More file actions
150 lines (123 loc) · 4.13 KB
/
parser.go
File metadata and controls
150 lines (123 loc) · 4.13 KB
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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
package staticmessages
import (
"errors"
"fmt"
"io"
"unicode"
"unicode/utf8"
"gopkg.in/yaml.v3"
)
var (
ErrYamlNameInvalid = errors.New("yml name invalid")
ErrYamlDefinitionInvalid = errors.New("yml definition is invalid")
)
// Parse parses yml messages from r.
func Parse(name string, r io.Reader) (*Messages, error) {
if len(name) == 0 {
return nil, ErrYamlNameInvalid
}
// Capitalize the first letter of the name.
ru, size := utf8.DecodeRuneInString(name)
name = string(unicode.ToUpper(ru)) + name[size:]
var node yaml.Node
decoder := yaml.NewDecoder(r)
if err := decoder.Decode(&node); err != nil {
return nil, fmt.Errorf("%w: %v", ErrYamlDefinitionInvalid, err)
}
if node.Kind == yaml.DocumentNode {
if len(node.Content) == 0 {
return nil, fmt.Errorf("%w: expected yaml.MappingNode got Document node without content", ErrYamlDefinitionInvalid)
}
if len(node.Content) > 1 {
return nil, fmt.Errorf("%w: expected yaml.MappingNode got Document node with more then 1 child", ErrYamlDefinitionInvalid)
}
node = *node.Content[0]
}
if node.Kind != yaml.MappingNode {
return nil, fmt.Errorf("%w: expected yaml.MappingNode got: %d", ErrYamlDefinitionInvalid, node.Kind)
}
messages := &Messages{
Name: name,
Messages: make([]*LocalizedMessage, 0),
}
// We parse the yaml manually into a yaml.Node to maintain the ordering of the fields as defined in r.
// If we would use a map the ordering is not guaranteed.
//
// The following yaml:
//
// MessageOne:
// default: Hello 1
// MessageTwo:
// default: Hello 2
// nl: Hallo 2
//
// Results into the following items in node.Content:
//
// Type Index Content
// (yaml.ScalarNode) node.Content[0] MessageOne
// (yaml.MappingNode) node.Content[1] default:Hello 1
// (yaml.ScalarNode) node.Content[2] MessageTwo
// (yaml.MappingNode) node.Content[3] default: Hello 2\nnl: Hallo 2
//
// This means we need to make hops in our for loop of 2, hence the i += 2.
for i := 0; (i + 1) < len(node.Content); i += 2 {
identifier := node.Content[i]
spec := node.Content[i+1]
if identifier.Kind != yaml.ScalarNode {
return nil, fmt.Errorf("%w: expected yaml.ScalarNode for node %#v", ErrYamlDefinitionInvalid, identifier)
}
if spec.Kind != yaml.MappingNode {
return nil, fmt.Errorf("%w: expected yaml.MappingNode for node %#v", ErrYamlDefinitionInvalid, identifier)
}
loc, err := parseMessage(identifier.Value, spec)
if err != nil {
return nil, err
}
messages.Messages = append(messages.Messages, loc)
}
return messages, nil
}
func parseMessage(identifier string, spec *yaml.Node) (*LocalizedMessage, error) {
var defaultMessage *Message
translations := make([]*Translation, 0)
var err error
for i := 0; (i + 1) < len(spec.Content); i += 2 {
key := spec.Content[i]
value := spec.Content[i+1]
if key.Kind != yaml.ScalarNode {
return nil, fmt.Errorf("%w: expected yaml.ScalarNode for node %#v", ErrYamlDefinitionInvalid, key)
}
if value.Kind != yaml.ScalarNode {
return nil, fmt.Errorf("%w: expected yaml.ScalarNode for node %#v", ErrYamlDefinitionInvalid, value)
}
if key.Value == "default" {
defaultMessage, err = ParseMessage(value.Value)
if err != nil {
return nil, fmt.Errorf("%w: error parsing node: %#v: %v", ErrYamlDefinitionInvalid, value, err)
}
} else {
translation, err := ParseMessage(value.Value)
if err != nil {
return nil, fmt.Errorf("%w: error parsing node: %#v: %v", ErrYamlDefinitionInvalid, value, err)
}
translations = append(translations, &Translation{
Locale: key.Value,
Message: translation,
})
}
}
if defaultMessage == nil {
return nil, fmt.Errorf("%w: expected default message", ErrYamlDefinitionInvalid)
}
loc, err := NewLocalizedMessage(identifier, defaultMessage)
if err != nil {
return nil, fmt.Errorf("%w: error creating localized message: %v", ErrYamlDefinitionInvalid, err)
}
for _, translation := range translations {
err = loc.AddTranslation(translation.Locale, translation.Message)
if err != nil {
return nil, fmt.Errorf("%w: error adding translation: %v", ErrYamlDefinitionInvalid, err)
}
}
return loc, nil
}