func recGetMessages(raw interface{}, isMapMessage, isInitialCall bool) ([]*Message, error) {
	var messages []*Message
	var err error
	switch data := raw.(type) {
	case string:
		if isInitialCall {
			return nil, errInvalidTranslationFile
		}
		m, err := NewMessage(data)
		return []*Message{m}, err
	case map[string]interface{}:
		if isMapMessage {
			m, err := NewMessage(data)
			return []*Message{m}, err
		}
		messages = make([]*Message, 0, len(data))
		for id, data := range data {
			messages, err = addChildMessages(id, data, messages)
			if err != nil {
				return nil, err
			}
		}
	case map[interface{}]interface{}:
		if isMapMessage {
			m, err := NewMessage(data)
			return []*Message{m}, err
		}
		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)
			}
			messages, err = addChildMessages(strid, data, messages)
			if err != nil {
				return nil, err
			}
		}
	case []interface{}:
		messages = make([]*Message, 0, len(data))
		for _, data := range data {
			childMessages, err := recGetMessages(data, isMessage(data), false)
			if err != nil {
				return nil, err
			}
			messages = append(messages, childMessages...)
		}
	default:
		return nil, fmt.Errorf("unsupported file format %T", raw)
	}
	return messages, nil
}
recGetMessages looks for translation messages inside "raw" parameter,
scanning nested maps using recursion.
package i18n
import (
	"encoding/json"
	"errors"
	"fmt"
	"os"
	"golang.org/x/text/language"
)
type MessageFile struct {
	Path     string
	Tag      language.Tag
	Format   string
	Messages []*Message
}
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 err error
	var raw interface{}
	if err = unmarshalFunc(buf, &raw); err != nil {
		return nil, err
	}
	if messageFile.Messages, err = recGetMessages(raw, isMessage(raw), true); err != nil {
		return nil, err
	}
	return messageFile, nil
}
const nestedSeparator = "."
var errInvalidTranslationFile = errors.New("invalid translation file, expected key-values, got a single value")