mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2026-01-04 11:19:39 -06:00
added the iterator over slice and map
This commit is contained in:
8
changelog/unreleased/added-generyc-translator.md
Normal file
8
changelog/unreleased/added-generyc-translator.md
Normal file
@@ -0,0 +1,8 @@
|
||||
Enhancement: Added generic way to translate composite entities
|
||||
|
||||
Added a generic way to translate the necessary fields in composite entities.
|
||||
The function takes the entity, translation function and fields to translate that are described by the TranslateField function.
|
||||
The function supports nested structs and slices of structs.
|
||||
|
||||
https://github.com/owncloud/ocis/pull/9722
|
||||
https://github.com/owncloud/ocis/issues/9700
|
||||
@@ -65,7 +65,9 @@ func TranslateLocation(t Translator, locale string) func(string, ...any) string
|
||||
return t.Locale(locale).Get
|
||||
}
|
||||
|
||||
// TranslateEntity function tranlate all described fields in the struct in the given locale including nested structs
|
||||
// TranslateEntity function provides the generic way to translate the necessary fields in composite entities.
|
||||
// The function takes the entity, translation function and fields to translate
|
||||
// that are described by the TranslateField function. The function supports nested structs and slices of structs.
|
||||
//
|
||||
// type InnreStruct struct {
|
||||
// Description string
|
||||
@@ -86,12 +88,29 @@ func TranslateLocation(t Translator, locale string) func(string, ...any) string
|
||||
// TranslateField("DisplayName")))
|
||||
func TranslateEntity(entity any, tr func(string, ...any) string, fields ...any) error {
|
||||
value := reflect.ValueOf(entity)
|
||||
if value.Kind() != reflect.Ptr || !value.IsNil() && value.Elem().Kind() != reflect.Struct {
|
||||
// must be a pointer to a struct
|
||||
return ErrStructPointer
|
||||
// Indirect through pointers and interfaces
|
||||
if value.Kind() == reflect.Ptr || value.Kind() == reflect.Interface {
|
||||
if value.IsNil() {
|
||||
// treat a nil struct pointer as valid
|
||||
return nil
|
||||
}
|
||||
value = value.Elem()
|
||||
}
|
||||
if value.IsNil() {
|
||||
// treat a nil struct pointer as valid
|
||||
|
||||
switch value.Kind() {
|
||||
case reflect.Slice, reflect.Map:
|
||||
for i := 0; i < value.Len(); i++ {
|
||||
nextValue := value.Index(i)
|
||||
// Indirect through pointers and interfaces
|
||||
if nextValue.Kind() == reflect.Ptr || nextValue.Kind() == reflect.Interface {
|
||||
if nextValue.IsNil() {
|
||||
// treat a nil struct pointer as valid
|
||||
continue
|
||||
}
|
||||
nextValue = value.Index(i).Elem()
|
||||
}
|
||||
translateInner(nextValue, tr, fields...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
translateInner(value, tr, fields...)
|
||||
@@ -111,8 +130,8 @@ func translateField(value reflect.Value, tr func(string, ...any) string, fl fiel
|
||||
return
|
||||
}
|
||||
fieldName, fields := fl()
|
||||
// exported field
|
||||
if value.Kind() == reflect.Ptr {
|
||||
// Indirect through pointers and interfaces
|
||||
if value.Kind() == reflect.Ptr || value.Kind() == reflect.Interface {
|
||||
if value.IsNil() {
|
||||
return
|
||||
}
|
||||
@@ -122,6 +141,12 @@ func translateField(value reflect.Value, tr func(string, ...any) string, fl fiel
|
||||
if !innerValue.IsValid() {
|
||||
return
|
||||
}
|
||||
switch innerValue.Kind() {
|
||||
case reflect.Slice, reflect.Map:
|
||||
for i := 0; i < innerValue.Len(); i++ {
|
||||
translateInner(innerValue.Index(i), tr, fields...)
|
||||
}
|
||||
}
|
||||
if isStruct(innerValue) {
|
||||
translateInner(innerValue, tr, fields...)
|
||||
return
|
||||
@@ -169,8 +194,6 @@ func isStruct(r reflect.Value) bool {
|
||||
}
|
||||
|
||||
var (
|
||||
// ErrStructPointer is the error that a struct being validated is not specified as a pointer.
|
||||
ErrStructPointer = errors.New("only a pointer to a struct can be validated")
|
||||
ErrUnsupportedType = errors.New("unsupported type")
|
||||
)
|
||||
|
||||
|
||||
@@ -19,6 +19,10 @@ func TestTranslateStruct(t *testing.T) {
|
||||
SubStruct *InnreStruct
|
||||
}
|
||||
|
||||
type WrapperStruct struct {
|
||||
StructList []*InnreStruct
|
||||
}
|
||||
|
||||
toStrPointer := func(str string) *string {
|
||||
return &str
|
||||
}
|
||||
@@ -34,7 +38,68 @@ func TestTranslateStruct(t *testing.T) {
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "empty struct",
|
||||
name: "top level slice of struct",
|
||||
args: args{
|
||||
structPtr: []*InnreStruct{
|
||||
{
|
||||
Description: "inner 1",
|
||||
DisplayName: toStrPointer("innerDisplayName 1"),
|
||||
},
|
||||
{
|
||||
Description: "inner 2",
|
||||
DisplayName: toStrPointer("innerDisplayName 2"),
|
||||
},
|
||||
},
|
||||
request: []any{
|
||||
TranslateField("Description"),
|
||||
TranslateField("DisplayName")},
|
||||
},
|
||||
expected: []*InnreStruct{
|
||||
{
|
||||
Description: "new Inner 1",
|
||||
DisplayName: toStrPointer("new InnerDisplayName 1"),
|
||||
},
|
||||
{
|
||||
Description: "new Inner 2",
|
||||
DisplayName: toStrPointer("new InnerDisplayName 2"),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "wrapped struct full",
|
||||
args: args{
|
||||
structPtr: &WrapperStruct{
|
||||
StructList: []*InnreStruct{
|
||||
{
|
||||
Description: "inner 1",
|
||||
DisplayName: toStrPointer("innerDisplayName 1"),
|
||||
},
|
||||
{
|
||||
Description: "inner 2",
|
||||
DisplayName: toStrPointer("innerDisplayName 2"),
|
||||
},
|
||||
},
|
||||
},
|
||||
request: []any{
|
||||
TranslateField("StructList",
|
||||
TranslateField("Description"),
|
||||
TranslateField("DisplayName"))},
|
||||
},
|
||||
expected: &WrapperStruct{
|
||||
StructList: []*InnreStruct{
|
||||
{
|
||||
Description: "new Inner 1",
|
||||
DisplayName: toStrPointer("new InnerDisplayName 1"),
|
||||
},
|
||||
{
|
||||
Description: "new Inner 2",
|
||||
DisplayName: toStrPointer("new InnerDisplayName 2"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "empty struct, NotExistingSubStructName",
|
||||
args: args{
|
||||
structPtr: &TopLevelStruct{},
|
||||
request: []any{
|
||||
@@ -140,6 +205,14 @@ func TestTranslateStruct(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "nil",
|
||||
args: args{
|
||||
structPtr: nil,
|
||||
request: []any{TranslateField("Description")},
|
||||
},
|
||||
expected: nil,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
@@ -163,6 +236,14 @@ func mock() func(string, ...interface{}) string {
|
||||
return "new Inner"
|
||||
case "innerDisplayName":
|
||||
return "new InnerDisplayName"
|
||||
case "inner 1":
|
||||
return "new Inner 1"
|
||||
case "innerDisplayName 1":
|
||||
return "new InnerDisplayName 1"
|
||||
case "inner 2":
|
||||
return "new Inner 2"
|
||||
case "innerDisplayName 2":
|
||||
return "new InnerDisplayName 2"
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
@@ -85,10 +85,6 @@ func (s *ActivitylogService) HandleGetItemActivities(w http.ResponseWriter, r *h
|
||||
return
|
||||
}
|
||||
|
||||
// FIXME: configurable default locale?
|
||||
loc := l10n.MustGetUserLocale(r.Context(), activeUser.GetId().GetOpaqueId(), r.Header.Get(l10n.HeaderAcceptLanguage), s.valService)
|
||||
t := l10n.NewTranslatorFromCommonConfig("en", _domain, "", _localeFS, _localeSubPath)
|
||||
|
||||
resp := GetActivitiesResponse{Activities: make([]libregraph.Activity, 0, len(evRes.GetEvents()))}
|
||||
for _, e := range evRes.GetEvents() {
|
||||
delete(toDelete, e.GetId())
|
||||
@@ -168,6 +164,10 @@ func (s *ActivitylogService) HandleGetItemActivities(w http.ResponseWriter, r *h
|
||||
continue
|
||||
}
|
||||
|
||||
// FIXME: configurable default locale?
|
||||
loc := l10n.MustGetUserLocale(r.Context(), activeUser.GetId().GetOpaqueId(), r.Header.Get(l10n.HeaderAcceptLanguage), s.valService)
|
||||
t := l10n.NewTranslatorFromCommonConfig("en", _domain, "", _localeFS, _localeSubPath)
|
||||
|
||||
resp.Activities = append(resp.Activities, NewActivity(t.Translate(message, loc), ts, e.GetId(), vars))
|
||||
}
|
||||
|
||||
|
||||
@@ -25,38 +25,3 @@ msgstr ""
|
||||
#: pkg/service/v0/spacetemplates.go:37
|
||||
msgid "Here you can add a description for this Space."
|
||||
msgstr "Здесь вы можете добавить описание этого пространства."
|
||||
|
||||
#: pkg/unifiedrole/unifiedrole.go:87
|
||||
msgid "Can edit"
|
||||
msgstr ""
|
||||
|
||||
#. UnifiedRole Viewer, Role DisplayName (resolves directly)
|
||||
#: pkg/unifiedrole/unifiedrole.go:79
|
||||
msgid "Can view"
|
||||
msgstr ""
|
||||
|
||||
#. default description for new spaces
|
||||
#: pkg/service/v0/spacetemplates.go:31
|
||||
msgid "Here you can add a description for this Space."
|
||||
msgstr ""
|
||||
|
||||
#. UnifiedRole Viewer, Role Description (resolves directly)
|
||||
#. UnifiedRole SpaceViewer, Role Description (resolves directly)
|
||||
#: pkg/unifiedrole/unifiedrole.go:77 pkg/unifiedrole/unifiedrole.go:82
|
||||
msgid "View and download."
|
||||
msgstr ""
|
||||
|
||||
#: pkg/unifiedrole/unifiedrole.go:91
|
||||
msgid "View, download and edit."
|
||||
msgstr ""
|
||||
|
||||
#: pkg/unifiedrole/unifiedrole.go:92
|
||||
msgid "View, download and upload."
|
||||
msgstr ""
|
||||
|
||||
#. canEdit := "Can edit"
|
||||
#. UnifiedRole Editor, Role Description (resolves directly)
|
||||
#. UnifiedRole SpaseEditor, Role Description (resolves directly)
|
||||
#: pkg/unifiedrole/unifiedrole.go:86 pkg/unifiedrole/unifiedrole.go:90
|
||||
msgid "View, download, upload, edit, add and delete."
|
||||
msgstr ""
|
||||
|
||||
@@ -638,15 +638,12 @@ func (api DriveItemPermissionsApi) ListPermissions(w http.ResponseWriter, r *htt
|
||||
w.Header().Add("Content-Language", loc)
|
||||
if loc != "" && loc != "en" {
|
||||
trf := l10n2.NewTranslateLocation(loc, "en")
|
||||
for i, role := range permissions.LibreGraphPermissionsRolesAllowedValues {
|
||||
err := l10n.TranslateEntity(&role, trf,
|
||||
l10n.TranslateField("Description"),
|
||||
l10n.TranslateField("DisplayName"))
|
||||
if err != nil {
|
||||
api.logger.Warn().Err(err).Msg("tranlation error")
|
||||
continue
|
||||
}
|
||||
permissions.LibreGraphPermissionsRolesAllowedValues[i] = role
|
||||
err := l10n.TranslateEntity(permissions.LibreGraphPermissionsRolesAllowedValues, trf,
|
||||
l10n.TranslateField("Description"),
|
||||
l10n.TranslateField("DisplayName"),
|
||||
)
|
||||
if err != nil {
|
||||
api.logger.Error().Err(err).Msg("tranlation error")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -675,15 +672,12 @@ func (api DriveItemPermissionsApi) ListSpaceRootPermissions(w http.ResponseWrite
|
||||
w.Header().Add("Content-Language", loc)
|
||||
if loc != "" && loc != "en" {
|
||||
trf := l10n2.NewTranslateLocation(loc, "en")
|
||||
for i, role := range permissions.LibreGraphPermissionsRolesAllowedValues {
|
||||
err := l10n.TranslateEntity(&role, trf,
|
||||
l10n.TranslateField("Description"),
|
||||
l10n.TranslateField("DisplayName"))
|
||||
if err != nil {
|
||||
api.logger.Warn().Err(err).Msg("tranlation error")
|
||||
continue
|
||||
}
|
||||
permissions.LibreGraphPermissionsRolesAllowedValues[i] = role
|
||||
err := l10n.TranslateEntity(permissions.LibreGraphPermissionsRolesAllowedValues, trf,
|
||||
l10n.TranslateField("Description"),
|
||||
l10n.TranslateField("DisplayName"),
|
||||
)
|
||||
if err != nil {
|
||||
api.logger.Error().Err(err).Msg("tranlation error")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user