feat(settings): translate notifications settings

Signed-off-by: jkoberg <jkoberg@owncloud.com>
This commit is contained in:
jkoberg
2025-01-02 11:31:42 +01:00
parent 1d6d905ea5
commit 7947c99930
12 changed files with 222 additions and 30 deletions
+1
View File
@@ -38,6 +38,7 @@ type Config struct {
ServiceAccountIDs []string `yaml:"service_account_ids" env:"SETTINGS_SERVICE_ACCOUNT_IDS;OCIS_SERVICE_ACCOUNT_ID" desc:"The list of all service account IDs. These will be assigned the hidden 'service-account' role. Note: When using 'OCIS_SERVICE_ACCOUNT_ID' this will contain only one value while 'SETTINGS_SERVICE_ACCOUNT_IDS' can have multiple. See the 'auth-service' service description for more details about service accounts." introductionVersion:"5.0"`
DefaultLanguage string `yaml:"default_language" env:"OCIS_DEFAULT_LANGUAGE" desc:"The default language used by services and the WebUI. If not defined, English will be used as default. See the documentation for more details." introductionVersion:"5.0"`
TranslationPath string `yaml:"translation_path" env:"OCIS_TRANSLATION_PATH;SETTINGS_TRANSLATION_PATH" desc:"(optional) Set this to a path with custom translations to overwrite the builtin translations. Note that file and folder naming rules apply, see the documentation for more details." introductionVersion:"7.0"`
Context context.Context `yaml:"-"`
}
@@ -0,0 +1,10 @@
[main]
host = https://www.transifex.com
[o:owncloud-org:p:owncloud:r:ocis-settings]
file_filter = locale/<lang>/LC_MESSAGES/settings.po
minimum_perc = 75
resource_name = ocis-settings
source_file = settings.pot
source_lang = en
type = PO
+74 -3
View File
@@ -2,13 +2,17 @@ package svc
import (
"context"
"embed"
"errors"
"fmt"
"strings"
cs3permissions "github.com/cs3org/go-cs3apis/cs3/permissions/v1beta1"
rpcv1beta1 "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
ctxpkg "github.com/cs3org/reva/v2/pkg/ctx"
"github.com/cs3org/reva/v2/pkg/rgrpc/status"
"github.com/leonelquinteros/gotext"
"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"
@@ -23,6 +27,11 @@ import (
"google.golang.org/protobuf/types/known/emptypb"
)
//go:embed l10n/locale
var _translationFS embed.FS
var _domain = "settings"
// Service represents a service.
type Service struct {
id string
@@ -134,18 +143,29 @@ func (g Service) ListBundles(ctx context.Context, req *settingssvc.ListBundlesRe
if validationError := validateListBundles(req); validationError != nil {
return merrors.BadRequest(g.id, "%s", validationError)
}
bundles, err := g.manager.ListBundles(settingsmsg.Bundle_TYPE_DEFAULT, req.BundleIds)
bundles, err := g.manager.ListBundles(settingsmsg.Bundle_TYPE_DEFAULT, req.GetBundleIds())
if err != nil {
return merrors.NotFound(g.id, "%s", err)
}
roleIDs := g.getRoleIDs(ctx)
// find user locale
var locale string
if u, ok := ctxpkg.ContextGetUser(ctx); ok {
var err error
locale, err = g.getUserLocale(ctx, u.GetId().GetOpaqueId())
if err != nil {
g.logger.Error().Err(err).Str("userid", u.GetId().GetOpaqueId()).Msg("failed to get user locale")
}
}
// filter settings in bundles that are allowed according to roles
var filteredBundles []*settingsmsg.Bundle
for _, bundle := range bundles {
filteredBundle := g.getFilteredBundle(roleIDs, bundle)
if len(filteredBundle.Settings) > 0 {
filteredBundles = append(filteredBundles, filteredBundle)
if len(filteredBundle.GetSettings()) > 0 {
t := l10n.NewTranslatorFromCommonConfig(g.config.DefaultLanguage, _domain, g.config.TranslationPath, _translationFS, "l10n/locale").Locale(locale)
filteredBundles = append(filteredBundles, translateBundle(filteredBundle, t))
}
}
@@ -642,7 +662,58 @@ func (g Service) canManageRoles(ctx context.Context) bool {
return g.hasStaticPermission(ctx, RoleManagementPermissionID)
}
func (g Service) getUserLocale(ctx context.Context, userID string) (string, error) {
var resp settingssvc.GetValueResponse
err := g.GetValueByUniqueIdentifiers(
ctx,
&settingssvc.GetValueByUniqueIdentifiersRequest{
AccountUuid: userID,
SettingId: defaults.SettingUUIDProfileLanguage,
},
&resp,
)
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
}
func formatPermissionName(setting *settingsmsg.Setting) string {
constraint := strings.TrimPrefix(setting.GetPermissionValue().GetConstraint().String(), "CONSTRAINT_")
return setting.Name + "." + strings.ToLower(constraint)
}
func translateBundle(bundle *settingsmsg.Bundle, t *gotext.Locale) *settingsmsg.Bundle {
for i, set := range bundle.GetSettings() {
switch set.GetId() {
default:
continue
case defaults.SettingUUIDProfileEmailSendingInterval:
// translate interval names ('Instant', 'Daily', 'Weekly', 'Never')
value := set.GetSingleChoiceValue()
for i, v := range value.GetOptions() {
value.Options[i].DisplayValue = t.Get(v.GetDisplayValue())
}
set.Value = &settingsmsg.Setting_SingleChoiceValue{SingleChoiceValue: value}
fallthrough
case defaults.SettingUUIDProfileEventShareCreated,
defaults.SettingUUIDProfileEventShareRemoved,
defaults.SettingUUIDProfileEventShareExpired,
defaults.SettingUUIDProfileEventSpaceShared,
defaults.SettingUUIDProfileEventSpaceUnshared,
defaults.SettingUUIDProfileEventSpaceMembershipExpired,
defaults.SettingUUIDProfileEventSpaceDisabled,
defaults.SettingUUIDProfileEventSpaceDeleted:
// translate event names ('Share Received', 'Share Removed', ...)
set.DisplayName = t.Get(set.GetDisplayName())
// translate event descriptions ('Notify me when I receive a share', ...)
set.Description = t.Get(set.GetDescription())
bundle.Settings[i] = set
}
}
return bundle
}
@@ -282,8 +282,8 @@ func generateBundleProfileRequest() *settingsmsg.Bundle {
{
Id: SettingUUIDProfileEmailSendingInterval,
Name: "email-sending-interval-options",
DisplayName: "Email Notifications options",
Description: "Email notifications options",
DisplayName: TemplateEmailSendingInterval,
Description: TemplateEmailSendingIntervalDescription,
Resource: &settingsmsg.Resource{
Type: settingsmsg.Resource_TYPE_USER,
},
@@ -292,8 +292,8 @@ func generateBundleProfileRequest() *settingsmsg.Bundle {
{
Id: SettingUUIDProfileEventShareCreated,
Name: "event-share-created-options",
DisplayName: "Share created",
Description: "Share created",
DisplayName: TemplateShareCreated,
Description: TemplateShareCreatedDescription,
Resource: &settingsmsg.Resource{
Type: settingsmsg.Resource_TYPE_USER,
},
@@ -309,8 +309,8 @@ func generateBundleProfileRequest() *settingsmsg.Bundle {
{
Id: SettingUUIDProfileEventShareRemoved,
Name: "event-share-removed-options",
DisplayName: "Share removed",
Description: "Share removed",
DisplayName: TemplateShareRemoved,
Description: TemplateShareRemovedDescription,
Resource: &settingsmsg.Resource{
Type: settingsmsg.Resource_TYPE_USER,
},
@@ -326,8 +326,8 @@ func generateBundleProfileRequest() *settingsmsg.Bundle {
{
Id: SettingUUIDProfileEventShareExpired,
Name: "event-share-expired-options",
DisplayName: "Share expired",
Description: "Share expired",
DisplayName: TemplateShareExpired,
Description: TemplateShareExpiredDescription,
Resource: &settingsmsg.Resource{
Type: settingsmsg.Resource_TYPE_USER,
},
@@ -343,8 +343,8 @@ func generateBundleProfileRequest() *settingsmsg.Bundle {
{
Id: SettingUUIDProfileEventSpaceShared,
Name: "event-space-shared-options",
DisplayName: "Space shared",
Description: "Space shared",
DisplayName: TemplateSpaceShared,
Description: TemplateSpaceSharedDescription,
Resource: &settingsmsg.Resource{
Type: settingsmsg.Resource_TYPE_USER,
},
@@ -360,8 +360,8 @@ func generateBundleProfileRequest() *settingsmsg.Bundle {
{
Id: SettingUUIDProfileEventSpaceUnshared,
Name: "event-space-unshared-options",
DisplayName: "Space unshared",
Description: "Space unshared",
DisplayName: TemplateSpaceUnshared,
Description: TemplateSpaceUnsharedDescription,
Resource: &settingsmsg.Resource{
Type: settingsmsg.Resource_TYPE_USER,
},
@@ -377,8 +377,8 @@ func generateBundleProfileRequest() *settingsmsg.Bundle {
{
Id: SettingUUIDProfileEventSpaceMembershipExpired,
Name: "event-space-membership-expired-options",
DisplayName: "Space membership expired",
Description: "Space membership expired",
DisplayName: TemplateSpaceMembershipExpired,
Description: TemplateSpaceMembershipExpiredDescription,
Resource: &settingsmsg.Resource{
Type: settingsmsg.Resource_TYPE_USER,
},
@@ -394,8 +394,8 @@ func generateBundleProfileRequest() *settingsmsg.Bundle {
{
Id: SettingUUIDProfileEventSpaceDisabled,
Name: "event-space-disabled-options",
DisplayName: "Space disabled",
Description: "Space disabled",
DisplayName: TemplateSpaceDisabled,
Description: TemplateSpaceDisabledDescription,
Resource: &settingsmsg.Resource{
Type: settingsmsg.Resource_TYPE_USER,
},
@@ -411,8 +411,8 @@ func generateBundleProfileRequest() *settingsmsg.Bundle {
{
Id: SettingUUIDProfileEventSpaceDeleted,
Name: "event-space-deleted-options",
DisplayName: "Space deleted",
Description: "Space deleted",
DisplayName: TemplateSpaceDeleted,
Description: TemplateSpaceDeletedDescription,
Resource: &settingsmsg.Resource{
Type: settingsmsg.Resource_TYPE_USER,
},
@@ -428,8 +428,8 @@ func generateBundleProfileRequest() *settingsmsg.Bundle {
{
Id: SettingUUIDProfileEventPostprocessingStepFinished,
Name: "event-postprocessing-step-finished-options",
DisplayName: "Postprocessing Step Finished",
Description: "Postprocessing Step Finished",
DisplayName: TemplateFileRejected,
Description: TemplateFileRejectedDescription,
Resource: &settingsmsg.Resource{
Type: settingsmsg.Resource_TYPE_USER,
},
@@ -455,7 +455,7 @@ var sendEmailOptions = settingsmsg.Setting_SingleChoiceValue{
StringValue: "instant",
},
},
DisplayValue: "Instant",
DisplayValue: TemplateIntervalInstant,
Default: true,
},
{
@@ -464,7 +464,7 @@ var sendEmailOptions = settingsmsg.Setting_SingleChoiceValue{
StringValue: "daily",
},
},
DisplayValue: "Daily",
DisplayValue: TemplateIntervalDaily,
},
{
Value: &settingsmsg.ListOptionValue{
@@ -472,7 +472,7 @@ var sendEmailOptions = settingsmsg.Setting_SingleChoiceValue{
StringValue: "weekly",
},
},
DisplayValue: "Weekly",
DisplayValue: TemplateIntervalWeekly,
},
{
Value: &settingsmsg.ListOptionValue{
@@ -480,7 +480,7 @@ var sendEmailOptions = settingsmsg.Setting_SingleChoiceValue{
StringValue: "never",
},
},
DisplayValue: "Never",
DisplayValue: TemplateIntervalNever,
},
},
},
@@ -0,0 +1,55 @@
package defaults
import "github.com/owncloud/ocis/v2/ocis-pkg/l10n"
// Translatable configuration options
var (
// name of the notification option 'Share Received'
TemplateShareCreated = l10n.Template("Share Received")
// description of the notification option 'Share Received'
TemplateShareCreatedDescription = l10n.Template("Notify me when I receive a share")
// name of the notification option 'Share Removed'
TemplateShareRemoved = l10n.Template("Share Removed")
// description of the notification option 'Share Removed'
TemplateShareRemovedDescription = l10n.Template("Notify me when my shares are removed")
// name of the notification option 'Share Expired'
TemplateShareExpired = l10n.Template("Share Expired")
// description of the notification option 'Share Expired'
TemplateShareExpiredDescription = l10n.Template("Notify me when my shares expire")
// name of the notification option 'Space Shared'
TemplateSpaceShared = l10n.Template("Added as space member")
// description of the notification option 'Space Shared'
TemplateSpaceSharedDescription = l10n.Template("Notify me when I am added as a member to a space")
// name of the notification option 'Space Unshared'
TemplateSpaceUnshared = l10n.Template("Removed as space member")
// description of the notification option 'Space Unshared'
TemplateSpaceUnsharedDescription = l10n.Template("Notify me when I am removed as a member from a space")
// name of the notification option 'Space Membership Expired'
TemplateSpaceMembershipExpired = l10n.Template("Space membership expired")
// description of the notification option 'Space Membership Expired'
TemplateSpaceMembershipExpiredDescription = l10n.Template("Notify me when my membership of a space expires")
// name of the notification option 'Space Disabled'
TemplateSpaceDisabled = l10n.Template("Space disabled")
// description of the notification option 'Space Disabled'
TemplateSpaceDisabledDescription = l10n.Template("Notify me when a space I am a member of is disabled")
// name of the notification option 'Space Deleted'
TemplateSpaceDeleted = l10n.Template("Space deleted")
// description of the notification option 'Space Deleted'
TemplateSpaceDeletedDescription = l10n.Template("Notify me when a space I am a member of is deleted")
// name of the notification option 'File Rejected'
TemplateFileRejected = l10n.Template("File rejected")
// description of the notification option 'File Rejected'
TemplateFileRejectedDescription = l10n.Template("Notify me when a file I uploaded is rejected because of virus infection or policy violation")
// name of the notification option 'Email Interval'
TemplateEmailSendingInterval = l10n.Template("Email sending interval")
// description of the notification option 'Email Interval'
TemplateEmailSendingIntervalDescription = l10n.Template("Notifiy me via email:")
// translation for the 'instant' email interval option
TemplateIntervalInstant = l10n.Template("Instant")
// translation for the 'daily' email interval option
TemplateIntervalDaily = l10n.Template("Daily")
// translation for the 'weekly' email interval option
TemplateIntervalWeekly = l10n.Template("Weekly")
// translation for the 'never' email interval option
TemplateIntervalNever = l10n.Template("Never")
)