parser.go

  1package i18n
  2
  3import (
  4	"encoding/json"
  5	"fmt"
  6)
  7
  8// TranslationFile represents the structure of a JSON translation file.
  9type TranslationFile struct {
 10	Language string                 `json:"language"`
 11	Messages map[string]interface{} `json:"messages"`
 12}
 13
 14// ParseJSON parses a JSON translation file and returns a MessageMap.
 15func ParseJSON(data []byte) (MessageMap, error) {
 16	var file TranslationFile
 17	if err := json.Unmarshal(data, &file); err != nil {
 18		return nil, fmt.Errorf("%w: %w", ErrParseFailed, err)
 19	}
 20
 21	messages := make(MessageMap)
 22	parseNestedMessages("", file.Messages, messages)
 23
 24	return messages, nil
 25}
 26
 27// parseNestedMessages recursively parses nested message structures.
 28// Builds dot-notation keys like "composer.title" from nested objects.
 29func parseNestedMessages(prefix string, data map[string]interface{}, messages MessageMap) {
 30	for key, value := range data {
 31		fullKey := key
 32		if prefix != "" {
 33			fullKey = prefix + "." + key
 34		}
 35
 36		switch v := value.(type) {
 37		case string:
 38			// Simple string message
 39			messages[fullKey] = &Message{
 40				ID:    fullKey,
 41				Other: v,
 42			}
 43
 44		case map[string]interface{}:
 45			// Check if this is a plural form object or nested structure
 46			if isPluralForm(v) {
 47				messages[fullKey] = parsePluralMessage(fullKey, v)
 48			} else {
 49				// Nested structure - recurse
 50				parseNestedMessages(fullKey, v, messages)
 51			}
 52
 53		default:
 54			// Unexpected type - treat as string
 55			messages[fullKey] = &Message{
 56				ID:    fullKey,
 57				Other: fmt.Sprintf("%v", v),
 58			}
 59		}
 60	}
 61}
 62
 63// isPluralForm checks if a map contains plural form keys.
 64func isPluralForm(data map[string]interface{}) bool {
 65	pluralKeys := []string{"zero", "one", "two", "few", "many", "other"}
 66	for _, key := range pluralKeys {
 67		if _, ok := data[key]; ok {
 68			return true
 69		}
 70	}
 71	return false
 72}
 73
 74// parsePluralMessage creates a Message from plural form data.
 75func parsePluralMessage(id string, data map[string]interface{}) *Message {
 76	msg := &Message{ID: id}
 77
 78	if v, ok := data["zero"].(string); ok {
 79		msg.Zero = v
 80	}
 81	if v, ok := data["one"].(string); ok {
 82		msg.One = v
 83	}
 84	if v, ok := data["two"].(string); ok {
 85		msg.Two = v
 86	}
 87	if v, ok := data["few"].(string); ok {
 88		msg.Few = v
 89	}
 90	if v, ok := data["many"].(string); ok {
 91		msg.Many = v
 92	}
 93	if v, ok := data["other"].(string); ok {
 94		msg.Other = v
 95	}
 96	if v, ok := data["description"].(string); ok {
 97		msg.Description = v
 98	}
 99
100	return msg
101}