lazydocker/vendor/github.com/nicksnyder/go-i18n/v2/internal/parse.go
2019-05-12 10:32:02 +10:00

112 lines
2.6 KiB
Go

package internal
import (
"encoding/json"
"fmt"
"os"
"golang.org/x/text/language"
)
// UnmarshalFunc unmarshals data into v.
type UnmarshalFunc func(data []byte, v interface{}) error
// MessageFile represents a parsed message file.
type MessageFile struct {
Path string
Tag language.Tag
Format string
Messages []*Message
}
// ParseMessageFileBytes returns the messages parsed from file.
func ParseMessageFileBytes(buf []byte, path string, unmarshalFuncs map[string]UnmarshalFunc) (*MessageFile, error) {
lang, format := parsePath(path)
tag := language.Make(lang)
messageFile := &MessageFile{
Path: path,
Tag: tag,
Format: format,
}
if len(buf) == 0 {
return messageFile, nil
}
unmarshalFunc := unmarshalFuncs[messageFile.Format]
if unmarshalFunc == nil {
if messageFile.Format == "json" {
unmarshalFunc = json.Unmarshal
} else {
return nil, fmt.Errorf("no unmarshaler registered for %s", messageFile.Format)
}
}
var raw interface{}
if err := unmarshalFunc(buf, &raw); err != nil {
return nil, err
}
switch data := raw.(type) {
case map[string]interface{}:
messageFile.Messages = make([]*Message, 0, len(data))
for id, data := range data {
m, err := NewMessage(data)
if err != nil {
return nil, err
}
m.ID = id
messageFile.Messages = append(messageFile.Messages, m)
}
case map[interface{}]interface{}:
messageFile.Messages = make([]*Message, 0, len(data))
for id, data := range data {
strid, ok := id.(string)
if !ok {
return nil, fmt.Errorf("expected key to be string but got %#v", id)
}
m, err := NewMessage(data)
if err != nil {
return nil, err
}
m.ID = strid
messageFile.Messages = append(messageFile.Messages, m)
}
case []interface{}:
// Backward compatibility for v1 file format.
messageFile.Messages = make([]*Message, 0, len(data))
for _, data := range data {
m, err := NewMessage(data)
if err != nil {
return nil, err
}
messageFile.Messages = append(messageFile.Messages, m)
}
default:
return nil, fmt.Errorf("unsupported file format %T", raw)
}
return messageFile, nil
}
func parsePath(path string) (langTag, format string) {
formatStartIdx := -1
for i := len(path) - 1; i >= 0; i-- {
c := path[i]
if os.IsPathSeparator(c) {
if formatStartIdx != -1 {
langTag = path[i+1 : formatStartIdx]
}
return
}
if path[i] == '.' {
if formatStartIdx != -1 {
langTag = path[i+1 : formatStartIdx]
return
}
if formatStartIdx == -1 {
format = path[i+1:]
formatStartIdx = i
}
}
}
if formatStartIdx != -1 {
langTag = path[:formatStartIdx]
}
return
}