feat(l10n): adjust translate entity
Signed-off-by: jkoberg <jkoberg@owncloud.com>
This commit is contained in:
+145
-143
@@ -16,8 +16,13 @@ import (
|
||||
micrometadata "go-micro.dev/v4/metadata"
|
||||
)
|
||||
|
||||
// HeaderAcceptLanguage is the header key for the accept-language header
|
||||
var HeaderAcceptLanguage = "Accept-Language"
|
||||
var (
|
||||
// HeaderAcceptLanguage is the header key for the accept-language header
|
||||
HeaderAcceptLanguage = "Accept-Language"
|
||||
|
||||
// ErrUnsupportedType is returned when the type is not supported
|
||||
ErrUnsupportedType = errors.New("unsupported type")
|
||||
)
|
||||
|
||||
// Template marks a string as translatable
|
||||
func Template(s string) string { return s }
|
||||
@@ -54,48 +59,101 @@ func (t Translator) Translate(str, locale string) string {
|
||||
return t.Locale(locale).Get(str)
|
||||
}
|
||||
|
||||
type structs func() []any
|
||||
type maps func() []any
|
||||
type each func() []any
|
||||
type field func() string
|
||||
// Locale returns the gotext.Locale, use `.Get` method to translate strings
|
||||
func (t Translator) Locale(locale string) *gotext.Locale {
|
||||
l := gotext.NewLocaleFS(locale, t.fs)
|
||||
l.AddDomain(t.domain) // make domain configurable only if needed
|
||||
if locale != "en" && len(l.GetTranslations()) == 0 {
|
||||
l = gotext.NewLocaleFS(t.defaultLocale, t.fs)
|
||||
l.AddDomain(t.domain) // make domain configurable only if needed
|
||||
}
|
||||
return l
|
||||
}
|
||||
|
||||
// TranslateEntity translates a slice, array or struct
|
||||
func (t Translator) TranslateEntity(locale string, entity any, opts ...TranslateOption) error {
|
||||
return TranslateEntity(t.Locale(locale).Get, entity, opts...)
|
||||
}
|
||||
|
||||
// MustGetUserLocale returns the locale the user wants to use, omitting errors
|
||||
func MustGetUserLocale(ctx context.Context, userID string, preferedLang string, vc settingssvc.ValueService) string {
|
||||
if preferedLang != "" {
|
||||
return preferedLang
|
||||
}
|
||||
|
||||
locale, _ := GetUserLocale(ctx, userID, vc)
|
||||
return locale
|
||||
}
|
||||
|
||||
// GetUserLocale returns the locale of the user
|
||||
func GetUserLocale(ctx context.Context, userID string, vc settingssvc.ValueService) (string, error) {
|
||||
resp, err := vc.GetValueByUniqueIdentifiers(
|
||||
micrometadata.Set(ctx, middleware.AccountID, userID),
|
||||
&settingssvc.GetValueByUniqueIdentifiersRequest{
|
||||
AccountUuid: userID,
|
||||
SettingId: defaults.SettingUUIDProfileLanguage,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
val := resp.GetValue().GetValue().GetListValue().GetValues()
|
||||
if len(val) == 0 {
|
||||
return "", errors.New("no language setting found")
|
||||
}
|
||||
return val[0].GetStringValue(), nil
|
||||
}
|
||||
|
||||
// TranslateOption is used to specify fields in structs or slices to translate
|
||||
type TranslateOption func() (string, FieldType, []TranslateOption)
|
||||
|
||||
// FieldType is used to specify the type of field to translate
|
||||
type FieldType int
|
||||
|
||||
const (
|
||||
// FieldTypeString is a string field
|
||||
FieldTypeString FieldType = iota
|
||||
// FieldTypeStruct is a struct field
|
||||
FieldTypeStruct
|
||||
// FieldTypeIterable is a slice or array field
|
||||
FieldTypeIterable
|
||||
// FieldTypeMap is a map field
|
||||
FieldTypeMap
|
||||
)
|
||||
|
||||
// TranslateField function provides the generic way to translate the necessary field in composite entities.
|
||||
func TranslateField(fieldName string) field {
|
||||
return func() string {
|
||||
return fieldName
|
||||
func TranslateField(fieldName string) TranslateOption {
|
||||
return func() (string, FieldType, []TranslateOption) {
|
||||
return fieldName, FieldTypeString, nil
|
||||
}
|
||||
}
|
||||
|
||||
// TranslateStruct function provides the generic way to translate the nested fields in composite entities.
|
||||
// When the TranslateStruct function is used right after the TranslateEntity, the first argument must be the entity itself,
|
||||
// the rest of the arguments are the fields to translate or nested function.
|
||||
func TranslateStruct(args ...any) structs {
|
||||
return func() []any {
|
||||
return args
|
||||
func TranslateStruct(fieldName string, args ...TranslateOption) TranslateOption {
|
||||
return func() (string, FieldType, []TranslateOption) {
|
||||
return fieldName, FieldTypeStruct, args
|
||||
}
|
||||
}
|
||||
|
||||
// TranslateEach function provides the generic way to translate the necessary fields in slices or nested entities.
|
||||
func TranslateEach(fieldName string, args ...TranslateOption) TranslateOption {
|
||||
return func() (string, FieldType, []TranslateOption) {
|
||||
return fieldName, FieldTypeIterable, args
|
||||
}
|
||||
}
|
||||
|
||||
// TranslateMap function provides the generic way to translate the necessary fields in maps.
|
||||
// It's not implemented yet.
|
||||
func TranslateMap(args ...any) maps {
|
||||
return func() []any {
|
||||
return args
|
||||
}
|
||||
}
|
||||
|
||||
// TranslateEach function provides the generic way to translate the necessary fields in slices or nested entities.
|
||||
// When the TranslateEach function is used right after the TranslateEntity, the first argument must be the slice itself,
|
||||
// the rest of the arguments are nested function or no arguments if the slice contains only strings.
|
||||
func TranslateEach(args ...any) each {
|
||||
return func() []any {
|
||||
return args
|
||||
func TranslateMap(fieldName string, args ...TranslateOption) TranslateOption {
|
||||
return func() (string, FieldType, []TranslateOption) {
|
||||
return fieldName, FieldTypeMap, args
|
||||
}
|
||||
}
|
||||
|
||||
// TranslateEntity function provides the generic way to translate the necessary fields in composite entities.
|
||||
// The function takes TranslateLocation function and entity with fields to translate.
|
||||
// The function takes a translation function that has the locale already set, see Translator.TranslateEntity
|
||||
// The function also takes the entity with fields to translate.
|
||||
// The function supports nested structs and slices of structs.
|
||||
// Depending on entity type it should be wrapped to the appropriate function TranslateStruct, TranslateEach, TranslateField.
|
||||
//
|
||||
// type InnerStruct struct {
|
||||
// Description string
|
||||
@@ -118,56 +176,48 @@ func TranslateEach(args ...any) each {
|
||||
// },
|
||||
// }
|
||||
// tr := l10n_pkg.NewTranslateLocation(loc, "en")
|
||||
// err := l10n.TranslateEntity(tr,
|
||||
// l10n.TranslateStruct(s,
|
||||
// l10n.TranslateEach("StructList",
|
||||
// l10n.TranslateField("Description"),
|
||||
// l10n.TranslateField("DisplayName"))),
|
||||
// )
|
||||
func TranslateEntity(tr func(string, ...any) string, arg any) error {
|
||||
switch a := arg.(type) {
|
||||
case structs:
|
||||
args := a()
|
||||
if len(args) < 2 {
|
||||
return fmt.Errorf("the TranslateStruct function expects at least 2 arguments, sructure and fields to translate")
|
||||
}
|
||||
entity := args[0]
|
||||
value := reflect.ValueOf(entity)
|
||||
// err := l10n.TranslateEntity(tr, s,
|
||||
// l10n.TranslateEach("StructList",
|
||||
// l10n.TranslateField("Description"),
|
||||
// l10n.TranslateField("DisplayName"),
|
||||
// ))
|
||||
func TranslateEntity(tr func(string, ...any) string, entity any, opts ...TranslateOption) error {
|
||||
value := reflect.ValueOf(entity)
|
||||
|
||||
value, ok := cleanValue(value)
|
||||
if !ok {
|
||||
return errors.New("entity is not valid")
|
||||
}
|
||||
|
||||
switch value.Kind() {
|
||||
case reflect.Struct:
|
||||
if !isStruct(value) {
|
||||
return fmt.Errorf("the root entity must be a struct, got %v", value.Kind())
|
||||
}
|
||||
rangeOverArgs(tr, value, args[1:]...)
|
||||
rangeOverArgs(tr, value, opts...)
|
||||
return nil
|
||||
case each:
|
||||
args := a()
|
||||
if len(args) < 1 {
|
||||
return fmt.Errorf("the translateEach function expects at least 1 argument, slice")
|
||||
}
|
||||
entity := args[0]
|
||||
value := reflect.ValueOf(entity)
|
||||
if len(args) > 1 {
|
||||
translateEach(tr, value, args[1:]...)
|
||||
case reflect.Slice, reflect.Array:
|
||||
if len(opts) > 0 {
|
||||
translateEach(tr, value, opts...)
|
||||
} else {
|
||||
translateEach(tr, value)
|
||||
}
|
||||
return nil
|
||||
case maps:
|
||||
case reflect.Map:
|
||||
// TODO implement
|
||||
case reflect.String:
|
||||
translateField(tr, value)
|
||||
return nil
|
||||
}
|
||||
return ErrUnsupportedType
|
||||
}
|
||||
|
||||
func translateEach(tr func(string, ...any) string, value reflect.Value, args ...any) {
|
||||
// Indirect through pointers and interfaces
|
||||
if value.Kind() == reflect.Ptr || value.Kind() == reflect.Interface {
|
||||
if value.IsNil() {
|
||||
return
|
||||
}
|
||||
value = value.Elem()
|
||||
}
|
||||
if !value.IsValid() {
|
||||
func translateEach(tr func(string, ...any) string, value reflect.Value, args ...TranslateOption) {
|
||||
value, ok := cleanValue(value)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
switch value.Kind() {
|
||||
case reflect.Array, reflect.Slice:
|
||||
for i := 0; i < value.Len(); i++ {
|
||||
@@ -185,54 +235,37 @@ func translateEach(tr func(string, ...any) string, value reflect.Value, args ...
|
||||
}
|
||||
}
|
||||
|
||||
func rangeOverArgs(tr func(string, ...any) string, value reflect.Value, args ...any) {
|
||||
// Indirect through pointers and interfaces
|
||||
if value.Kind() == reflect.Ptr || value.Kind() == reflect.Interface {
|
||||
if value.IsNil() {
|
||||
return
|
||||
}
|
||||
value = value.Elem()
|
||||
}
|
||||
if !value.IsValid() {
|
||||
func rangeOverArgs(tr func(string, ...any) string, value reflect.Value, args ...TranslateOption) {
|
||||
value, ok := cleanValue(value)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
for _, arg := range args {
|
||||
switch a := arg.(type) {
|
||||
case field:
|
||||
fieldName := a()
|
||||
fieldName, fieldType, opts := arg()
|
||||
|
||||
switch fieldType {
|
||||
case FieldTypeString:
|
||||
// exported field
|
||||
f := value.FieldByName(fieldName)
|
||||
translateField(tr, f)
|
||||
case structs:
|
||||
args := a()
|
||||
if len(args) > 2 {
|
||||
if fieldName, ok := args[0].(string); ok {
|
||||
// exported field
|
||||
innerValue := value.FieldByName(fieldName)
|
||||
if !innerValue.IsValid() {
|
||||
return
|
||||
}
|
||||
if isStruct(innerValue) {
|
||||
rangeOverArgs(tr, innerValue, args[1:]...)
|
||||
return
|
||||
}
|
||||
}
|
||||
case FieldTypeStruct:
|
||||
// exported field
|
||||
innerValue := value.FieldByName(fieldName)
|
||||
if !innerValue.IsValid() || !isStruct(innerValue) {
|
||||
return
|
||||
}
|
||||
case each:
|
||||
args := a()
|
||||
if len(args) > 2 {
|
||||
if fieldName, ok := args[0].(string); ok {
|
||||
// exported field
|
||||
innerValue := value.FieldByName(fieldName)
|
||||
if !innerValue.IsValid() {
|
||||
return
|
||||
}
|
||||
switch innerValue.Kind() {
|
||||
case reflect.Array, reflect.Slice:
|
||||
translateEach(tr, innerValue, args[1:]...)
|
||||
}
|
||||
}
|
||||
rangeOverArgs(tr, innerValue, opts...)
|
||||
case FieldTypeIterable:
|
||||
// exported field
|
||||
innerValue := value.FieldByName(fieldName)
|
||||
if !innerValue.IsValid() {
|
||||
return
|
||||
}
|
||||
if kind := innerValue.Kind(); kind != reflect.Array && kind != reflect.Slice {
|
||||
return
|
||||
}
|
||||
translateEach(tr, innerValue, opts...)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -268,46 +301,15 @@ func isStruct(r reflect.Value) bool {
|
||||
return r.Kind() == reflect.Struct
|
||||
}
|
||||
|
||||
var (
|
||||
ErrUnsupportedType = errors.New("unsupported type")
|
||||
)
|
||||
|
||||
// Locale returns the gotext.Locale, use `.Get` method to translate strings
|
||||
func (t Translator) Locale(locale string) *gotext.Locale {
|
||||
l := gotext.NewLocaleFS(locale, t.fs)
|
||||
l.AddDomain(t.domain) // make domain configurable only if needed
|
||||
if locale != "en" && len(l.GetTranslations()) == 0 {
|
||||
l = gotext.NewLocaleFS(t.defaultLocale, t.fs)
|
||||
l.AddDomain(t.domain) // make domain configurable only if needed
|
||||
func cleanValue(v reflect.Value) (reflect.Value, bool) {
|
||||
if v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface {
|
||||
if v.IsNil() {
|
||||
return v, false
|
||||
}
|
||||
v = v.Elem()
|
||||
}
|
||||
return l
|
||||
}
|
||||
|
||||
// MustGetUserLocale returns the locale the user wants to use, omitting errors
|
||||
func MustGetUserLocale(ctx context.Context, userID string, preferedLang string, vc settingssvc.ValueService) string {
|
||||
if preferedLang != "" {
|
||||
return preferedLang
|
||||
if !v.IsValid() {
|
||||
return v, false
|
||||
}
|
||||
|
||||
locale, _ := GetUserLocale(ctx, userID, vc)
|
||||
return locale
|
||||
}
|
||||
|
||||
// GetUserLocale returns the locale of the user
|
||||
func GetUserLocale(ctx context.Context, userID string, vc settingssvc.ValueService) (string, error) {
|
||||
resp, err := vc.GetValueByUniqueIdentifiers(
|
||||
micrometadata.Set(ctx, middleware.AccountID, userID),
|
||||
&settingssvc.GetValueByUniqueIdentifiersRequest{
|
||||
AccountUuid: userID,
|
||||
SettingId: defaults.SettingUUIDProfileLanguage,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
val := resp.GetValue().GetValue().GetListValue().GetValues()
|
||||
if len(val) == 0 {
|
||||
return "", errors.New("no language setting found")
|
||||
}
|
||||
return val[0].GetStringValue(), nil
|
||||
return v, true
|
||||
}
|
||||
|
||||
+105
-97
@@ -29,31 +29,33 @@ func TestTranslateStruct(t *testing.T) {
|
||||
}
|
||||
|
||||
type args struct {
|
||||
structPtr interface{}
|
||||
structPtr []TranslateOption
|
||||
//request []any
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
entity any
|
||||
args args
|
||||
expected any
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "top level slice of struct",
|
||||
entity: []*InnerStruct{
|
||||
{
|
||||
Description: "inner 1",
|
||||
DisplayName: toStrPointer("innerDisplayName 1"),
|
||||
},
|
||||
{
|
||||
Description: "inner 2",
|
||||
DisplayName: toStrPointer("innerDisplayName 2"),
|
||||
},
|
||||
},
|
||||
args: args{
|
||||
structPtr: TranslateEach(
|
||||
[]*InnerStruct{
|
||||
{
|
||||
Description: "inner 1",
|
||||
DisplayName: toStrPointer("innerDisplayName 1"),
|
||||
},
|
||||
{
|
||||
Description: "inner 2",
|
||||
DisplayName: toStrPointer("innerDisplayName 2"),
|
||||
},
|
||||
},
|
||||
structPtr: []TranslateOption{
|
||||
TranslateField("Description"),
|
||||
TranslateField("DisplayName")),
|
||||
TranslateField("DisplayName"),
|
||||
},
|
||||
},
|
||||
expected: []*InnerStruct{
|
||||
{
|
||||
@@ -68,13 +70,11 @@ func TestTranslateStruct(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "top level slice of string",
|
||||
args: args{
|
||||
structPtr: TranslateEach(
|
||||
[]string{
|
||||
"inner 1",
|
||||
"inner 2",
|
||||
}),
|
||||
entity: []string{
|
||||
"inner 1",
|
||||
"inner 2",
|
||||
},
|
||||
args: args{},
|
||||
expected: []string{
|
||||
"new Inner 1",
|
||||
"new Inner 2",
|
||||
@@ -82,27 +82,29 @@ func TestTranslateStruct(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "top level slice of struct",
|
||||
args: args{
|
||||
structPtr: TranslateEach(
|
||||
[]*TopLevelStruct{
|
||||
{
|
||||
Description: "inner 1",
|
||||
DisplayName: toStrPointer("innerDisplayName 1"),
|
||||
SubStruct: &InnerStruct{
|
||||
Description: "inner",
|
||||
DisplayName: toStrPointer("innerDisplayName"),
|
||||
},
|
||||
},
|
||||
{
|
||||
Description: "inner 2",
|
||||
DisplayName: toStrPointer("innerDisplayName 2"),
|
||||
},
|
||||
entity: []*TopLevelStruct{
|
||||
{
|
||||
Description: "inner 1",
|
||||
DisplayName: toStrPointer("innerDisplayName 1"),
|
||||
SubStruct: &InnerStruct{
|
||||
Description: "inner",
|
||||
DisplayName: toStrPointer("innerDisplayName"),
|
||||
},
|
||||
},
|
||||
{
|
||||
Description: "inner 2",
|
||||
DisplayName: toStrPointer("innerDisplayName 2"),
|
||||
},
|
||||
},
|
||||
args: args{
|
||||
structPtr: []TranslateOption{
|
||||
TranslateField("Description"),
|
||||
TranslateField("DisplayName"),
|
||||
TranslateStruct("SubStruct",
|
||||
TranslateField("Description"),
|
||||
TranslateField("DisplayName"))),
|
||||
TranslateField("DisplayName"),
|
||||
),
|
||||
},
|
||||
},
|
||||
expected: []*TopLevelStruct{
|
||||
{
|
||||
@@ -121,24 +123,25 @@ func TestTranslateStruct(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "wrapped struct full",
|
||||
args: args{
|
||||
structPtr: TranslateStruct(
|
||||
&WrapperStruct{
|
||||
StructList: []*InnerStruct{
|
||||
{
|
||||
Description: "inner 1",
|
||||
DisplayName: toStrPointer("innerDisplayName 1"),
|
||||
},
|
||||
{
|
||||
Description: "inner 2",
|
||||
DisplayName: toStrPointer("innerDisplayName 2"),
|
||||
},
|
||||
},
|
||||
entity: &WrapperStruct{
|
||||
StructList: []*InnerStruct{
|
||||
{
|
||||
Description: "inner 1",
|
||||
DisplayName: toStrPointer("innerDisplayName 1"),
|
||||
},
|
||||
{
|
||||
Description: "inner 2",
|
||||
DisplayName: toStrPointer("innerDisplayName 2"),
|
||||
},
|
||||
},
|
||||
},
|
||||
args: args{
|
||||
structPtr: []TranslateOption{
|
||||
TranslateEach("StructList",
|
||||
TranslateField("Description"),
|
||||
TranslateField("DisplayName")),
|
||||
),
|
||||
TranslateField("DisplayName"),
|
||||
),
|
||||
},
|
||||
},
|
||||
expected: &WrapperStruct{
|
||||
StructList: []*InnerStruct{
|
||||
@@ -154,41 +157,48 @@ func TestTranslateStruct(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "empty struct, NotExistingSubStructName",
|
||||
name: "empty struct, NotExistingSubStructName",
|
||||
entity: &TopLevelStruct{},
|
||||
args: args{
|
||||
structPtr: TranslateStruct(
|
||||
&TopLevelStruct{},
|
||||
structPtr: []TranslateOption{
|
||||
TranslateField("Description"),
|
||||
TranslateField("DisplayName"),
|
||||
TranslateStruct("NotExistingSubStructName",
|
||||
TranslateField("Description"),
|
||||
TranslateField("DisplayName"))),
|
||||
TranslateField("DisplayName"),
|
||||
),
|
||||
},
|
||||
},
|
||||
expected: &TopLevelStruct{},
|
||||
},
|
||||
{
|
||||
name: "empty struct",
|
||||
name: "empty struct",
|
||||
entity: &TopLevelStruct{},
|
||||
args: args{
|
||||
structPtr: TranslateStruct(
|
||||
&TopLevelStruct{},
|
||||
structPtr: []TranslateOption{
|
||||
TranslateField("Description"),
|
||||
TranslateField("DisplayName"),
|
||||
TranslateStruct("SubStruct",
|
||||
TranslateField("Description"),
|
||||
TranslateField("DisplayName"))),
|
||||
TranslateField("DisplayName"),
|
||||
),
|
||||
},
|
||||
},
|
||||
expected: &TopLevelStruct{},
|
||||
},
|
||||
{
|
||||
name: "empty struct, not existing field",
|
||||
entity: &TopLevelStruct{
|
||||
Description: "description",
|
||||
DisplayName: toStrPointer("displayName"),
|
||||
},
|
||||
args: args{
|
||||
structPtr: TranslateStruct(
|
||||
&TopLevelStruct{
|
||||
Description: "description",
|
||||
DisplayName: toStrPointer("displayName"),
|
||||
}, TranslateField("NotExistingFieldName"),
|
||||
structPtr: []TranslateOption{
|
||||
TranslateField("NotExistingFieldName"),
|
||||
TranslateStruct("SubStruct",
|
||||
TranslateField("NotExistingFieldName"))),
|
||||
TranslateField("NotExistingFieldName"),
|
||||
),
|
||||
},
|
||||
},
|
||||
expected: &TopLevelStruct{
|
||||
Description: "description",
|
||||
@@ -197,17 +207,19 @@ func TestTranslateStruct(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "inner struct DisplayName empy",
|
||||
entity: &TopLevelStruct{
|
||||
Description: "description",
|
||||
DisplayName: toStrPointer("displayName"),
|
||||
},
|
||||
args: args{
|
||||
structPtr: TranslateStruct(
|
||||
&TopLevelStruct{
|
||||
Description: "description",
|
||||
DisplayName: toStrPointer("displayName"),
|
||||
},
|
||||
structPtr: []TranslateOption{
|
||||
TranslateField("Description"),
|
||||
TranslateField("DisplayName"),
|
||||
TranslateStruct("SubStruct",
|
||||
TranslateField("Description"),
|
||||
TranslateField("DisplayName"))),
|
||||
TranslateField("DisplayName"),
|
||||
),
|
||||
},
|
||||
},
|
||||
expected: &TopLevelStruct{
|
||||
Description: "new Description",
|
||||
@@ -216,18 +228,19 @@ func TestTranslateStruct(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "inner struct full",
|
||||
entity: &TopLevelStruct{
|
||||
Description: "description",
|
||||
DisplayName: toStrPointer("displayName"),
|
||||
},
|
||||
args: args{
|
||||
structPtr: TranslateStruct(
|
||||
&TopLevelStruct{
|
||||
Description: "description",
|
||||
DisplayName: toStrPointer("displayName"),
|
||||
},
|
||||
structPtr: []TranslateOption{
|
||||
TranslateField("Description"),
|
||||
TranslateField("DisplayName"),
|
||||
TranslateStruct("SubStruct",
|
||||
TranslateField("Description"),
|
||||
TranslateField("DisplayName")),
|
||||
),
|
||||
TranslateField("DisplayName"),
|
||||
),
|
||||
},
|
||||
},
|
||||
expected: &TopLevelStruct{
|
||||
Description: "new Description",
|
||||
@@ -236,21 +249,23 @@ func TestTranslateStruct(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "full struct",
|
||||
entity: &TopLevelStruct{
|
||||
Description: "description",
|
||||
DisplayName: toStrPointer("displayName"),
|
||||
SubStruct: &InnerStruct{
|
||||
Description: "inner",
|
||||
DisplayName: toStrPointer("innerDisplayName"),
|
||||
},
|
||||
},
|
||||
args: args{
|
||||
structPtr: TranslateStruct(
|
||||
&TopLevelStruct{
|
||||
Description: "description",
|
||||
DisplayName: toStrPointer("displayName"),
|
||||
SubStruct: &InnerStruct{
|
||||
Description: "inner",
|
||||
DisplayName: toStrPointer("innerDisplayName"),
|
||||
}},
|
||||
structPtr: []TranslateOption{
|
||||
TranslateField("Description"),
|
||||
TranslateField("DisplayName"),
|
||||
TranslateStruct("SubStruct",
|
||||
TranslateField("Description"),
|
||||
TranslateField("DisplayName")),
|
||||
),
|
||||
TranslateField("DisplayName"),
|
||||
),
|
||||
},
|
||||
},
|
||||
expected: &TopLevelStruct{
|
||||
Description: "new Description",
|
||||
@@ -271,25 +286,18 @@ func TestTranslateStruct(t *testing.T) {
|
||||
{
|
||||
name: "empty slice",
|
||||
args: args{
|
||||
structPtr: []any{TranslateEach([]string{})},
|
||||
structPtr: []TranslateOption{},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
err := TranslateEntity(mock(), tt.args.structPtr)
|
||||
err := TranslateEntity(mock(), tt.entity, tt.args.structPtr...)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("TranslateEntity() error = %v, wantErr %v", err, tt.wantErr)
|
||||
}
|
||||
switch a := tt.args.structPtr.(type) {
|
||||
case structs:
|
||||
assert.Equal(t, tt.expected, a()[0])
|
||||
case maps:
|
||||
assert.Equal(t, tt.expected, a()[0])
|
||||
case each:
|
||||
assert.Equal(t, tt.expected, a()[0])
|
||||
}
|
||||
assert.Equal(t, tt.expected, tt.entity)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user