diff --git a/i18n/bundle_test.go b/i18n/bundle_test.go index 99706623..37f0cab1 100644 --- a/i18n/bundle_test.go +++ b/i18n/bundle_test.go @@ -30,6 +30,8 @@ var everythingMessage = MustNewMessage(map[string]string{ "few": "few translation", "many": "many translation", "other": "other translation", + "leftDelim": "<<", + "rightDelim": ">>", }) func TestConcurrentAccess(t *testing.T) { @@ -113,7 +115,9 @@ func TestJSON(t *testing.T) { "two": "two translation", "few": "few translation", "many": "many translation", - "other": "other translation" + "other": "other translation", + "leftDelim": "<<", + "rightDelim": ">>" } }`), "en-US.json") @@ -143,6 +147,8 @@ everything: few: few translation many: many translation other: other translation + leftDelim: "<<" + rightDelim: ">>" `), "en-US.yaml") expectMessage(t, bundle, language.AmericanEnglish, "simple", simpleMessage) @@ -171,6 +177,8 @@ everything: few: few translation many: many translation other: other translation + leftDelim: "<<" + rightDelmin: ">>" garbage: something description: translation @@ -212,6 +220,8 @@ two = "two translation" few = "few translation" many = "many translation" other = "other translation" +leftDelim = "<<" +rightDelim = ">>" `), "en-US.toml") expectMessage(t, bundle, language.AmericanEnglish, "simple", simpleMessage) @@ -241,9 +251,7 @@ func TestV1Format(t *testing.T) { `), "en-US.json") expectMessage(t, bundle, language.AmericanEnglish, "simple", simpleMessage) - e := *everythingMessage - e.Description = "" - expectMessage(t, bundle, language.AmericanEnglish, "everything", &e) + expectMessage(t, bundle, language.AmericanEnglish, "everything", newV1EverythingMessage()) } func TestV1FlatFormat(t *testing.T) { @@ -264,15 +272,21 @@ func TestV1FlatFormat(t *testing.T) { `), "en-US.json") expectMessage(t, bundle, language.AmericanEnglish, "simple", simpleMessage) - e := *everythingMessage - e.Description = "" - expectMessage(t, bundle, language.AmericanEnglish, "everything", &e) + expectMessage(t, bundle, language.AmericanEnglish, "everything", newV1EverythingMessage()) } func expectMessage(t *testing.T, bundle *Bundle, tag language.Tag, messageID string, message *Message) { expected := NewMessageTemplate(message) actual := bundle.messageTemplates[tag][messageID] if !reflect.DeepEqual(actual, expected) { - t.Errorf("bundle.MessageTemplates[%q][%q] = %#v; want %#v", tag, messageID, actual, expected) + t.Errorf("bundle.MessageTemplates[%q][%q]\ngot %#v\nwant %#v", tag, messageID, actual, expected) } } + +func newV1EverythingMessage() *Message { + e := *everythingMessage + e.Description = "" + e.LeftDelim = "" + e.RightDelim = "" + return &e +} diff --git a/i18n/message.go b/i18n/message.go index 30587693..7af4c9b5 100644 --- a/i18n/message.go +++ b/i18n/message.go @@ -192,7 +192,8 @@ var reservedKeys = map[string]struct{}{ } func isReserved(key string, val any) bool { - if _, ok := reservedKeys[key]; ok { + lk := strings.ToLower(key) + if _, ok := reservedKeys[lk]; ok { if key == "translation" { return true } @@ -214,62 +215,44 @@ func isMessage(v interface{}) (bool, error) { case nil, string: return true, nil case map[string]interface{}: - reservedKeyCount := 0 - for key := range reservedKeys { - val, ok := data[key] - if ok && isReserved(key, val) { - reservedKeyCount++ + reservedKeys := make([]string, 0, len(reservedKeys)) + unreservedKeys := make([]string, 0, len(data)) + for k, v := range data { + if isReserved(k, v) { + reservedKeys = append(reservedKeys, k) + } else { + unreservedKeys = append(unreservedKeys, k) } } - if reservedKeyCount == 0 { - return false, nil - } - if len(data) > reservedKeyCount { - reservedKeys := make([]string, 0, reservedKeyCount) - unreservedKeys := make([]string, 0, len(data)-reservedKeyCount) - for k, v := range data { - if isReserved(k, v) { - reservedKeys = append(reservedKeys, k) - } else { - unreservedKeys = append(unreservedKeys, k) - } - } + hasReservedKeys := len(reservedKeys) > 0 + if hasReservedKeys && len(unreservedKeys) > 0 { return false, &mixedKeysError{ reservedKeys: reservedKeys, unreservedKeys: unreservedKeys, } } - return true, nil + return hasReservedKeys, nil case map[interface{}]interface{}: - reservedKeyCount := 0 - for key := range reservedKeys { - val, ok := data[key] - if ok && isReserved(key, val) { - reservedKeyCount++ + reservedKeys := make([]string, 0, len(reservedKeys)) + unreservedKeys := make([]string, 0, len(data)) + for key, v := range data { + k, ok := key.(string) + if !ok { + unreservedKeys = append(unreservedKeys, fmt.Sprintf("%+v", key)) + } else if isReserved(k, v) { + reservedKeys = append(reservedKeys, k) + } else { + unreservedKeys = append(unreservedKeys, k) } } - if reservedKeyCount == 0 { - return false, nil - } - if len(data) > reservedKeyCount { - reservedKeys := make([]string, 0, reservedKeyCount) - unreservedKeys := make([]string, 0, len(data)-reservedKeyCount) - for key, v := range data { - k, ok := key.(string) - if !ok { - unreservedKeys = append(unreservedKeys, fmt.Sprintf("%+v", key)) - } else if isReserved(k, v) { - reservedKeys = append(reservedKeys, k) - } else { - unreservedKeys = append(unreservedKeys, k) - } - } + hasReservedKeys := len(reservedKeys) > 0 + if hasReservedKeys && len(unreservedKeys) > 0 { return false, &mixedKeysError{ reservedKeys: reservedKeys, unreservedKeys: unreservedKeys, } } - return true, nil + return hasReservedKeys, nil } return false, nil }