@@ -2,6 +2,7 @@ package internal
22
33import (
44 "encoding/json"
5+ "errors"
56 "fmt"
67 "os"
78
@@ -39,49 +40,105 @@ func ParseMessageFileBytes(buf []byte, path string, unmarshalFuncs map[string]Un
3940 return nil , fmt .Errorf ("no unmarshaler registered for %s" , messageFile .Format )
4041 }
4142 }
43+ var err error
4244 var raw interface {}
43- if err : = unmarshalFunc (buf , & raw ); err != nil {
45+ if err = unmarshalFunc (buf , & raw ); err != nil {
4446 return nil , err
4547 }
48+
49+ if messageFile .Messages , err = recGetMessages (raw , isMessage (raw ), true ); err != nil {
50+ return nil , err
51+ }
52+
53+ return messageFile , nil
54+ }
55+
56+ const nestedSeparator = "."
57+
58+ var errInvalidTranslationFile = errors .New ("invalid translation file, expected key-values, got a single value" )
59+
60+ // recGetMessages looks for translation messages inside "raw" parameter,
61+ // scanning nested maps using recursion.
62+ func recGetMessages (raw interface {}, isMapMessage , isInitialCall bool ) ([]* Message , error ) {
63+ var messages []* Message
64+ var err error
65+
4666 switch data := raw .(type ) {
67+ case string :
68+ if isInitialCall {
69+ return nil , errInvalidTranslationFile
70+ }
71+ m , err := NewMessage (data )
72+ return []* Message {m }, err
73+
4774 case map [string ]interface {}:
48- messageFile .Messages = make ([]* Message , 0 , len (data ))
49- for id , data := range data {
75+ if isMapMessage {
5076 m , err := NewMessage (data )
77+ return []* Message {m }, err
78+ }
79+ messages = make ([]* Message , 0 , len (data ))
80+ for id , data := range data {
81+ // recursively scan map items
82+ messages , err = addChildMessages (id , data , messages )
5183 if err != nil {
5284 return nil , err
5385 }
54- m .ID = id
55- messageFile .Messages = append (messageFile .Messages , m )
5686 }
87+
5788 case map [interface {}]interface {}:
58- messageFile .Messages = make ([]* Message , 0 , len (data ))
89+ if isMapMessage {
90+ m , err := NewMessage (data )
91+ return []* Message {m }, err
92+ }
93+ messages = make ([]* Message , 0 , len (data ))
5994 for id , data := range data {
6095 strid , ok := id .(string )
6196 if ! ok {
6297 return nil , fmt .Errorf ("expected key to be string but got %#v" , id )
6398 }
64- m , err := NewMessage (data )
99+ // recursively scan map items
100+ messages , err = addChildMessages (strid , data , messages )
65101 if err != nil {
66102 return nil , err
67103 }
68- m .ID = strid
69- messageFile .Messages = append (messageFile .Messages , m )
70104 }
105+
71106 case []interface {}:
72107 // Backward compatibility for v1 file format.
73- messageFile . Messages = make ([]* Message , 0 , len (data ))
108+ messages = make ([]* Message , 0 , len (data ))
74109 for _ , data := range data {
75- m , err := NewMessage (data )
110+ // recursively scan slice items
111+ childMessages , err := recGetMessages (data , isMessage (data ), false )
76112 if err != nil {
77113 return nil , err
78114 }
79- messageFile . Messages = append (messageFile . Messages , m )
115+ messages = append (messages , childMessages ... )
80116 }
117+
81118 default :
82119 return nil , fmt .Errorf ("unsupported file format %T" , raw )
83120 }
84- return messageFile , nil
121+
122+ return messages , nil
123+ }
124+
125+ func addChildMessages (id string , data interface {}, messages []* Message ) ([]* Message , error ) {
126+ isChildMessage := isMessage (data )
127+ childMessages , err := recGetMessages (data , isChildMessage , false )
128+ if err != nil {
129+ return nil , err
130+ }
131+ for _ , m := range childMessages {
132+ if isChildMessage {
133+ if m .ID == "" {
134+ m .ID = id // start with innermost key
135+ }
136+ } else {
137+ m .ID = id + nestedSeparator + m .ID // update ID with each nested key on the way
138+ }
139+ messages = append (messages , m )
140+ }
141+ return messages , nil
85142}
86143
87144func parsePath (path string ) (langTag , format string ) {
0 commit comments