diff --git a/ocis-pkg/l10n/l10n.go b/ocis-pkg/l10n/l10n.go index 742c86bf2..f9b89528f 100644 --- a/ocis-pkg/l10n/l10n.go +++ b/ocis-pkg/l10n/l10n.go @@ -2,10 +2,16 @@ package l10n import ( + "context" + "errors" "io/fs" "os" "github.com/leonelquinteros/gotext" + "github.com/owncloud/ocis/v2/ocis-pkg/middleware" + settingssvc "github.com/owncloud/ocis/v2/protogen/gen/ocis/services/settings/v0" + "github.com/owncloud/ocis/v2/services/settings/pkg/store/defaults" + micrometadata "go-micro.dev/v4/metadata" ) // Template marks a string as translatable @@ -53,3 +59,32 @@ func (t Translator) Locale(locale string) *gotext.Locale { } 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 + } + + 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 +} diff --git a/services/notifications/Makefile b/services/notifications/Makefile index dff7c0f58..08f9b2820 100644 --- a/services/notifications/Makefile +++ b/services/notifications/Makefile @@ -44,7 +44,7 @@ l10n-push: .PHONY: l10n-read l10n-read: $(GO_XGETTEXT) - go-xgettext -o $(OUTPUT_DIR)/notifications.pot --keyword=Template --add-comments -s pkg/email/templates.go + go-xgettext -o $(OUTPUT_DIR)/notifications.pot --keyword=l10n.Template --add-comments -s pkg/email/templates.go .PHONY: l10n-write l10n-write: diff --git a/services/notifications/pkg/email/templates.go b/services/notifications/pkg/email/templates.go index c90eee444..615e8409b 100644 --- a/services/notifications/pkg/email/templates.go +++ b/services/notifications/pkg/email/templates.go @@ -1,7 +1,6 @@ package email -// Template marks the string as a translatable template -func Template(s string) string { return s } +import "github.com/owncloud/ocis/v2/ocis-pkg/l10n" // the available templates var ( @@ -10,24 +9,24 @@ var ( textTemplate: "templates/text/email.text.tmpl", htmlTemplate: "templates/html/email.html.tmpl", // ShareCreated email template, Subject field (resolves directly) - Subject: Template(`{ShareSharer} shared '{ShareFolder}' with you`), + Subject: l10n.Template(`{ShareSharer} shared '{ShareFolder}' with you`), // ShareCreated email template, resolves via {{ .Greeting }} - Greeting: Template(`Hello {ShareGrantee}`), + Greeting: l10n.Template(`Hello {ShareGrantee}`), // ShareCreated email template, resolves via {{ .MessageBody }} - MessageBody: Template(`{ShareSharer} has shared "{ShareFolder}" with you.`), + MessageBody: l10n.Template(`{ShareSharer} has shared "{ShareFolder}" with you.`), // ShareCreated email template, resolves via {{ .CallToAction }} - CallToAction: Template(`Click here to view it: {ShareLink}`), + CallToAction: l10n.Template(`Click here to view it: {ShareLink}`), } ShareExpired = MessageTemplate{ textTemplate: "templates/text/email.text.tmpl", htmlTemplate: "templates/html/email.html.tmpl", // ShareExpired email template, Subject field (resolves directly) - Subject: Template(`Share to '{ShareFolder}' expired at {ExpiredAt}`), + Subject: l10n.Template(`Share to '{ShareFolder}' expired at {ExpiredAt}`), // ShareExpired email template, resolves via {{ .Greeting }} - Greeting: Template(`Hello {ShareGrantee},`), + Greeting: l10n.Template(`Hello {ShareGrantee},`), // ShareExpired email template, resolves via {{ .MessageBody }} - MessageBody: Template(`Your share to {ShareFolder} has expired at {ExpiredAt} + MessageBody: l10n.Template(`Your share to {ShareFolder} has expired at {ExpiredAt} Even though this share has been revoked you still might have access through other shares and/or space memberships.`), } @@ -37,39 +36,39 @@ Even though this share has been revoked you still might have access through othe textTemplate: "templates/text/email.text.tmpl", htmlTemplate: "templates/html/email.html.tmpl", // SharedSpace email template, Subject field (resolves directly) - Subject: Template("{SpaceSharer} invited you to join {SpaceName}"), + Subject: l10n.Template("{SpaceSharer} invited you to join {SpaceName}"), // SharedSpace email template, resolves via {{ .Greeting }} - Greeting: Template(`Hello {SpaceGrantee},`), + Greeting: l10n.Template(`Hello {SpaceGrantee},`), // SharedSpace email template, resolves via {{ .MessageBody }} - MessageBody: Template(`{SpaceSharer} has invited you to join "{SpaceName}".`), + MessageBody: l10n.Template(`{SpaceSharer} has invited you to join "{SpaceName}".`), // SharedSpace email template, resolves via {{ .CallToAction }} - CallToAction: Template(`Click here to view it: {ShareLink}`), + CallToAction: l10n.Template(`Click here to view it: {ShareLink}`), } UnsharedSpace = MessageTemplate{ textTemplate: "templates/text/email.text.tmpl", htmlTemplate: "templates/html/email.html.tmpl", // UnsharedSpace email template, Subject field (resolves directly) - Subject: Template(`{SpaceSharer} removed you from {SpaceName}`), + Subject: l10n.Template(`{SpaceSharer} removed you from {SpaceName}`), // UnsharedSpace email template, resolves via {{ .Greeting }} - Greeting: Template(`Hello {SpaceGrantee},`), + Greeting: l10n.Template(`Hello {SpaceGrantee},`), // UnsharedSpace email template, resolves via {{ .MessageBody }} - MessageBody: Template(`{SpaceSharer} has removed you from "{SpaceName}". + MessageBody: l10n.Template(`{SpaceSharer} has removed you from "{SpaceName}". You might still have access through your other groups or direct membership.`), // UnsharedSpace email template, resolves via {{ .CallToAction }} - CallToAction: Template(`Click here to check it: {ShareLink}`), + CallToAction: l10n.Template(`Click here to check it: {ShareLink}`), } MembershipExpired = MessageTemplate{ textTemplate: "templates/text/email.text.tmpl", htmlTemplate: "templates/html/email.html.tmpl", // MembershipExpired email template, Subject field (resolves directly) - Subject: Template(`Membership of '{SpaceName}' expired at {ExpiredAt}`), + Subject: l10n.Template(`Membership of '{SpaceName}' expired at {ExpiredAt}`), // MembershipExpired email template, resolves via {{ .Greeting }} - Greeting: Template(`Hello {SpaceGrantee},`), + Greeting: l10n.Template(`Hello {SpaceGrantee},`), // MembershipExpired email template, resolves via {{ .MessageBody }} - MessageBody: Template(`Your membership of space {SpaceName} has expired at {ExpiredAt} + MessageBody: l10n.Template(`Your membership of space {SpaceName} has expired at {ExpiredAt} Even though this membership has expired you still might have access through other shares and/or space memberships`), } diff --git a/services/notifications/pkg/service/service.go b/services/notifications/pkg/service/service.go index 8b4de702f..d24a13356 100644 --- a/services/notifications/pkg/service/service.go +++ b/services/notifications/pkg/service/service.go @@ -18,6 +18,7 @@ import ( provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1" "github.com/cs3org/reva/v2/pkg/events" "github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool" + "github.com/owncloud/ocis/v2/ocis-pkg/l10n" "github.com/owncloud/ocis/v2/ocis-pkg/log" "github.com/owncloud/ocis/v2/ocis-pkg/middleware" settingssvc "github.com/owncloud/ocis/v2/protogen/gen/ocis/services/settings/v0" @@ -108,7 +109,7 @@ func (s eventsNotifier) render(ctx context.Context, template email.MessageTempla // Render the Email Template for each user messageList := make([]*channels.Message, len(granteeList)) for i, usr := range granteeList { - locale := s.getUserLang(ctx, usr.GetId()) + locale := l10n.MustGetUserLocale(ctx, usr.GetId().GetOpaqueId(), "", s.valueService) fields[granteeFieldName] = usr.GetDisplayName() rendered, err := email.RenderEmailTemplate(template, locale, s.defaultLanguage, s.emailTemplatePath, s.translationPath, fields) @@ -215,22 +216,6 @@ func (s eventsNotifier) getUser(ctx context.Context, u *user.UserId) (*user.User return r.GetUser(), nil } -func (s eventsNotifier) getUserLang(ctx context.Context, u *user.UserId) string { - granteeCtx := metadata.Set(ctx, middleware.AccountID, u.GetOpaqueId()) - if resp, err := s.valueService.GetValueByUniqueIdentifiers(granteeCtx, - &settingssvc.GetValueByUniqueIdentifiersRequest{ - AccountUuid: u.GetOpaqueId(), - SettingId: defaults.SettingUUIDProfileLanguage, - }, - ); err == nil { - val := resp.GetValue().GetValue().GetListValue().GetValues() - if len(val) > 0 && val[0] != nil { - return val[0].GetStringValue() - } - } - return _defaultLocale -} - func (s eventsNotifier) disableEmails(ctx context.Context, u *user.UserId) bool { granteeCtx := metadata.Set(ctx, middleware.AccountID, u.OpaqueId) if resp, err := s.valueService.GetValueByUniqueIdentifiers(granteeCtx, diff --git a/services/userlog/Makefile b/services/userlog/Makefile index eb2a175ef..4be42ab76 100644 --- a/services/userlog/Makefile +++ b/services/userlog/Makefile @@ -44,7 +44,7 @@ l10n-push: .PHONY: l10n-read l10n-read: $(GO_XGETTEXT) - go-xgettext -o $(OUTPUT_DIR)/userlog.pot --keyword=Template -s pkg/service/templates.go + go-xgettext -o $(OUTPUT_DIR)/userlog.pot --keyword=l10n.Template -s pkg/service/templates.go .PHONY: l10n-write l10n-write: diff --git a/services/userlog/pkg/service/service.go b/services/userlog/pkg/service/service.go index 696055de2..f34e3ca15 100644 --- a/services/userlog/pkg/service/service.go +++ b/services/userlog/pkg/service/service.go @@ -11,20 +11,18 @@ import ( gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1" user "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1" "github.com/go-chi/chi/v5" - micrometadata "go-micro.dev/v4/metadata" "go-micro.dev/v4/store" "go.opentelemetry.io/otel/trace" "github.com/cs3org/reva/v2/pkg/events" "github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool" "github.com/cs3org/reva/v2/pkg/utils" + "github.com/owncloud/ocis/v2/ocis-pkg/l10n" "github.com/owncloud/ocis/v2/ocis-pkg/log" - "github.com/owncloud/ocis/v2/ocis-pkg/middleware" "github.com/owncloud/ocis/v2/ocis-pkg/roles" ehmsg "github.com/owncloud/ocis/v2/protogen/gen/ocis/messages/eventhistory/v0" ehsvc "github.com/owncloud/ocis/v2/protogen/gen/ocis/services/eventhistory/v0" settingssvc "github.com/owncloud/ocis/v2/protogen/gen/ocis/services/settings/v0" - "github.com/owncloud/ocis/v2/services/settings/pkg/store/defaults" "github.com/owncloud/ocis/v2/services/userlog/pkg/config" ) @@ -343,7 +341,7 @@ func (ul *UserlogService) sendSSE(ctx context.Context, userIDs []string, event e m := make(map[string]events.SendSSE) for _, userid := range userIDs { - loc := ul.getUserLocale(userid) + loc := l10n.MustGetUserLocale(ctx, userid, "", ul.valueClient) if ev, ok := m[loc]; ok { ev.UserIDs = append(m[loc].UserIDs, userid) m[loc] = ev @@ -455,25 +453,6 @@ func (ul *UserlogService) alterGlobalEvents(ctx context.Context, alter func(map[ }) } -func (ul *UserlogService) getUserLocale(userid string) string { - resp, err := ul.valueClient.GetValueByUniqueIdentifiers( - micrometadata.Set(context.Background(), middleware.AccountID, userid), - &settingssvc.GetValueByUniqueIdentifiersRequest{ - AccountUuid: userid, - SettingId: defaults.SettingUUIDProfileLanguage, - }, - ) - if err != nil { - ul.log.Error().Err(err).Str("userid", userid).Msg("cannot get users locale") - return "" - } - val := resp.GetValue().GetValue().GetListValue().GetValues() - if len(val) == 0 { - return "" - } - return val[0].GetStringValue() -} - func removeExecutant(users []string, executant *user.UserId) []string { var usrs []string for _, u := range users { diff --git a/services/userlog/pkg/service/templates.go b/services/userlog/pkg/service/templates.go index 6acf6fb8c..087f39d9f 100644 --- a/services/userlog/pkg/service/templates.go +++ b/services/userlog/pkg/service/templates.go @@ -1,63 +1,62 @@ package service -// Template marks the string as a translatable template -func Template(s string) string { return s } +import "github.com/owncloud/ocis/v2/ocis-pkg/l10n" // the available templates var ( VirusFound = NotificationTemplate{ - Subject: Template("Virus found"), - Message: Template("Virus found in {resource}. Upload not possible. Virus: {virus}"), + Subject: l10n.Template("Virus found"), + Message: l10n.Template("Virus found in {resource}. Upload not possible. Virus: {virus}"), } PoliciesEnforced = NotificationTemplate{ - Subject: Template("Policies enforced"), - Message: Template("File {resource} was deleted because it violates the policies"), + Subject: l10n.Template("Policies enforced"), + Message: l10n.Template("File {resource} was deleted because it violates the policies"), } SpaceShared = NotificationTemplate{ - Subject: Template("Space shared"), - Message: Template("{user} added you to Space {space}"), + Subject: l10n.Template("Space shared"), + Message: l10n.Template("{user} added you to Space {space}"), } SpaceUnshared = NotificationTemplate{ - Subject: Template("Removed from Space"), - Message: Template("{user} removed you from Space {space}"), + Subject: l10n.Template("Removed from Space"), + Message: l10n.Template("{user} removed you from Space {space}"), } SpaceDisabled = NotificationTemplate{ - Subject: Template("Space disabled"), - Message: Template("{user} disabled Space {space}"), + Subject: l10n.Template("Space disabled"), + Message: l10n.Template("{user} disabled Space {space}"), } SpaceDeleted = NotificationTemplate{ - Subject: Template("Space deleted"), - Message: Template("{user} deleted Space {space}"), + Subject: l10n.Template("Space deleted"), + Message: l10n.Template("{user} deleted Space {space}"), } SpaceMembershipExpired = NotificationTemplate{ - Subject: Template("Membership expired"), - Message: Template("Access to Space {space} lost"), + Subject: l10n.Template("Membership expired"), + Message: l10n.Template("Access to Space {space} lost"), } ShareCreated = NotificationTemplate{ - Subject: Template("Resource shared"), - Message: Template("{user} shared {resource} with you"), + Subject: l10n.Template("Resource shared"), + Message: l10n.Template("{user} shared {resource} with you"), } ShareRemoved = NotificationTemplate{ - Subject: Template("Resource unshared"), - Message: Template("{user} unshared {resource} with you"), + Subject: l10n.Template("Resource unshared"), + Message: l10n.Template("{user} unshared {resource} with you"), } ShareExpired = NotificationTemplate{ - Subject: Template("Share expired"), - Message: Template("Access to {resource} expired"), + Subject: l10n.Template("Share expired"), + Message: l10n.Template("Access to {resource} expired"), } PlatformDeprovision = NotificationTemplate{ - Subject: Template("Instance will be shut down and deprovisioned"), - Message: Template("Attention! The instance will be shut down and deprovisioned on {date}. Download all your data before that date as no access past that date is possible."), + Subject: l10n.Template("Instance will be shut down and deprovisioned"), + Message: l10n.Template("Attention! The instance will be shut down and deprovisioned on {date}. Download all your data before that date as no access past that date is possible."), } )