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}