From 5dd2e75c10d1f7ce073671017dce3c375336dc41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Espino?= Date: Fri, 26 Feb 2021 08:12:49 +0100 Subject: [PATCH] Extracting i18n functionality to i18n core library (#16914) * extracting i18n functionality to i18n core library * Removing utils.T * Adding documentation and changing one function name for better explanation * Changing other missing utils.T * Adding license string * Renaming corelibs to pkg * Renaming corelibs to pkg (moving directory) * Renaming from pkg to shared * Fixing bodyPage.Html casing * Fixing merges * Fixing merge problem * Fixing tests --- api4/team_test.go | 8 +- app/admin.go | 5 +- app/app.go | 18 +- app/app_iface.go | 13 +- app/bot.go | 6 +- app/channel.go | 47 ++--- app/command.go | 12 +- app/command_autocomplete_test.go | 4 +- app/email.go | 72 +++---- app/email_batching.go | 5 +- app/expirynotify.go | 4 +- app/integration_action.go | 15 +- .../opentracing_layer.go.tmpl | 1 - app/ldap.go | 4 +- app/notification.go | 10 +- app/notification_email.go | 5 +- app/notification_email_test.go | 46 ++--- app/notification_push.go | 7 +- app/notification_push_test.go | 4 +- app/notification_test.go | 3 +- app/oauth.go | 3 +- app/opentracing/opentracing_layer.go | 9 +- app/plugin_api.go | 6 +- app/plugin_api_test.go | 4 +- app/plugin_commands_test.go | 4 +- app/post.go | 6 +- app/ratelimit.go | 5 +- app/security_update_check.go | 5 +- app/server.go | 17 +- app/slashcommands/command_away.go | 5 +- app/slashcommands/command_channel_header.go | 5 +- app/slashcommands/command_channel_purpose.go | 5 +- app/slashcommands/command_channel_rename.go | 5 +- app/slashcommands/command_code.go | 5 +- app/slashcommands/command_custom_status.go | 5 +- app/slashcommands/command_dnd.go | 5 +- app/slashcommands/command_echo.go | 5 +- app/slashcommands/command_expand_collapse.go | 7 +- app/slashcommands/command_groupmsg.go | 5 +- app/slashcommands/command_groupmsg_test.go | 2 +- app/slashcommands/command_help.go | 5 +- app/slashcommands/command_invite.go | 5 +- app/slashcommands/command_invite_people.go | 5 +- app/slashcommands/command_join.go | 5 +- app/slashcommands/command_join_test.go | 2 +- app/slashcommands/command_leave.go | 5 +- app/slashcommands/command_loadtest.go | 4 +- app/slashcommands/command_logout.go | 5 +- app/slashcommands/command_me.go | 5 +- app/slashcommands/command_msg.go | 5 +- app/slashcommands/command_msg_test.go | 2 +- app/slashcommands/command_mute.go | 5 +- app/slashcommands/command_mute_test.go | 2 +- app/slashcommands/command_offline.go | 5 +- app/slashcommands/command_online.go | 5 +- app/slashcommands/command_open.go | 5 +- app/slashcommands/command_remove.go | 7 +- app/slashcommands/command_search.go | 5 +- app/slashcommands/command_settings.go | 5 +- app/slashcommands/command_shortcuts.go | 5 +- app/slashcommands/command_shrug.go | 5 +- app/team.go | 6 +- app/user.go | 8 +- app/web_conn.go | 6 +- app/web_conn_test.go | 8 +- app/web_hub_test.go | 4 +- app/webhub_fuzz.go | 4 +- app/websocket_router.go | 4 +- cmd/mattermost/commands/config.go | 3 +- cmd/mattermost/commands/init.go | 3 +- cmd/mattermost/commands/permissions.go | 6 +- cmd/mattermost/commands/permissions_test.go | 7 +- cmd/mattermost/commands/test.go | 6 +- config/utils.go | 3 +- model/command_args.go | 24 +-- model/utils.go | 10 +- model/websocket_request.go | 8 +- services/slackimport/slackimport.go | 47 ++--- shared/i18n/i18n.go | 185 ++++++++++++++++++ shared/i18n/i18n_test.go | 69 +++++++ store/sqlstore/store.go | 12 +- utils/api.go | 11 +- utils/html.go | 32 --- utils/html_test.go | 61 ------ utils/i18n.go | 118 +---------- web/context.go | 3 +- web/handlers.go | 3 +- web/oauth.go | 5 +- web/oauth_test.go | 3 +- wsapi/websocket_handler.go | 6 +- 90 files changed, 596 insertions(+), 568 deletions(-) create mode 100644 shared/i18n/i18n.go create mode 100644 shared/i18n/i18n_test.go diff --git a/api4/team_test.go b/api4/team_test.go index 80d90109e8..fada333a53 100644 --- a/api4/team_test.go +++ b/api4/team_test.go @@ -18,7 +18,7 @@ import ( "github.com/mattermost/mattermost-server/v5/app" "github.com/mattermost/mattermost-server/v5/model" "github.com/mattermost/mattermost-server/v5/services/mailservice" - "github.com/mattermost/mattermost-server/v5/utils" + "github.com/mattermost/mattermost-server/v5/shared/i18n" "github.com/mattermost/mattermost-server/v5/utils/testutils" ) @@ -2794,7 +2794,7 @@ func TestInviteUsersToTeam(t *testing.T) { CheckNoError(t, resp) require.True(t, okMsg, "should return true") nameFormat := *th.App.Config().TeamSettings.TeammateNameDisplay - expectedSubject := utils.T("api.templates.invite_subject", + expectedSubject := i18n.T("api.templates.invite_subject", map[string]interface{}{"SenderName": th.SystemAdminUser.GetDisplayName(nameFormat), "TeamDisplayName": th.BasicTeam.DisplayName, "SiteName": th.App.ClientConfig()["SiteName"]}) @@ -2805,7 +2805,7 @@ func TestInviteUsersToTeam(t *testing.T) { okMsg, resp = th.LocalClient.InviteUsersToTeam(th.BasicTeam.Id, emailList) CheckNoError(t, resp) require.True(t, okMsg, "should return true") - expectedSubject = utils.T("api.templates.invite_subject", + expectedSubject = i18n.T("api.templates.invite_subject", map[string]interface{}{"SenderName": "Administrator", "TeamDisplayName": th.BasicTeam.DisplayName, "SiteName": th.App.ClientConfig()["SiteName"]}) @@ -2925,7 +2925,7 @@ func TestInviteGuestsToTeam(t *testing.T) { require.True(t, okMsg, "should return true") nameFormat := *th.App.Config().TeamSettings.TeammateNameDisplay - expectedSubject := utils.T("api.templates.invite_guest_subject", + expectedSubject := i18n.T("api.templates.invite_guest_subject", map[string]interface{}{"SenderName": th.SystemAdminUser.GetDisplayName(nameFormat), "TeamDisplayName": th.BasicTeam.DisplayName, "SiteName": th.App.ClientConfig()["SiteName"]}) diff --git a/app/admin.go b/app/admin.go index a58af79543..7a8cb78267 100644 --- a/app/admin.go +++ b/app/admin.go @@ -16,6 +16,7 @@ import ( "github.com/mattermost/mattermost-server/v5/mlog" "github.com/mattermost/mattermost-server/v5/model" "github.com/mattermost/mattermost-server/v5/services/mailservice" + "github.com/mattermost/mattermost-server/v5/shared/i18n" "github.com/mattermost/mattermost-server/v5/utils" ) @@ -205,7 +206,7 @@ func (a *App) TestSiteURL(siteURL string) *model.AppError { func (a *App) TestEmail(userID string, cfg *model.Config) *model.AppError { if *cfg.EmailSettings.SMTPServer == "" { - return model.NewAppError("testEmail", "api.admin.test_email.missing_server", nil, utils.T("api.context.invalid_param.app_error", map[string]interface{}{"Name": "SMTPServer"}), http.StatusBadRequest) + return model.NewAppError("testEmail", "api.admin.test_email.missing_server", nil, i18n.T("api.context.invalid_param.app_error", map[string]interface{}{"Name": "SMTPServer"}), http.StatusBadRequest) } // if the user hasn't changed their email settings, fill in the actual SMTP password so that @@ -224,7 +225,7 @@ func (a *App) TestEmail(userID string, cfg *model.Config) *model.AppError { return err } - T := utils.GetUserTranslations(user.Locale) + T := i18n.GetUserTranslations(user.Locale) license := a.Srv().License() mailConfig := a.Srv().MailServiceConfig() if err := mailservice.SendMailUsingConfig(user.Email, T("api.admin.test_email.subject"), T("api.admin.test_email.body"), mailConfig, license != nil && *license.Features.Compliance, ""); err != nil { diff --git a/app/app.go b/app/app.go index 2a2b54de7d..4f76bc921b 100644 --- a/app/app.go +++ b/app/app.go @@ -12,9 +12,6 @@ import ( "strings" "time" - "github.com/mattermost/go-i18n/i18n" - goi18n "github.com/mattermost/go-i18n/i18n" - "github.com/mattermost/mattermost-server/v5/einterfaces" "github.com/mattermost/mattermost-server/v5/mlog" "github.com/mattermost/mattermost-server/v5/model" @@ -23,6 +20,7 @@ import ( "github.com/mattermost/mattermost-server/v5/services/mailservice" "github.com/mattermost/mattermost-server/v5/services/searchengine" "github.com/mattermost/mattermost-server/v5/services/timezones" + "github.com/mattermost/mattermost-server/v5/shared/i18n" "github.com/mattermost/mattermost-server/v5/utils" ) @@ -34,7 +32,7 @@ type App struct { // a cyclic dependency as bleve tests themselves import testlib. searchEngine *searchengine.Broker - t goi18n.TranslateFunc + t i18n.TranslateFunc session model.Session requestId string ipAddress string @@ -366,7 +364,7 @@ func (a *App) notifyAdminsOfWarnMetricStatus(warnMetricId string, isE0Edition bo } } - T := utils.GetUserTranslations(sysAdmins[0].Locale) + T := i18n.GetUserTranslations(sysAdmins[0].Locale) warnMetricsBot := &model.Bot{ Username: model.BOT_WARN_METRIC_BOT_USERNAME, DisplayName: T("app.system.warn_metric.bot_displayname"), @@ -380,7 +378,7 @@ func (a *App) notifyAdminsOfWarnMetricStatus(warnMetricId string, isE0Edition bo } for _, sysAdmin := range sysAdmins { - T := utils.GetUserTranslations(sysAdmin.Locale) + T := i18n.GetUserTranslations(sysAdmin.Locale) bot.DisplayName = T("app.system.warn_metric.bot_displayname") bot.Description = T("app.system.warn_metric.bot_description") @@ -466,9 +464,9 @@ func (a *App) NotifyAndSetWarnMetricAck(warnMetricId string, sender *model.User, if !forceAck { if *a.Config().EmailSettings.SMTPServer == "" { - return model.NewAppError("NotifyAndSetWarnMetricAck", "api.email.send_warn_metric_ack.missing_server.app_error", nil, utils.T("api.context.invalid_param.app_error", map[string]interface{}{"Name": "SMTPServer"}), http.StatusInternalServerError) + return model.NewAppError("NotifyAndSetWarnMetricAck", "api.email.send_warn_metric_ack.missing_server.app_error", nil, i18n.T("api.context.invalid_param.app_error", map[string]interface{}{"Name": "SMTPServer"}), http.StatusInternalServerError) } - T := utils.GetUserTranslations(sender.Locale) + T := i18n.GetUserTranslations(sender.Locale) bodyPage := a.Srv().EmailService.newEmailTemplate("warn_metric_ack", sender.Locale) bodyPage.Props["ContactNameHeader"] = T("api.templates.warn_metric_ack.body.contact_name_header") bodyPage.Props["ContactNameValue"] = sender.GetFullName() @@ -671,7 +669,7 @@ func (a *App) SetSession(s *model.Session) { a.session = *s } -func (a *App) SetT(t goi18n.TranslateFunc) { +func (a *App) SetT(t i18n.TranslateFunc) { a.t = t } func (a *App) SetRequestId(s string) { @@ -695,7 +693,7 @@ func (a *App) SetContext(c context.Context) { func (a *App) SetServer(srv *Server) { a.srv = srv } -func (a *App) GetT() goi18n.TranslateFunc { +func (a *App) GetT() i18n.TranslateFunc { return a.t } diff --git a/app/app_iface.go b/app/app_iface.go index c6d26e37e5..8057b38300 100644 --- a/app/app_iface.go +++ b/app/app_iface.go @@ -18,8 +18,6 @@ import ( "time" "github.com/dyatlov/go-opengraph/opengraph" - "github.com/mattermost/go-i18n/i18n" - goi18n "github.com/mattermost/go-i18n/i18n" "github.com/mattermost/mattermost-server/v5/audit" "github.com/mattermost/mattermost-server/v5/einterfaces" "github.com/mattermost/mattermost-server/v5/mlog" @@ -30,6 +28,7 @@ import ( "github.com/mattermost/mattermost-server/v5/services/imageproxy" "github.com/mattermost/mattermost-server/v5/services/searchengine" "github.com/mattermost/mattermost-server/v5/services/timezones" + "github.com/mattermost/mattermost-server/v5/shared/i18n" "github.com/mattermost/mattermost-server/v5/store" ) @@ -39,7 +38,7 @@ type AppIface interface { ExecuteCommand(args *model.CommandArgs) (*model.CommandResponse, *model.AppError) // @openTracingParams teamID // previous ListCommands now ListAutocompleteCommands - ListAutocompleteCommands(teamID string, T goi18n.TranslateFunc) ([]*model.Command, *model.AppError) + ListAutocompleteCommands(teamID string, T i18n.TranslateFunc) ([]*model.Command, *model.AppError) // @openTracingParams teamID, skipSlackParsing CreateCommandPost(post *model.Post, teamID string, response *model.CommandResponse, skipSlackParsing bool) (*model.Post, *model.AppError) // AddCursorIdsForPostList adds NextPostId and PrevPostId as cursor to the PostList. @@ -231,7 +230,7 @@ type AppIface interface { // function is only exposed to sysadmins and the possibility of this edge case is relatively small. MoveChannel(team *model.Team, channel *model.Channel, user *model.User) *model.AppError // NewWebConn returns a new WebConn instance. - NewWebConn(ws net.Conn, session model.Session, t goi18n.TranslateFunc, locale string) *WebConn + NewWebConn(ws net.Conn, session model.Session, t i18n.TranslateFunc, locale string) *WebConn // NewWebHub creates a new Hub. NewWebHub() *Hub // NotifySessionsExpired is called periodically from the job server to notify any mobile sessions that have expired. @@ -683,7 +682,7 @@ type AppIface interface { GetStatus(userID string) (*model.Status, *model.AppError) GetStatusFromCache(userID string) *model.Status GetStatusesByIds(userIDs []string) (map[string]interface{}, *model.AppError) - GetT() goi18n.TranslateFunc + GetT() i18n.TranslateFunc GetTeam(teamID string) (*model.Team, *model.AppError) GetTeamByInviteId(inviteId string) (*model.Team, *model.AppError) GetTeamByName(name string) (*model.Team, *model.AppError) @@ -784,7 +783,7 @@ type AppIface interface { LeaveChannel(channelID string, userID string) *model.AppError LeaveTeam(team *model.Team, user *model.User, requestorId string) *model.AppError LimitedClientConfig() map[string]string - ListAllCommands(teamID string, T goi18n.TranslateFunc) ([]*model.Command, *model.AppError) + ListAllCommands(teamID string, T i18n.TranslateFunc) ([]*model.Command, *model.AppError) ListDirectory(path string) ([]string, *model.AppError) ListExports() ([]string, *model.AppError) ListImports() ([]string, *model.AppError) @@ -954,7 +953,7 @@ type AppIface interface { SetStatusOffline(userID string, manual bool) SetStatusOnline(userID string, manual bool) SetStatusOutOfOffice(userID string) - SetT(t goi18n.TranslateFunc) + SetT(t i18n.TranslateFunc) SetTeamIcon(teamID string, imageData *multipart.FileHeader) *model.AppError SetTeamIconFromFile(team *model.Team, file io.Reader) *model.AppError SetTeamIconFromMultiPartFile(teamID string, file multipart.File) *model.AppError diff --git a/app/bot.go b/app/bot.go index 0682d09162..659543f8a8 100644 --- a/app/bot.go +++ b/app/bot.go @@ -13,8 +13,8 @@ import ( "github.com/mattermost/mattermost-server/v5/mlog" "github.com/mattermost/mattermost-server/v5/model" + "github.com/mattermost/mattermost-server/v5/shared/i18n" "github.com/mattermost/mattermost-server/v5/store" - "github.com/mattermost/mattermost-server/v5/utils" ) // CreateBot creates the given bot and corresponding user. @@ -72,7 +72,7 @@ func (a *App) CreateBot(bot *model.Bot) (*model.Bot, *model.AppError) { return nil, err } - T := utils.GetUserTranslations(ownerUser.Locale) + T := i18n.GetUserTranslations(ownerUser.Locale) botAddPost := &model.Post{ Type: model.POST_ADD_BOT_TEAMS_CHANNELS, UserId: savedBot.UserId, @@ -471,7 +471,7 @@ func (a *App) getDisableBotSysadminMessage(user *model.User, userBots model.BotL botList += fmt.Sprintf("* %v\n", bot.Username) } - T := utils.GetUserTranslations(user.Locale) + T := i18n.GetUserTranslations(user.Locale) message = T("app.bot.get_disable_bot_sysadmin_message", map[string]interface{}{ "UserName": user.Username, diff --git a/app/channel.go b/app/channel.go index 8c3c91be63..746349c542 100644 --- a/app/channel.go +++ b/app/channel.go @@ -14,6 +14,7 @@ import ( "github.com/mattermost/mattermost-server/v5/mlog" "github.com/mattermost/mattermost-server/v5/model" "github.com/mattermost/mattermost-server/v5/plugin" + "github.com/mattermost/mattermost-server/v5/shared/i18n" "github.com/mattermost/mattermost-server/v5/store" "github.com/mattermost/mattermost-server/v5/utils" ) @@ -22,13 +23,13 @@ import ( // func (a *App) CreateDefaultChannels(teamID string) ([]*model.Channel, *model.AppError) { displayNames := map[string]string{ - "town-square": utils.T("api.channel.create_default_channels.town_square"), - "off-topic": utils.T("api.channel.create_default_channels.off_topic"), + "town-square": i18n.T("api.channel.create_default_channels.town_square"), + "off-topic": i18n.T("api.channel.create_default_channels.off_topic"), } channels := []*model.Channel{} defaultChannelNames := a.DefaultChannelNames() for _, name := range defaultChannelNames { - displayName := utils.TDefault(displayNames[name], name) + displayName := i18n.TDefault(displayNames[name], name) channel := &model.Channel{DisplayName: displayName, Name: name, Type: model.CHANNEL_OPEN, TeamId: teamID} if _, err := a.CreateChannel(channel, false); err != nil { return nil, err @@ -711,8 +712,8 @@ func (a *App) UpdateChannelPrivacy(oldChannel *model.Channel, user *model.User) func (a *App) postChannelPrivacyMessage(user *model.User, channel *model.Channel) *model.AppError { message := (map[string]string{ - model.CHANNEL_OPEN: utils.T("api.channel.change_channel_privacy.private_to_public"), - model.CHANNEL_PRIVATE: utils.T("api.channel.change_channel_privacy.public_to_private"), + model.CHANNEL_OPEN: i18n.T("api.channel.change_channel_privacy.private_to_public"), + model.CHANNEL_PRIVATE: i18n.T("api.channel.change_channel_privacy.public_to_private"), })[channel.Type] post := &model.Post{ ChannelId: channel.Id, @@ -758,7 +759,7 @@ func (a *App) RestoreChannel(channel *model.Channel, userID string) (*model.Chan } if user != nil { - T := utils.GetUserTranslations(user.Locale) + T := i18n.GetUserTranslations(user.Locale) post := &model.Post{ ChannelId: channel.Id, @@ -1273,7 +1274,7 @@ func (a *App) DeleteChannel(channel *model.Channel, userID string) *model.AppErr } if user != nil { - T := utils.GetUserTranslations(user.Locale) + T := i18n.GetUserTranslations(user.Locale) post := &model.Post{ ChannelId: channel.Id, @@ -1500,11 +1501,11 @@ func (a *App) PostUpdateChannelHeaderMessage(userID string, channel *model.Chann var message string if oldChannelHeader == "" { - message = fmt.Sprintf(utils.T("api.channel.post_update_channel_header_message_and_forget.updated_to"), user.Username, newChannelHeader) + message = fmt.Sprintf(i18n.T("api.channel.post_update_channel_header_message_and_forget.updated_to"), user.Username, newChannelHeader) } else if newChannelHeader == "" { - message = fmt.Sprintf(utils.T("api.channel.post_update_channel_header_message_and_forget.removed"), user.Username, oldChannelHeader) + message = fmt.Sprintf(i18n.T("api.channel.post_update_channel_header_message_and_forget.removed"), user.Username, oldChannelHeader) } else { - message = fmt.Sprintf(utils.T("api.channel.post_update_channel_header_message_and_forget.updated_from"), user.Username, oldChannelHeader, newChannelHeader) + message = fmt.Sprintf(i18n.T("api.channel.post_update_channel_header_message_and_forget.updated_from"), user.Username, oldChannelHeader, newChannelHeader) } post := &model.Post{ @@ -1534,11 +1535,11 @@ func (a *App) PostUpdateChannelPurposeMessage(userID string, channel *model.Chan var message string if oldChannelPurpose == "" { - message = fmt.Sprintf(utils.T("app.channel.post_update_channel_purpose_message.updated_to"), user.Username, newChannelPurpose) + message = fmt.Sprintf(i18n.T("app.channel.post_update_channel_purpose_message.updated_to"), user.Username, newChannelPurpose) } else if newChannelPurpose == "" { - message = fmt.Sprintf(utils.T("app.channel.post_update_channel_purpose_message.removed"), user.Username, oldChannelPurpose) + message = fmt.Sprintf(i18n.T("app.channel.post_update_channel_purpose_message.removed"), user.Username, oldChannelPurpose) } else { - message = fmt.Sprintf(utils.T("app.channel.post_update_channel_purpose_message.updated_from"), user.Username, oldChannelPurpose, newChannelPurpose) + message = fmt.Sprintf(i18n.T("app.channel.post_update_channel_purpose_message.updated_from"), user.Username, oldChannelPurpose, newChannelPurpose) } post := &model.Post{ @@ -1565,7 +1566,7 @@ func (a *App) PostUpdateChannelDisplayNameMessage(userID string, channel *model. return model.NewAppError("PostUpdateChannelDisplayNameMessage", "api.channel.post_update_channel_displayname_message_and_forget.retrieve_user.error", nil, err.Error(), http.StatusBadRequest) } - message := fmt.Sprintf(utils.T("api.channel.post_update_channel_displayname_message_and_forget.updated_from"), user.Username, oldChannelDisplayName, newChannelDisplayName) + message := fmt.Sprintf(i18n.T("api.channel.post_update_channel_displayname_message_and_forget.updated_from"), user.Username, oldChannelDisplayName, newChannelDisplayName) post := &model.Post{ ChannelId: channel.Id, @@ -1962,11 +1963,11 @@ func (a *App) JoinChannel(channel *model.Channel, userID string) *model.AppError } func (a *App) postJoinChannelMessage(user *model.User, channel *model.Channel) *model.AppError { - message := fmt.Sprintf(utils.T("api.channel.join_channel.post_and_forget"), user.Username) + message := fmt.Sprintf(i18n.T("api.channel.join_channel.post_and_forget"), user.Username) postType := model.POST_JOIN_CHANNEL if user.IsGuest() { - message = fmt.Sprintf(utils.T("api.channel.guest_join_channel.post_and_forget"), user.Username) + message = fmt.Sprintf(i18n.T("api.channel.guest_join_channel.post_and_forget"), user.Username) postType = model.POST_GUEST_JOIN_CHANNEL } @@ -1990,7 +1991,7 @@ func (a *App) postJoinChannelMessage(user *model.User, channel *model.Channel) * func (a *App) postJoinTeamMessage(user *model.User, channel *model.Channel) *model.AppError { post := &model.Post{ ChannelId: channel.Id, - Message: fmt.Sprintf(utils.T("api.team.join_team.post_and_forget"), user.Username), + Message: fmt.Sprintf(i18n.T("api.team.join_team.post_and_forget"), user.Username), Type: model.POST_JOIN_TEAM, UserId: user.Id, Props: model.StringInterface{ @@ -2087,7 +2088,7 @@ func (a *App) postLeaveChannelMessage(user *model.User, channel *model.Channel) // Message here embeds `@username`, not just `username`, to ensure that mentions // treat this as a username mention even though the user has now left the channel. // The client renders its own system message, ignoring this value altogether. - Message: fmt.Sprintf(utils.T("api.channel.leave.left"), fmt.Sprintf("@%s", user.Username)), + Message: fmt.Sprintf(i18n.T("api.channel.leave.left"), fmt.Sprintf("@%s", user.Username)), Type: model.POST_LEAVE_CHANNEL, UserId: user.Id, Props: model.StringInterface{ @@ -2103,11 +2104,11 @@ func (a *App) postLeaveChannelMessage(user *model.User, channel *model.Channel) } func (a *App) PostAddToChannelMessage(user *model.User, addedUser *model.User, channel *model.Channel, postRootId string) *model.AppError { - message := fmt.Sprintf(utils.T("api.channel.add_member.added"), addedUser.Username, user.Username) + message := fmt.Sprintf(i18n.T("api.channel.add_member.added"), addedUser.Username, user.Username) postType := model.POST_ADD_TO_CHANNEL if addedUser.IsGuest() { - message = fmt.Sprintf(utils.T("api.channel.add_guest.added"), addedUser.Username, user.Username) + message = fmt.Sprintf(i18n.T("api.channel.add_guest.added"), addedUser.Username, user.Username) postType = model.POST_ADD_GUEST_TO_CHANNEL } @@ -2135,7 +2136,7 @@ func (a *App) PostAddToChannelMessage(user *model.User, addedUser *model.User, c func (a *App) postAddToTeamMessage(user *model.User, addedUser *model.User, channel *model.Channel, postRootId string) *model.AppError { post := &model.Post{ ChannelId: channel.Id, - Message: fmt.Sprintf(utils.T("api.team.add_user_to_team.added"), addedUser.Username, user.Username), + Message: fmt.Sprintf(i18n.T("api.team.add_user_to_team.added"), addedUser.Username, user.Username), Type: model.POST_ADD_TO_TEAM, UserId: user.Id, RootId: postRootId, @@ -2160,7 +2161,7 @@ func (a *App) postRemoveFromChannelMessage(removerUserId string, removedUser *mo // Message here embeds `@username`, not just `username`, to ensure that mentions // treat this as a username mention even though the user has now left the channel. // The client renders its own system message, ignoring this value altogether. - Message: fmt.Sprintf(utils.T("api.channel.remove_member.removed"), fmt.Sprintf("@%s", removedUser.Username)), + Message: fmt.Sprintf(i18n.T("api.channel.remove_member.removed"), fmt.Sprintf("@%s", removedUser.Username)), Type: model.POST_REMOVE_FROM_CHANNEL, UserId: removerUserId, Props: model.StringInterface{ @@ -2753,7 +2754,7 @@ func (a *App) postChannelMoveMessage(user *model.User, channel *model.Channel, p post := &model.Post{ ChannelId: channel.Id, - Message: fmt.Sprintf(utils.T("api.team.move_channel.success"), previousTeam.Name), + Message: fmt.Sprintf(i18n.T("api.team.move_channel.success"), previousTeam.Name), Type: model.POST_MOVE_CHANNEL, UserId: user.Id, Props: model.StringInterface{ diff --git a/app/command.go b/app/command.go index b7c8590aef..0f3c017ea5 100644 --- a/app/command.go +++ b/app/command.go @@ -14,12 +14,10 @@ import ( "sync" "unicode" - goi18n "github.com/mattermost/go-i18n/i18n" - "github.com/mattermost/mattermost-server/v5/mlog" "github.com/mattermost/mattermost-server/v5/model" + "github.com/mattermost/mattermost-server/v5/shared/i18n" "github.com/mattermost/mattermost-server/v5/store" - "github.com/mattermost/mattermost-server/v5/utils" ) const ( @@ -28,7 +26,7 @@ const ( type CommandProvider interface { GetTrigger() string - GetCommand(a *App, T goi18n.TranslateFunc) *model.Command + GetCommand(a *App, T i18n.TranslateFunc) *model.Command DoCommand(a *App, args *model.CommandArgs, message string) *model.CommandResponse } @@ -80,7 +78,7 @@ func (a *App) CreateCommandPost(post *model.Post, teamID string, response *model // @openTracingParams teamID // previous ListCommands now ListAutocompleteCommands -func (a *App) ListAutocompleteCommands(teamID string, T goi18n.TranslateFunc) ([]*model.Command, *model.AppError) { +func (a *App) ListAutocompleteCommands(teamID string, T i18n.TranslateFunc) ([]*model.Command, *model.AppError) { commands := make([]*model.Command, 0, 32) seen := make(map[string]bool) @@ -138,7 +136,7 @@ func (a *App) ListTeamCommands(teamID string) ([]*model.Command, *model.AppError return teamCmds, nil } -func (a *App) ListAllCommands(teamID string, T goi18n.TranslateFunc) ([]*model.Command, *model.AppError) { +func (a *App) ListAllCommands(teamID string, T i18n.TranslateFunc) ([]*model.Command, *model.AppError) { commands := make([]*model.Command, 0, 32) seen := make(map[string]bool) for _, value := range commandProviders { @@ -645,7 +643,7 @@ func (a *App) createCommand(cmd *model.Command) (*model.Command, *model.AppError } for _, builtInProvider := range commandProviders { - builtInCommand := builtInProvider.GetCommand(a, utils.T) + builtInCommand := builtInProvider.GetCommand(a, i18n.T) if builtInCommand != nil && cmd.Trigger == builtInCommand.Trigger { return nil, model.NewAppError("CreateCommand", "api.command.duplicate_trigger.app_error", nil, "", http.StatusBadRequest) } diff --git a/app/command_autocomplete_test.go b/app/command_autocomplete_test.go index a0b10660c9..bc257c79ac 100644 --- a/app/command_autocomplete_test.go +++ b/app/command_autocomplete_test.go @@ -7,10 +7,10 @@ import ( "fmt" "testing" - goi18n "github.com/mattermost/go-i18n/i18n" "github.com/stretchr/testify/assert" "github.com/mattermost/mattermost-server/v5/model" + "github.com/mattermost/mattermost-server/v5/shared/i18n" ) func TestParseStaticListArgument(t *testing.T) { @@ -644,7 +644,7 @@ func (p *testProvider) GetTrigger() string { return "bogus" } -func (p *testProvider) GetCommand(a *App, T goi18n.TranslateFunc) *model.Command { +func (p *testProvider) GetCommand(a *App, T i18n.TranslateFunc) *model.Command { top := model.NewAutocompleteData(p.GetTrigger(), "[command]", "Just a test.") top.AddNamedDynamicListArgument("dynaArg", "A dynamic list", "builtin:bogus", true) diff --git a/app/email.go b/app/email.go index f82f16d9c1..9323e0ab92 100644 --- a/app/email.go +++ b/app/email.go @@ -14,7 +14,6 @@ import ( "strings" "time" - "github.com/mattermost/go-i18n/i18n" "github.com/pkg/errors" "github.com/throttled/throttled" "github.com/throttled/throttled/store/memstore" @@ -22,6 +21,7 @@ import ( "github.com/mattermost/mattermost-server/v5/mlog" "github.com/mattermost/mattermost-server/v5/model" "github.com/mattermost/mattermost-server/v5/services/mailservice" + "github.com/mattermost/mattermost-server/v5/shared/i18n" "github.com/mattermost/mattermost-server/v5/utils" ) @@ -88,7 +88,7 @@ func (es *EmailService) setUpRateLimiters() error { } func (es *EmailService) sendChangeUsernameEmail(newUsername, email, locale, siteURL string) *model.AppError { - T := utils.GetUserTranslations(locale) + T := i18n.GetUserTranslations(locale) subject := T("api.templates.username_change_subject", map[string]interface{}{"SiteName": es.srv.Config().TeamSettings.SiteName, @@ -109,7 +109,7 @@ func (es *EmailService) sendChangeUsernameEmail(newUsername, email, locale, site } func (es *EmailService) sendEmailChangeVerifyEmail(newUserEmail, locale, siteURL, token string) *model.AppError { - T := utils.GetUserTranslations(locale) + T := i18n.GetUserTranslations(locale) link := fmt.Sprintf("%s/do_verify_email?token=%s&email=%s", siteURL, token, url.QueryEscape(newUserEmail)) @@ -133,7 +133,7 @@ func (es *EmailService) sendEmailChangeVerifyEmail(newUserEmail, locale, siteURL } func (es *EmailService) sendEmailChangeEmail(oldEmail, newEmail, locale, siteURL string) *model.AppError { - T := utils.GetUserTranslations(locale) + T := i18n.GetUserTranslations(locale) subject := T("api.templates.email_change_subject", map[string]interface{}{"SiteName": es.srv.Config().TeamSettings.SiteName, @@ -154,7 +154,7 @@ func (es *EmailService) sendEmailChangeEmail(oldEmail, newEmail, locale, siteURL } func (es *EmailService) sendVerifyEmail(userEmail, locale, siteURL, token, redirect string) *model.AppError { - T := utils.GetUserTranslations(locale) + T := i18n.GetUserTranslations(locale) link := fmt.Sprintf("%s/do_verify_email?token=%s&email=%s", siteURL, token, url.QueryEscape(userEmail)) if redirect != "" { @@ -187,7 +187,7 @@ func (es *EmailService) sendVerifyEmail(userEmail, locale, siteURL, token, redir } func (es *EmailService) SendSignInChangeEmail(email, method, locale, siteURL string) *model.AppError { - T := utils.GetUserTranslations(locale) + T := i18n.GetUserTranslations(locale) subject := T("api.templates.signin_change_email.subject", map[string]interface{}{"SiteName": es.srv.Config().TeamSettings.SiteName}) @@ -211,7 +211,7 @@ func (es *EmailService) sendWelcomeEmail(userID string, email string, verified b return model.NewAppError("SendWelcomeEmail", "api.user.send_welcome_email_and_forget.failed.error", nil, "Send Email Notifications and Require Email Verification is disabled in the system console", http.StatusInternalServerError) } - T := utils.GetUserTranslations(locale) + T := i18n.GetUserTranslations(locale) serverURL := condenseSiteURL(siteURL) @@ -257,7 +257,7 @@ func (es *EmailService) sendWelcomeEmail(userID string, email string, verified b } func (es *EmailService) sendPasswordChangeEmail(email, method, locale, siteURL string) *model.AppError { - T := utils.GetUserTranslations(locale) + T := i18n.GetUserTranslations(locale) subject := T("api.templates.password_change_subject", map[string]interface{}{"SiteName": es.srv.Config().TeamSettings.SiteName, @@ -278,7 +278,7 @@ func (es *EmailService) sendPasswordChangeEmail(email, method, locale, siteURL s } func (es *EmailService) sendUserAccessTokenAddedEmail(email, locale, siteURL string) *model.AppError { - T := utils.GetUserTranslations(locale) + T := i18n.GetUserTranslations(locale) subject := T("api.templates.user_access_token_subject", map[string]interface{}{"SiteName": es.srv.Config().TeamSettings.SiteName}) @@ -298,7 +298,7 @@ func (es *EmailService) sendUserAccessTokenAddedEmail(email, locale, siteURL str } func (es *EmailService) SendPasswordResetEmail(email string, token *model.Token, locale, siteURL string) (bool, *model.AppError) { - T := utils.GetUserTranslations(locale) + T := i18n.GetUserTranslations(locale) link := fmt.Sprintf("%s/reset_password_complete?token=%s", siteURL, url.QueryEscape(token.Token)) @@ -308,7 +308,7 @@ func (es *EmailService) SendPasswordResetEmail(email string, token *model.Token, bodyPage := es.newEmailTemplate("reset_body", locale) bodyPage.Props["SiteURL"] = siteURL bodyPage.Props["Title"] = T("api.templates.reset_body.title") - bodyPage.Props["Info1"] = utils.TranslateAsHTML(T, "api.templates.reset_body.info1", nil) + bodyPage.Props["Info1"] = i18n.TranslateAsHTML(T, "api.templates.reset_body.info1", nil) bodyPage.Props["Info2"] = T("api.templates.reset_body.info2") bodyPage.Props["ResetUrl"] = link bodyPage.Props["Button"] = T("api.templates.reset_body.button") @@ -321,7 +321,7 @@ func (es *EmailService) SendPasswordResetEmail(email string, token *model.Token, } func (es *EmailService) sendMfaChangeEmail(email string, activated bool, locale, siteURL string) *model.AppError { - T := utils.GetUserTranslations(locale) + T := i18n.GetUserTranslations(locale) subject := T("api.templates.mfa_change_subject", map[string]interface{}{"SiteName": es.srv.Config().TeamSettings.SiteName}) @@ -364,18 +364,18 @@ func (es *EmailService) SendInviteEmails(team *model.Team, senderName string, se for _, invite := range invites { if invite != "" { - subject := utils.T("api.templates.invite_subject", + subject := i18n.T("api.templates.invite_subject", map[string]interface{}{"SenderName": senderName, "TeamDisplayName": team.DisplayName, "SiteName": es.srv.Config().TeamSettings.SiteName}) bodyPage := es.newEmailTemplate("invite_body", "") bodyPage.Props["SiteURL"] = siteURL - bodyPage.Props["Title"] = utils.T("api.templates.invite_body.title") - bodyPage.HTML["Info"] = utils.TranslateAsHTML(utils.T, "api.templates.invite_body.info", + bodyPage.Props["Title"] = i18n.T("api.templates.invite_body.title") + bodyPage.HTML["Info"] = i18n.TranslateAsHTML(i18n.T, "api.templates.invite_body.info", map[string]interface{}{"SenderName": senderName, "TeamDisplayName": team.DisplayName}) - bodyPage.Props["Button"] = utils.T("api.templates.invite_body.button") - bodyPage.HTML["ExtraInfo"] = utils.TranslateAsHTML(utils.T, "api.templates.invite_body.extra_info", + bodyPage.Props["Button"] = i18n.T("api.templates.invite_body.button") + bodyPage.HTML["ExtraInfo"] = i18n.TranslateAsHTML(i18n.T, "api.templates.invite_body.extra_info", map[string]interface{}{"TeamDisplayName": team.DisplayName}) bodyPage.Props["TeamURL"] = siteURL + "/" + team.Name @@ -423,24 +423,24 @@ func (es *EmailService) sendGuestInviteEmails(team *model.Team, channels []*mode for _, invite := range invites { if invite != "" { - subject := utils.T("api.templates.invite_guest_subject", + subject := i18n.T("api.templates.invite_guest_subject", map[string]interface{}{"SenderName": senderName, "TeamDisplayName": team.DisplayName, "SiteName": es.srv.Config().TeamSettings.SiteName}) bodyPage := es.newEmailTemplate("invite_body", "") bodyPage.Props["SiteURL"] = siteURL - bodyPage.Props["Title"] = utils.T("api.templates.invite_body.title") - bodyPage.HTML["Info"] = utils.TranslateAsHTML(utils.T, "api.templates.invite_body_guest.info", + bodyPage.Props["Title"] = i18n.T("api.templates.invite_body.title") + bodyPage.HTML["Info"] = i18n.TranslateAsHTML(i18n.T, "api.templates.invite_body_guest.info", map[string]interface{}{"SenderName": senderName, "TeamDisplayName": team.DisplayName}) - bodyPage.Props["Button"] = utils.T("api.templates.invite_body.button") + bodyPage.Props["Button"] = i18n.T("api.templates.invite_body.button") bodyPage.Props["SenderName"] = senderName bodyPage.Props["SenderId"] = senderUserId bodyPage.Props["Message"] = "" if message != "" { bodyPage.Props["Message"] = message } - bodyPage.HTML["ExtraInfo"] = utils.TranslateAsHTML(utils.T, "api.templates.invite_body.extra_info", + bodyPage.HTML["ExtraInfo"] = i18n.TranslateAsHTML(i18n.T, "api.templates.invite_body.extra_info", map[string]interface{}{"TeamDisplayName": team.DisplayName}) bodyPage.Props["TeamURL"] = siteURL + "/" + team.Name @@ -497,9 +497,9 @@ func (es *EmailService) newEmailTemplate(name, locale string) *utils.HTMLTemplat var localT i18n.TranslateFunc if locale != "" { - localT = utils.GetUserTranslations(locale) + localT = i18n.GetUserTranslations(locale) } else { - localT = utils.T + localT = i18n.T } t.Props["Footer"] = localT("api.templates.email_footer") @@ -521,7 +521,7 @@ func (es *EmailService) newEmailTemplate(name, locale string) *utils.HTMLTemplat } func (es *EmailService) SendDeactivateAccountEmail(email string, locale, siteURL string) *model.AppError { - T := utils.GetUserTranslations(locale) + T := i18n.GetUserTranslations(locale) serverURL := condenseSiteURL(siteURL) @@ -551,7 +551,7 @@ func (es *EmailService) SendRemoveExpiredLicenseEmail(email string, locale, site return err } - T := utils.GetUserTranslations(locale) + T := i18n.GetUserTranslations(locale) subject := T("api.templates.remove_expired_license.subject", map[string]interface{}{"SiteName": es.srv.Config().TeamSettings.SiteName}) @@ -623,7 +623,7 @@ func (es *EmailService) CreateVerifyEmailToken(userID string, newEmail string) ( } func (es *EmailService) SendAtUserLimitWarningEmail(email string, locale string, siteURL string) (bool, *model.AppError) { - T := utils.GetUserTranslations(locale) + T := i18n.GetUserTranslations(locale) subject := T("api.templates.at_limit_subject") @@ -646,7 +646,7 @@ func (es *EmailService) SendAtUserLimitWarningEmail(email string, locale string, // SendUpgradeEmail formats an email template and sends an email to an admin specified in the email arg func (es *EmailService) SendUpgradeEmail(user, email, locale, siteURL, action string) (bool, *model.AppError) { - T := utils.GetUserTranslations(locale) + T := i18n.GetUserTranslations(locale) bodyPage := es.newEmailTemplate("cloud_upgrade_request_email", locale) @@ -674,7 +674,7 @@ func (es *EmailService) SendUpgradeEmail(user, email, locale, siteURL, action st } func (es *EmailService) SendOverUserLimitWarningEmail(email string, locale string, siteURL string) (bool, *model.AppError) { - T := utils.GetUserTranslations(locale) + T := i18n.GetUserTranslations(locale) subject := T("api.templates.over_limit_subject") @@ -696,7 +696,7 @@ func (es *EmailService) SendOverUserLimitWarningEmail(email string, locale strin } func (es *EmailService) SendOverUserLimitThirtyDayWarningEmail(email string, locale string, siteURL string) (bool, *model.AppError) { - T := utils.GetUserTranslations(locale) + T := i18n.GetUserTranslations(locale) subject := T("api.templates.over_limit_30_days_subject") @@ -721,7 +721,7 @@ func (es *EmailService) SendOverUserLimitThirtyDayWarningEmail(email string, loc } func (es *EmailService) SendOverUserLimitNinetyDayWarningEmail(email string, locale string, siteURL string, overLimitDate string) (bool, *model.AppError) { - T := utils.GetUserTranslations(locale) + T := i18n.GetUserTranslations(locale) subject := T("api.templates.over_limit_90_days_subject") @@ -745,7 +745,7 @@ func (es *EmailService) SendOverUserLimitNinetyDayWarningEmail(email string, loc } func (es *EmailService) SendOverUserLimitWorkspaceSuspendedWarningEmail(email string, locale string, siteURL string) (bool, *model.AppError) { - T := utils.GetUserTranslations(locale) + T := i18n.GetUserTranslations(locale) subject := T("api.templates.over_limit_suspended_subject") @@ -767,7 +767,7 @@ func (es *EmailService) SendOverUserLimitWorkspaceSuspendedWarningEmail(email st } func (es *EmailService) SendOverUserFourteenDayWarningEmail(email string, locale string, siteURL string, overLimitDate string) (bool, *model.AppError) { - T := utils.GetUserTranslations(locale) + T := i18n.GetUserTranslations(locale) subject := T("api.templates.over_limit_14_days_subject") @@ -788,7 +788,7 @@ func (es *EmailService) SendOverUserFourteenDayWarningEmail(email string, locale } func (es *EmailService) SendOverUserSevenDayWarningEmail(email string, locale string, siteURL string) (bool, *model.AppError) { - T := utils.GetUserTranslations(locale) + T := i18n.GetUserTranslations(locale) subject := T("api.templates.over_limit_7_days_subject") @@ -828,7 +828,7 @@ func (es *EmailService) SendSuspensionEmailToSupport(email string, installationI } func (es *EmailService) SendPaymentFailedEmail(email string, locale string, failedPayment *model.FailedPayment, siteURL string) (bool, *model.AppError) { - T := utils.GetUserTranslations(locale) + T := i18n.GetUserTranslations(locale) subject := T("api.templates.payment_failed.subject") @@ -853,7 +853,7 @@ func (es *EmailService) SendPaymentFailedEmail(email string, locale string, fail } func (es *EmailService) SendNoCardPaymentFailedEmail(email string, locale string, siteURL string) *model.AppError { - T := utils.GetUserTranslations(locale) + T := i18n.GetUserTranslations(locale) subject := T("api.templates.payment_failed_no_card.subject") diff --git a/app/email_batching.go b/app/email_batching.go index 23f4d8df07..1a57a21224 100644 --- a/app/email_batching.go +++ b/app/email_batching.go @@ -12,10 +12,9 @@ import ( "sync" "time" - "github.com/mattermost/go-i18n/i18n" - "github.com/mattermost/mattermost-server/v5/mlog" "github.com/mattermost/mattermost-server/v5/model" + "github.com/mattermost/mattermost-server/v5/shared/i18n" "github.com/mattermost/mattermost-server/v5/utils" ) @@ -201,7 +200,7 @@ func (es *EmailService) sendBatchedEmailNotification(userID string, notification return } - translateFunc := utils.GetUserTranslations(user.Locale) + translateFunc := i18n.GetUserTranslations(user.Locale) displayNameFormat := *es.srv.Config().TeamSettings.TeammateNameDisplay var contents string diff --git a/app/expirynotify.go b/app/expirynotify.go index ed297355a6..36ffc373aa 100644 --- a/app/expirynotify.go +++ b/app/expirynotify.go @@ -8,7 +8,7 @@ import ( "github.com/mattermost/mattermost-server/v5/mlog" "github.com/mattermost/mattermost-server/v5/model" - "github.com/mattermost/mattermost-server/v5/utils" + "github.com/mattermost/mattermost-server/v5/shared/i18n" ) const ( @@ -80,7 +80,7 @@ func (a *App) getSessionExpiredPushMessage(session *model.Session) string { if err == nil { locale = user.Locale } - T := utils.GetUserTranslations(locale) + T := i18n.GetUserTranslations(locale) siteName := *a.Config().TeamSettings.SiteName props := map[string]interface{}{"siteName": siteName, "daysCount": *a.Config().ServiceSettings.SessionLengthMobileInDays} diff --git a/app/integration_action.go b/app/integration_action.go index 26c6a8d9d6..5b2612066e 100644 --- a/app/integration_action.go +++ b/app/integration_action.go @@ -34,6 +34,7 @@ import ( "github.com/mattermost/mattermost-server/v5/mlog" "github.com/mattermost/mattermost-server/v5/model" + "github.com/mattermost/mattermost-server/v5/shared/i18n" "github.com/mattermost/mattermost-server/v5/store" "github.com/mattermost/mattermost-server/v5/utils" ) @@ -456,12 +457,12 @@ func (a *App) doLocalWarnMetricsRequest(rawURL string, upstreamRequest *model.Po } isE0Edition := (model.BuildEnterpriseReady == "true") // license == nil was already validated upstream - _, warnMetricDisplayTexts := a.getWarnMetricStatusAndDisplayTextsForId(warnMetricId, utils.T, isE0Edition) + _, warnMetricDisplayTexts := a.getWarnMetricStatusAndDisplayTextsForId(warnMetricId, i18n.T, isE0Edition) botPost.Message = ":white_check_mark: " + warnMetricDisplayTexts.BotSuccessMessage if isE0Edition { if appErr = a.RequestLicenseAndAckWarnMetric(warnMetricId, true); appErr != nil { - botPost.Message = ":warning: " + utils.T("api.server.warn_metric.bot_response.start_trial_failure.message") + botPost.Message = ":warning: " + i18n.T("api.server.warn_metric.bot_response.start_trial_failure.message") } } else { forceAck := upstreamRequest.Context["force_ack"].(bool) @@ -470,12 +471,12 @@ func (a *App) doLocalWarnMetricsRequest(rawURL string, upstreamRequest *model.Po return appErr } mailtoLinkText := a.buildWarnMetricMailtoLink(warnMetricId, user) - botPost.Message = ":warning: " + utils.T("api.server.warn_metric.bot_response.notification_failure.message") + botPost.Message = ":warning: " + i18n.T("api.server.warn_metric.bot_response.notification_failure.message") actions := []*model.PostAction{} actions = append(actions, &model.PostAction{ Id: "emailUs", - Name: utils.T("api.server.warn_metric.email_us"), + Name: i18n.T("api.server.warn_metric.email_us"), Type: model.POST_ACTION_TYPE_BUTTON, Options: []*model.PostActionOptions{ { @@ -500,7 +501,7 @@ func (a *App) doLocalWarnMetricsRequest(rawURL string, upstreamRequest *model.Po AuthorName: "", Title: "", Actions: actions, - Text: utils.T("api.server.warn_metric.bot_response.notification_failure.body"), + Text: i18n.T("api.server.warn_metric.bot_response.notification_failure.body"), }} model.ParseSlackAttachment(botPost, attachements) } @@ -527,7 +528,7 @@ func (mlc *MailToLinkContent) ToJson() string { } func (a *App) buildWarnMetricMailtoLink(warnMetricId string, user *model.User) string { - T := utils.GetUserTranslations(user.Locale) + T := i18n.GetUserTranslations(user.Locale) _, warnMetricDisplayTexts := a.getWarnMetricStatusAndDisplayTextsForId(warnMetricId, T, false) mailBody := warnMetricDisplayTexts.EmailBody @@ -540,7 +541,7 @@ func (a *App) buildWarnMetricMailtoLink(warnMetricId string, user *model.User) s if err != nil { mlog.Warn("Error retrieving the number of registered users", mlog.Err(err)) } else { - mailBody += utils.T("api.server.warn_metric.bot_response.mailto_registered_users_header", map[string]interface{}{"NoRegisteredUsers": registeredUsersCount}) + mailBody += i18n.T("api.server.warn_metric.bot_response.mailto_registered_users_header", map[string]interface{}{"NoRegisteredUsers": registeredUsersCount}) mailBody += "\r\n" } diff --git a/app/layer_generators/opentracing_layer.go.tmpl b/app/layer_generators/opentracing_layer.go.tmpl index c32c564817..c441d4bace 100644 --- a/app/layer_generators/opentracing_layer.go.tmpl +++ b/app/layer_generators/opentracing_layer.go.tmpl @@ -9,7 +9,6 @@ package opentracing import ( "github.com/opentracing/opentracing-go/ext" spanlog "github.com/opentracing/opentracing-go/log" - goi18n "github.com/mattermost/go-i18n/i18n" ) type {{.Name}} struct { diff --git a/app/ldap.go b/app/ldap.go index 8facf82651..49a17874a9 100644 --- a/app/ldap.go +++ b/app/ldap.go @@ -10,7 +10,7 @@ import ( "github.com/mattermost/mattermost-server/v5/mlog" "github.com/mattermost/mattermost-server/v5/model" - "github.com/mattermost/mattermost-server/v5/utils" + "github.com/mattermost/mattermost-server/v5/shared/i18n" ) func (a *App) SyncLdap() { @@ -150,7 +150,7 @@ func (a *App) SwitchLdapToEmail(ldapPassword, code, email, newPassword string) ( return "", err } - T := utils.GetUserTranslations(user.Locale) + T := i18n.GetUserTranslations(user.Locale) a.Srv().Go(func() { if err := a.Srv().EmailService.SendSignInChangeEmail(user.Email, T("api.templates.signin_change_email.body.method_email"), user.Locale, a.GetSiteURL()); err != nil { diff --git a/app/notification.go b/app/notification.go index 00702ca306..f179b06138 100644 --- a/app/notification.go +++ b/app/notification.go @@ -16,8 +16,8 @@ import ( "github.com/mattermost/mattermost-server/v5/mlog" "github.com/mattermost/mattermost-server/v5/model" + "github.com/mattermost/mattermost-server/v5/shared/i18n" "github.com/mattermost/mattermost-server/v5/store" - "github.com/mattermost/mattermost-server/v5/utils" "github.com/mattermost/mattermost-server/v5/utils/markdown" ) @@ -245,7 +245,7 @@ func (a *App) SendNotifications(post *model.Post, team *model.Team, channel *mod // Check for channel-wide mentions in channels that have too many members for those to work if int64(len(profileMap)) > *a.Config().TeamSettings.MaxNotificationsPerChannel { - T := utils.GetUserTranslations(sender.Locale) + T := i18n.GetUserTranslations(sender.Locale) if mentions.HereMentioned { a.SendEphemeralPost( @@ -486,7 +486,7 @@ func (a *App) userAllowsEmail(user *model.User, channelMemberNotificationProps m } func (a *App) sendNoUsersNotifiedByGroupInChannel(sender *model.User, post *model.Post, channel *model.Channel, group *model.Group) { - T := utils.GetUserTranslations(sender.Locale) + T := i18n.GetUserTranslations(sender.Locale) ephemeralPost := &model.Post{ UserId: sender.Id, RootId: post.RootId, @@ -586,7 +586,7 @@ func makeOutOfChannelMentionPost(sender *model.User, post *model.Post, outOfChan ogUsers := model.UserSlice(outOfGroupsUsers) ogUsernames := ogUsers.Usernames() - T := utils.GetUserTranslations(sender.Locale) + T := i18n.GetUserTranslations(sender.Locale) ephemeralPostId := model.NewId() var message string @@ -1003,7 +1003,7 @@ func (n *PostNotification) GetChannelName(userNameFormat, excludeId string) stri // and whether or not the username has been overridden by an integration. func (n *PostNotification) GetSenderName(userNameFormat string, overridesAllowed bool) string { if n.Post.IsSystemMessage() { - return utils.T("system.message.name") + return i18n.T("system.message.name") } if overridesAllowed && n.Channel.Type != model.CHANNEL_DIRECT { diff --git a/app/notification_email.go b/app/notification_email.go index 6be69f0469..3b33daeab8 100644 --- a/app/notification_email.go +++ b/app/notification_email.go @@ -13,10 +13,9 @@ import ( "strings" "time" - "github.com/mattermost/go-i18n/i18n" - "github.com/mattermost/mattermost-server/v5/mlog" "github.com/mattermost/mattermost-server/v5/model" + "github.com/mattermost/mattermost-server/v5/shared/i18n" "github.com/mattermost/mattermost-server/v5/utils" ) @@ -67,7 +66,7 @@ func (a *App) sendNotificationEmail(notification *PostNotification, user *model. // fall back to sending a single email if we can't batch it for some reason } - translateFunc := utils.GetUserTranslations(user.Locale) + translateFunc := i18n.GetUserTranslations(user.Locale) var useMilitaryTime bool if data, err := a.Srv().Store.Preference().Get(user.Id, model.PREFERENCE_CATEGORY_DISPLAY_SETTINGS, model.PREFERENCE_NAME_USE_MILITARY_TIME); err != nil { diff --git a/app/notification_email_test.go b/app/notification_email_test.go index f40f89da66..cee9500e8e 100644 --- a/app/notification_email_test.go +++ b/app/notification_email_test.go @@ -17,8 +17,8 @@ import ( "github.com/mattermost/mattermost-server/v5/model" "github.com/mattermost/mattermost-server/v5/services/timezones" + "github.com/mattermost/mattermost-server/v5/shared/i18n" "github.com/mattermost/mattermost-server/v5/store/storetest/mocks" - "github.com/mattermost/mattermost-server/v5/utils" ) func TestGetDirectMessageNotificationEmailSubject(t *testing.T) { @@ -27,7 +27,7 @@ func TestGetDirectMessageNotificationEmailSubject(t *testing.T) { post := &model.Post{ CreateAt: 1501804801000, } - translateFunc := utils.GetUserTranslations("en") + translateFunc := i18n.GetUserTranslations("en") subject := getDirectMessageNotificationEmailSubject(user, post, translateFunc, "http://localhost:8065", "@sender", true) require.Regexp(t, regexp.MustCompile("^"+regexp.QuoteMeta(expectedPrefix)), subject, fmt.Sprintf("Expected subject line prefix '%s', got %s", expectedPrefix, subject)) } @@ -38,7 +38,7 @@ func TestGetGroupMessageNotificationEmailSubjectFull(t *testing.T) { post := &model.Post{ CreateAt: 1501804801000, } - translateFunc := utils.GetUserTranslations("en") + translateFunc := i18n.GetUserTranslations("en") emailNotificationContentsType := model.EMAIL_NOTIFICATION_CONTENTS_FULL subject := getGroupMessageNotificationEmailSubject(user, post, translateFunc, "http://localhost:8065", "sender", emailNotificationContentsType, true) require.Regexp(t, regexp.MustCompile("^"+regexp.QuoteMeta(expectedPrefix)), subject, fmt.Sprintf("Expected subject line prefix '%s', got %s", expectedPrefix, subject)) @@ -50,7 +50,7 @@ func TestGetGroupMessageNotificationEmailSubjectGeneric(t *testing.T) { post := &model.Post{ CreateAt: 1501804801000, } - translateFunc := utils.GetUserTranslations("en") + translateFunc := i18n.GetUserTranslations("en") emailNotificationContentsType := model.EMAIL_NOTIFICATION_CONTENTS_GENERIC subject := getGroupMessageNotificationEmailSubject(user, post, translateFunc, "http://localhost:8065", "sender", emailNotificationContentsType, true) require.Regexp(t, regexp.MustCompile("^"+regexp.QuoteMeta(expectedPrefix)), subject, fmt.Sprintf("Expected subject line prefix '%s', got %s", expectedPrefix, subject)) @@ -62,7 +62,7 @@ func TestGetNotificationEmailSubject(t *testing.T) { post := &model.Post{ CreateAt: 1501804801000, } - translateFunc := utils.GetUserTranslations("en") + translateFunc := i18n.GetUserTranslations("en") subject := getNotificationEmailSubject(user, post, translateFunc, "http://localhost:8065", "team", true) require.Regexp(t, regexp.MustCompile("^"+regexp.QuoteMeta(expectedPrefix)), subject, fmt.Sprintf("Expected subject line prefix '%s', got %s", expectedPrefix, subject)) } @@ -84,7 +84,7 @@ func TestGetNotificationEmailBodyFullNotificationPublicChannel(t *testing.T) { teamName := "testteam" teamURL := "http://localhost:8065/testteam" emailNotificationContentsType := model.EMAIL_NOTIFICATION_CONTENTS_FULL - translateFunc := utils.GetUserTranslations("en") + translateFunc := i18n.GetUserTranslations("en") storeMock := th.App.Srv().Store.(*mocks.Store) teamStoreMock := mocks.TeamStore{} @@ -116,7 +116,7 @@ func TestGetNotificationEmailBodyFullNotificationGroupChannel(t *testing.T) { teamName := "testteam" teamURL := "http://localhost:8065/testteam" emailNotificationContentsType := model.EMAIL_NOTIFICATION_CONTENTS_FULL - translateFunc := utils.GetUserTranslations("en") + translateFunc := i18n.GetUserTranslations("en") storeMock := th.App.Srv().Store.(*mocks.Store) teamStoreMock := mocks.TeamStore{} @@ -148,7 +148,7 @@ func TestGetNotificationEmailBodyFullNotificationPrivateChannel(t *testing.T) { teamName := "testteam" teamURL := "http://localhost:8065/testteam" emailNotificationContentsType := model.EMAIL_NOTIFICATION_CONTENTS_FULL - translateFunc := utils.GetUserTranslations("en") + translateFunc := i18n.GetUserTranslations("en") storeMock := th.App.Srv().Store.(*mocks.Store) teamStoreMock := mocks.TeamStore{} @@ -180,7 +180,7 @@ func TestGetNotificationEmailBodyFullNotificationDirectChannel(t *testing.T) { teamName := "testteam" teamURL := "http://localhost:8065/testteam" emailNotificationContentsType := model.EMAIL_NOTIFICATION_CONTENTS_FULL - translateFunc := utils.GetUserTranslations("en") + translateFunc := i18n.GetUserTranslations("en") storeMock := th.App.Srv().Store.(*mocks.Store) teamStoreMock := mocks.TeamStore{} @@ -215,7 +215,7 @@ func TestGetNotificationEmailBodyFullNotificationLocaleTimeWithTimezone(t *testi teamName := "testteam" teamURL := "http://localhost:8065/testteam" emailNotificationContentsType := model.EMAIL_NOTIFICATION_CONTENTS_FULL - translateFunc := utils.GetUserTranslations("en") + translateFunc := i18n.GetUserTranslations("en") storeMock := th.App.Srv().Store.(*mocks.Store) teamStoreMock := mocks.TeamStore{} @@ -248,7 +248,7 @@ func TestGetNotificationEmailBodyFullNotificationLocaleTimeNoTimezone(t *testing teamName := "testteam" teamURL := "http://localhost:8065/testteam" emailNotificationContentsType := model.EMAIL_NOTIFICATION_CONTENTS_FULL - translateFunc := utils.GetUserTranslations("en") + translateFunc := i18n.GetUserTranslations("en") storeMock := th.App.Srv().Store.(*mocks.Store) teamStoreMock := mocks.TeamStore{} @@ -300,7 +300,7 @@ func TestGetNotificationEmailBodyFullNotificationLocaleTime12Hour(t *testing.T) teamName := "testteam" teamURL := "http://localhost:8065/testteam" emailNotificationContentsType := model.EMAIL_NOTIFICATION_CONTENTS_FULL - translateFunc := utils.GetUserTranslations("en") + translateFunc := i18n.GetUserTranslations("en") storeMock := th.App.Srv().Store.(*mocks.Store) teamStoreMock := mocks.TeamStore{} @@ -333,7 +333,7 @@ func TestGetNotificationEmailBodyFullNotificationLocaleTime24Hour(t *testing.T) teamName := "testteam" teamURL := "http://localhost:8065/testteam" emailNotificationContentsType := model.EMAIL_NOTIFICATION_CONTENTS_FULL - translateFunc := utils.GetUserTranslations("en") + translateFunc := i18n.GetUserTranslations("en") storeMock := th.App.Srv().Store.(*mocks.Store) teamStoreMock := mocks.TeamStore{} @@ -363,7 +363,7 @@ func TestGetNotificationEmailBodyGenericNotificationPublicChannel(t *testing.T) teamName := "testteam" teamURL := "http://localhost:8065/testteam" emailNotificationContentsType := model.EMAIL_NOTIFICATION_CONTENTS_GENERIC - translateFunc := utils.GetUserTranslations("en") + translateFunc := i18n.GetUserTranslations("en") storeMock := th.App.Srv().Store.(*mocks.Store) teamStoreMock := mocks.TeamStore{} @@ -394,7 +394,7 @@ func TestGetNotificationEmailBodyGenericNotificationGroupChannel(t *testing.T) { teamName := "testteam" teamURL := "http://localhost:8065/testteam" emailNotificationContentsType := model.EMAIL_NOTIFICATION_CONTENTS_GENERIC - translateFunc := utils.GetUserTranslations("en") + translateFunc := i18n.GetUserTranslations("en") storeMock := th.App.Srv().Store.(*mocks.Store) teamStoreMock := mocks.TeamStore{} @@ -425,7 +425,7 @@ func TestGetNotificationEmailBodyGenericNotificationPrivateChannel(t *testing.T) teamName := "testteam" teamURL := "http://localhost:8065/testteam" emailNotificationContentsType := model.EMAIL_NOTIFICATION_CONTENTS_GENERIC - translateFunc := utils.GetUserTranslations("en") + translateFunc := i18n.GetUserTranslations("en") storeMock := th.App.Srv().Store.(*mocks.Store) teamStoreMock := mocks.TeamStore{} @@ -456,7 +456,7 @@ func TestGetNotificationEmailBodyGenericNotificationDirectChannel(t *testing.T) teamName := "testteam" teamURL := "http://localhost:8065/testteam" emailNotificationContentsType := model.EMAIL_NOTIFICATION_CONTENTS_GENERIC - translateFunc := utils.GetUserTranslations("en") + translateFunc := i18n.GetUserTranslations("en") storeMock := th.App.Srv().Store.(*mocks.Store) teamStoreMock := mocks.TeamStore{} @@ -489,7 +489,7 @@ func TestGetNotificationEmailEscapingChars(t *testing.T) { teamName := "testteam" teamURL := "http://localhost:8065/testteam" emailNotificationContentsType := model.EMAIL_NOTIFICATION_CONTENTS_FULL - translateFunc := utils.GetUserTranslations("en") + translateFunc := i18n.GetUserTranslations("en") storeMock := th.App.Srv().Store.(*mocks.Store) teamStoreMock := mocks.TeamStore{} @@ -528,7 +528,7 @@ func TestGetNotificationEmailBodyPublicChannelMention(t *testing.T) { teamName := "testteam" teamURL := "http://localhost:8065/testteam" emailNotificationContentsType := model.EMAIL_NOTIFICATION_CONTENTS_FULL - translateFunc := utils.GetUserTranslations("en") + translateFunc := i18n.GetUserTranslations("en") storeMock := th.App.Srv().Store.(*mocks.Store) teamStoreMock := mocks.TeamStore{} @@ -593,7 +593,7 @@ func TestGetNotificationEmailBodyMultiPublicChannelMention(t *testing.T) { teamName := "testteam" teamURL := "http://localhost:8065/testteam" emailNotificationContentsType := model.EMAIL_NOTIFICATION_CONTENTS_FULL - translateFunc := utils.GetUserTranslations("en") + translateFunc := i18n.GetUserTranslations("en") storeMock := th.App.Srv().Store.(*mocks.Store) teamStoreMock := mocks.TeamStore{} @@ -641,7 +641,7 @@ func TestGetNotificationEmailBodyPrivateChannelMention(t *testing.T) { teamName := "testteam" teamURL := "http://localhost:8065/testteam" emailNotificationContentsType := model.EMAIL_NOTIFICATION_CONTENTS_FULL - translateFunc := utils.GetUserTranslations("en") + translateFunc := i18n.GetUserTranslations("en") storeMock := th.App.Srv().Store.(*mocks.Store) teamStoreMock := mocks.TeamStore{} @@ -790,7 +790,7 @@ func TestLandingLink(t *testing.T) { teamName := "testteam" teamURL := "http://localhost:8065/landing#/testteam" emailNotificationContentsType := model.EMAIL_NOTIFICATION_CONTENTS_FULL - translateFunc := utils.GetUserTranslations("en") + translateFunc := i18n.GetUserTranslations("en") storeMock := th.App.Srv().Store.(*mocks.Store) teamStoreMock := mocks.TeamStore{} @@ -819,7 +819,7 @@ func TestLandingLinkPermalink(t *testing.T) { teamName := "testteam" teamURL := "http://localhost:8065/landing#/testteam" emailNotificationContentsType := model.EMAIL_NOTIFICATION_CONTENTS_FULL - translateFunc := utils.GetUserTranslations("en") + translateFunc := i18n.GetUserTranslations("en") storeMock := th.App.Srv().Store.(*mocks.Store) teamStoreMock := mocks.TeamStore{} diff --git a/app/notification_push.go b/app/notification_push.go index 53eadda405..988579e8af 100644 --- a/app/notification_push.go +++ b/app/notification_push.go @@ -11,12 +11,11 @@ import ( "strings" "sync" - "github.com/mattermost/go-i18n/i18n" "github.com/pkg/errors" "github.com/mattermost/mattermost-server/v5/mlog" "github.com/mattermost/mattermost-server/v5/model" - "github.com/mattermost/mattermost-server/v5/utils" + "github.com/mattermost/mattermost-server/v5/shared/i18n" ) type notificationType string @@ -533,7 +532,7 @@ func (a *App) BuildPushNotificationMessage(contentsConfig string, post *model.Po } func (a *App) buildIdLoadedPushNotificationMessage(post *model.Post, user *model.User) *model.PushNotification { - userLocale := utils.GetUserTranslations(user.Locale) + userLocale := i18n.GetUserTranslations(user.Locale) msg := &model.PushNotification{ PostId: post.Id, ChannelId: post.ChannelId, @@ -588,7 +587,7 @@ func (a *App) buildFullPushNotificationMessage(contentsConfig string, post *mode } } - userLocale := utils.GetUserTranslations(user.Locale) + userLocale := i18n.GetUserTranslations(user.Locale) hasFiles := post.FileIds != nil && len(post.FileIds) > 0 msg.Message = a.getPushNotificationMessage( diff --git a/app/notification_push_test.go b/app/notification_push_test.go index 421e6f1f1a..3497ca9b27 100644 --- a/app/notification_push_test.go +++ b/app/notification_push_test.go @@ -17,9 +17,9 @@ import ( "github.com/mattermost/mattermost-server/v5/config" "github.com/mattermost/mattermost-server/v5/model" + "github.com/mattermost/mattermost-server/v5/shared/i18n" "github.com/mattermost/mattermost-server/v5/store/storetest/mocks" "github.com/mattermost/mattermost-server/v5/testlib" - "github.com/mattermost/mattermost-server/v5/utils" ) func TestDoesNotifyPropsAllowPushNotification(t *testing.T) { @@ -914,7 +914,7 @@ func TestGetPushNotificationMessage(t *testing.T) { "user", tc.ChannelType, tc.replyToThreadType, - utils.GetUserTranslations(locale), + i18n.GetUserTranslations(locale), ) assert.Equal(t, tc.ExpectedMessage, actualMessage) diff --git a/app/notification_test.go b/app/notification_test.go index 59bf924338..668820ff00 100644 --- a/app/notification_test.go +++ b/app/notification_test.go @@ -11,6 +11,7 @@ import ( "github.com/stretchr/testify/require" "github.com/mattermost/mattermost-server/v5/model" + "github.com/mattermost/mattermost-server/v5/shared/i18n" "github.com/mattermost/mattermost-server/v5/utils" ) @@ -1821,7 +1822,7 @@ func TestPostNotificationGetSenderName(t *testing.T) { }, "system message": { post: &model.Post{Type: model.POST_SYSTEM_MESSAGE_PREFIX + "custom"}, - expected: utils.T("system.message.name"), + expected: i18n.T("system.message.name"), }, "overridden username": { post: overriddenPost, diff --git a/app/oauth.go b/app/oauth.go index 42a70ea7e7..f289de3aaf 100644 --- a/app/oauth.go +++ b/app/oauth.go @@ -20,6 +20,7 @@ import ( "github.com/mattermost/mattermost-server/v5/einterfaces" "github.com/mattermost/mattermost-server/v5/mlog" "github.com/mattermost/mattermost-server/v5/model" + "github.com/mattermost/mattermost-server/v5/shared/i18n" "github.com/mattermost/mattermost-server/v5/store" "github.com/mattermost/mattermost-server/v5/utils" ) @@ -964,7 +965,7 @@ func (a *App) SwitchOAuthToEmail(email, password, requesterId string) (string, * return "", err } - T := utils.GetUserTranslations(user.Locale) + T := i18n.GetUserTranslations(user.Locale) a.Srv().Go(func() { if err := a.Srv().EmailService.SendSignInChangeEmail(user.Email, T("api.templates.signin_change_email.body.method_email"), user.Locale, a.GetSiteURL()); err != nil { diff --git a/app/opentracing/opentracing_layer.go b/app/opentracing/opentracing_layer.go index 97095820cc..054e367fe3 100644 --- a/app/opentracing/opentracing_layer.go +++ b/app/opentracing/opentracing_layer.go @@ -18,8 +18,6 @@ import ( "time" "github.com/dyatlov/go-opengraph/opengraph" - "github.com/mattermost/go-i18n/i18n" - goi18n "github.com/mattermost/go-i18n/i18n" "github.com/mattermost/mattermost-server/v5/app" "github.com/mattermost/mattermost-server/v5/audit" "github.com/mattermost/mattermost-server/v5/einterfaces" @@ -32,6 +30,7 @@ import ( "github.com/mattermost/mattermost-server/v5/services/searchengine" "github.com/mattermost/mattermost-server/v5/services/timezones" "github.com/mattermost/mattermost-server/v5/services/tracing" + "github.com/mattermost/mattermost-server/v5/shared/i18n" "github.com/mattermost/mattermost-server/v5/store" "github.com/opentracing/opentracing-go/ext" spanlog "github.com/opentracing/opentracing-go/log" @@ -10377,7 +10376,7 @@ func (a *OpenTracingAppLayer) LimitedClientConfigWithComputed() map[string]strin return resultVar0 } -func (a *OpenTracingAppLayer) ListAllCommands(teamID string, T goi18n.TranslateFunc) ([]*model.Command, *model.AppError) { +func (a *OpenTracingAppLayer) ListAllCommands(teamID string, T i18n.TranslateFunc) ([]*model.Command, *model.AppError) { origCtx := a.ctx span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.ListAllCommands") @@ -10399,7 +10398,7 @@ func (a *OpenTracingAppLayer) ListAllCommands(teamID string, T goi18n.TranslateF return resultVar0, resultVar1 } -func (a *OpenTracingAppLayer) ListAutocompleteCommands(teamID string, T goi18n.TranslateFunc) ([]*model.Command, *model.AppError) { +func (a *OpenTracingAppLayer) ListAutocompleteCommands(teamID string, T i18n.TranslateFunc) ([]*model.Command, *model.AppError) { origCtx := a.ctx span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.ListAutocompleteCommands") @@ -10858,7 +10857,7 @@ func (a *OpenTracingAppLayer) NewPluginAPI(manifest *model.Manifest) plugin.API return resultVar0 } -func (a *OpenTracingAppLayer) NewWebConn(ws net.Conn, session model.Session, t goi18n.TranslateFunc, locale string) *app.WebConn { +func (a *OpenTracingAppLayer) NewWebConn(ws net.Conn, session model.Session, t i18n.TranslateFunc, locale string) *app.WebConn { origCtx := a.ctx span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.NewWebConn") diff --git a/app/plugin_api.go b/app/plugin_api.go index 8efe843445..3b40613ac7 100644 --- a/app/plugin_api.go +++ b/app/plugin_api.go @@ -16,7 +16,7 @@ import ( "github.com/mattermost/mattermost-server/v5/mlog" "github.com/mattermost/mattermost-server/v5/model" - "github.com/mattermost/mattermost-server/v5/utils" + "github.com/mattermost/mattermost-server/v5/shared/i18n" ) type PluginAPI struct { @@ -76,7 +76,7 @@ func (api *PluginAPI) ExecuteSlashCommand(commandArgs *model.CommandArgs) (*mode if appErr != nil { return nil, appErr } - commandArgs.T = utils.GetUserTranslations(user.Locale) + commandArgs.T = i18n.GetUserTranslations(user.Locale) commandArgs.SiteURL = api.app.GetSiteURL() response, appErr := api.app.ExecuteCommand(commandArgs) if appErr != nil { @@ -1007,7 +1007,7 @@ func (api *PluginAPI) ListBuiltInCommands() ([]*model.Command, error) { seen := make(map[string]bool) for _, value := range commandProviders { - if cmd := value.GetCommand(api.app, utils.T); cmd != nil { + if cmd := value.GetCommand(api.app, i18n.T); cmd != nil { cpy := *cmd if cpy.AutoComplete && !seen[cpy.Trigger] { cpy.Sanitize() diff --git a/app/plugin_api_test.go b/app/plugin_api_test.go index 1fedff1949..5dfdb68002 100644 --- a/app/plugin_api_test.go +++ b/app/plugin_api_test.go @@ -25,10 +25,10 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" - goi18n "github.com/mattermost/go-i18n/i18n" "github.com/mattermost/mattermost-server/v5/einterfaces/mocks" "github.com/mattermost/mattermost-server/v5/model" "github.com/mattermost/mattermost-server/v5/plugin" + "github.com/mattermost/mattermost-server/v5/shared/i18n" "github.com/mattermost/mattermost-server/v5/utils" "github.com/mattermost/mattermost-server/v5/utils/fileutils" ) @@ -1689,7 +1689,7 @@ type MockSlashCommandProvider struct { func (*MockSlashCommandProvider) GetTrigger() string { return "mock" } -func (*MockSlashCommandProvider) GetCommand(a *App, T goi18n.TranslateFunc) *model.Command { +func (*MockSlashCommandProvider) GetCommand(a *App, T i18n.TranslateFunc) *model.Command { return &model.Command{ Trigger: "mock", AutoComplete: true, diff --git a/app/plugin_commands_test.go b/app/plugin_commands_test.go index 1d2ecb78a8..cafe469eb1 100644 --- a/app/plugin_commands_test.go +++ b/app/plugin_commands_test.go @@ -10,7 +10,7 @@ import ( "github.com/stretchr/testify/require" "github.com/mattermost/mattermost-server/v5/model" - "github.com/mattermost/mattermost-server/v5/utils" + "github.com/mattermost/mattermost-server/v5/shared/i18n" ) func TestPluginCommand(t *testing.T) { @@ -99,7 +99,7 @@ func TestPluginCommand(t *testing.T) { err2 := th.App.DisablePlugin(pluginIDs[0]) require.Nil(t, err2) - commands, err3 := th.App.ListAutocompleteCommands(args.TeamId, utils.T) + commands, err3 := th.App.ListAutocompleteCommands(args.TeamId, i18n.T) require.Nil(t, err3) for _, commands := range commands { diff --git a/app/post.go b/app/post.go index a3aeb3afa5..4a171be1f9 100644 --- a/app/post.go +++ b/app/post.go @@ -17,8 +17,8 @@ import ( "github.com/mattermost/mattermost-server/v5/model" "github.com/mattermost/mattermost-server/v5/plugin" "github.com/mattermost/mattermost-server/v5/services/cache" + "github.com/mattermost/mattermost-server/v5/shared/i18n" "github.com/mattermost/mattermost-server/v5/store" - "github.com/mattermost/mattermost-server/v5/utils" ) const ( @@ -65,7 +65,7 @@ func (a *App) CreatePostAsUser(post *model.Post, currentSessionId string, setOnl } } - T := utils.GetUserTranslations(user.Locale) + T := i18n.GetUserTranslations(user.Locale) a.SendEphemeralPost( post.UserId, &model.Post{ @@ -218,7 +218,7 @@ func (a *App) CreatePost(post *model.Post, channel *model.Channel, triggerWebhoo if post.Type == "" && !a.HasPermissionToChannel(user.Id, channel.Id, model.PERMISSION_USE_CHANNEL_MENTIONS) { mention := post.DisableMentionHighlights() if mention != "" { - T := utils.GetUserTranslations(user.Locale) + T := i18n.GetUserTranslations(user.Locale) ephemeralPost = &model.Post{ UserId: user.Id, RootId: post.RootId, diff --git a/app/ratelimit.go b/app/ratelimit.go index 189422e775..3518796856 100644 --- a/app/ratelimit.go +++ b/app/ratelimit.go @@ -15,6 +15,7 @@ import ( "github.com/mattermost/mattermost-server/v5/mlog" "github.com/mattermost/mattermost-server/v5/model" + "github.com/mattermost/mattermost-server/v5/shared/i18n" "github.com/mattermost/mattermost-server/v5/utils" ) @@ -29,7 +30,7 @@ type RateLimiter struct { func NewRateLimiter(settings *model.RateLimitSettings, trustedProxyIPHeader []string) (*RateLimiter, error) { store, err := memstore.New(*settings.MemoryStoreSize) if err != nil { - return nil, errors.Wrap(err, utils.T("api.server.start_server.rate_limiting_memory_store")) + return nil, errors.Wrap(err, i18n.T("api.server.start_server.rate_limiting_memory_store")) } quota := throttled.RateQuota{ @@ -39,7 +40,7 @@ func NewRateLimiter(settings *model.RateLimitSettings, trustedProxyIPHeader []st throttledRateLimiter, err := throttled.NewGCRARateLimiter(store, quota) if err != nil { - return nil, errors.Wrap(err, utils.T("api.server.start_server.rate_limiting_rate_limiter")) + return nil, errors.Wrap(err, i18n.T("api.server.start_server.rate_limiting_rate_limiter")) } return &RateLimiter{ diff --git a/app/security_update_check.go b/app/security_update_check.go index 8834b79187..c634907363 100644 --- a/app/security_update_check.go +++ b/app/security_update_check.go @@ -13,7 +13,7 @@ import ( "github.com/mattermost/mattermost-server/v5/mlog" "github.com/mattermost/mattermost-server/v5/model" "github.com/mattermost/mattermost-server/v5/services/mailservice" - "github.com/mattermost/mattermost-server/v5/utils" + "github.com/mattermost/mattermost-server/v5/shared/i18n" ) const ( @@ -116,8 +116,7 @@ func (s *Server) DoSecurityUpdateCheck() { mlog.Info("Sending security bulletin", mlog.String("bulletin_id", bulletin.Id), mlog.String("user_email", user.Email)) license := s.License() mailConfig := s.MailServiceConfig() - - mailservice.SendMailUsingConfig(user.Email, utils.T("mattermost.bulletin.subject"), string(body), mailConfig, license != nil && *license.Features.Compliance, "") + mailservice.SendMailUsingConfig(user.Email, i18n.T("mattermost.bulletin.subject"), string(body), mailConfig, license != nil && *license.Features.Compliance, "") } bulletinSeen := &model.System{Name: "SecurityBulletin_" + bulletin.Id, Value: bulletin.Id} diff --git a/app/server.go b/app/server.go index 0184a7ac1c..41e0785e14 100644 --- a/app/server.go +++ b/app/server.go @@ -54,6 +54,7 @@ import ( "github.com/mattermost/mattermost-server/v5/services/timezones" "github.com/mattermost/mattermost-server/v5/services/tracing" "github.com/mattermost/mattermost-server/v5/services/upgrader" + "github.com/mattermost/mattermost-server/v5/shared/i18n" "github.com/mattermost/mattermost-server/v5/store" "github.com/mattermost/mattermost-server/v5/store/localcachelayer" "github.com/mattermost/mattermost-server/v5/store/retrylayer" @@ -288,7 +289,7 @@ func NewServer(options ...Option) (*Server, error) { if err := utils.TranslationsPreInit(); err != nil { return nil, errors.Wrapf(err, "unable to load Mattermost translation files") } - model.AppErrorInit(utils.T) + model.AppErrorInit(i18n.T) searchEngine := searchengine.NewBroker(s.Config(), s.Jobs) bleveEngine := bleveengine.NewBleveEngine(s.Config(), s.Jobs) @@ -328,7 +329,7 @@ func NewServer(options ...Option) (*Server, error) { s.createPushNotificationsHub() - if err2 := utils.InitTranslations(s.Config().LocalizationSettings); err2 != nil { + if err2 := i18n.InitTranslations(*s.Config().LocalizationSettings.DefaultServerLocale, *s.Config().LocalizationSettings.DefaultClientLocale); err2 != nil { return nil, errors.Wrapf(err2, "unable to load Mattermost translation files") } @@ -1043,7 +1044,7 @@ func (s *Server) Start() error { listener, err := net.Listen("tcp", addr) if err != nil { - return errors.Wrapf(err, utils.T("api.server.start_server.starting.critical"), err) + return errors.Wrapf(err, i18n.T("api.server.start_server.starting.critical"), err) } s.ListenAddr = listener.Addr().(*net.TCPAddr) @@ -1059,7 +1060,7 @@ func (s *Server) Start() error { if host, port, err := net.SplitHostPort(addr); err != nil { mlog.Error("Unable to setup forwarding", mlog.Err(err)) } else if port != "443" { - return fmt.Errorf(utils.T("api.server.start_server.forward80to443.enabled_but_listening_on_wrong_port"), port) + return fmt.Errorf(i18n.T("api.server.start_server.forward80to443.enabled_but_listening_on_wrong_port"), port) } else { httpListenAddress := net.JoinHostPort(host, "http") @@ -1088,7 +1089,7 @@ func (s *Server) Start() error { } } } else if *s.Config().ServiceSettings.UseLetsEncrypt { - return errors.New(utils.T("api.server.start_server.forward80to443.disabled_while_using_lets_encrypt")) + return errors.New(i18n.T("api.server.start_server.forward80to443.disabled_while_using_lets_encrypt")) } s.didFinishListen = make(chan struct{}) @@ -1183,15 +1184,15 @@ func (s *Server) startLocalModeServer() error { socket := *s.configStore.Get().ServiceSettings.LocalModeSocketLocation if err := os.RemoveAll(socket); err != nil { - return errors.Wrapf(err, utils.T("api.server.start_server.starting.critical"), err) + return errors.Wrapf(err, i18n.T("api.server.start_server.starting.critical"), err) } unixListener, err := net.Listen("unix", socket) if err != nil { - return errors.Wrapf(err, utils.T("api.server.start_server.starting.critical"), err) + return errors.Wrapf(err, i18n.T("api.server.start_server.starting.critical"), err) } if err = os.Chmod(socket, 0600); err != nil { - return errors.Wrapf(err, utils.T("api.server.start_server.starting.critical"), err) + return errors.Wrapf(err, i18n.T("api.server.start_server.starting.critical"), err) } go func() { diff --git a/app/slashcommands/command_away.go b/app/slashcommands/command_away.go index 8a343a33e2..19250583d0 100644 --- a/app/slashcommands/command_away.go +++ b/app/slashcommands/command_away.go @@ -4,10 +4,9 @@ package slashcommands import ( - goi18n "github.com/mattermost/go-i18n/i18n" - "github.com/mattermost/mattermost-server/v5/app" "github.com/mattermost/mattermost-server/v5/model" + "github.com/mattermost/mattermost-server/v5/shared/i18n" ) type AwayProvider struct { @@ -25,7 +24,7 @@ func (*AwayProvider) GetTrigger() string { return CmdAway } -func (*AwayProvider) GetCommand(a *app.App, T goi18n.TranslateFunc) *model.Command { +func (*AwayProvider) GetCommand(a *app.App, T i18n.TranslateFunc) *model.Command { return &model.Command{ Trigger: CmdAway, AutoComplete: true, diff --git a/app/slashcommands/command_channel_header.go b/app/slashcommands/command_channel_header.go index 95aeccbbcd..c0ec16d012 100644 --- a/app/slashcommands/command_channel_header.go +++ b/app/slashcommands/command_channel_header.go @@ -4,10 +4,9 @@ package slashcommands import ( - goi18n "github.com/mattermost/go-i18n/i18n" - "github.com/mattermost/mattermost-server/v5/app" "github.com/mattermost/mattermost-server/v5/model" + "github.com/mattermost/mattermost-server/v5/shared/i18n" ) type HeaderProvider struct { @@ -25,7 +24,7 @@ func (*HeaderProvider) GetTrigger() string { return CmdHeader } -func (*HeaderProvider) GetCommand(a *app.App, T goi18n.TranslateFunc) *model.Command { +func (*HeaderProvider) GetCommand(a *app.App, T i18n.TranslateFunc) *model.Command { return &model.Command{ Trigger: CmdHeader, AutoComplete: true, diff --git a/app/slashcommands/command_channel_purpose.go b/app/slashcommands/command_channel_purpose.go index c0e58a433a..668fa001fa 100644 --- a/app/slashcommands/command_channel_purpose.go +++ b/app/slashcommands/command_channel_purpose.go @@ -4,10 +4,9 @@ package slashcommands import ( - goi18n "github.com/mattermost/go-i18n/i18n" - "github.com/mattermost/mattermost-server/v5/app" "github.com/mattermost/mattermost-server/v5/model" + "github.com/mattermost/mattermost-server/v5/shared/i18n" ) type PurposeProvider struct { @@ -25,7 +24,7 @@ func (*PurposeProvider) GetTrigger() string { return CmdPurpose } -func (*PurposeProvider) GetCommand(a *app.App, T goi18n.TranslateFunc) *model.Command { +func (*PurposeProvider) GetCommand(a *app.App, T i18n.TranslateFunc) *model.Command { return &model.Command{ Trigger: CmdPurpose, AutoComplete: true, diff --git a/app/slashcommands/command_channel_rename.go b/app/slashcommands/command_channel_rename.go index d5328ba36b..3aba972b3f 100644 --- a/app/slashcommands/command_channel_rename.go +++ b/app/slashcommands/command_channel_rename.go @@ -4,10 +4,9 @@ package slashcommands import ( - goi18n "github.com/mattermost/go-i18n/i18n" - "github.com/mattermost/mattermost-server/v5/app" "github.com/mattermost/mattermost-server/v5/model" + "github.com/mattermost/mattermost-server/v5/shared/i18n" ) type RenameProvider struct { @@ -25,7 +24,7 @@ func (*RenameProvider) GetTrigger() string { return CmdRename } -func (*RenameProvider) GetCommand(a *app.App, T goi18n.TranslateFunc) *model.Command { +func (*RenameProvider) GetCommand(a *app.App, T i18n.TranslateFunc) *model.Command { renameAutocompleteData := model.NewAutocompleteData(CmdRename, T("api.command_channel_rename.hint"), T("api.command_channel_rename.desc")) renameAutocompleteData.AddTextArgument(T("api.command_channel_rename.hint"), "[text]", "") return &model.Command{ diff --git a/app/slashcommands/command_code.go b/app/slashcommands/command_code.go index 1a030c123a..a4f821a014 100644 --- a/app/slashcommands/command_code.go +++ b/app/slashcommands/command_code.go @@ -6,10 +6,9 @@ package slashcommands import ( "strings" - goi18n "github.com/mattermost/go-i18n/i18n" - "github.com/mattermost/mattermost-server/v5/app" "github.com/mattermost/mattermost-server/v5/model" + "github.com/mattermost/mattermost-server/v5/shared/i18n" ) type CodeProvider struct { @@ -27,7 +26,7 @@ func (*CodeProvider) GetTrigger() string { return CmdCode } -func (*CodeProvider) GetCommand(a *app.App, T goi18n.TranslateFunc) *model.Command { +func (*CodeProvider) GetCommand(a *app.App, T i18n.TranslateFunc) *model.Command { return &model.Command{ Trigger: CmdCode, AutoComplete: true, diff --git a/app/slashcommands/command_custom_status.go b/app/slashcommands/command_custom_status.go index a546e9805b..4a61007a01 100644 --- a/app/slashcommands/command_custom_status.go +++ b/app/slashcommands/command_custom_status.go @@ -6,11 +6,10 @@ package slashcommands import ( "strings" - goi18n "github.com/mattermost/go-i18n/i18n" - "github.com/mattermost/mattermost-server/v5/app" "github.com/mattermost/mattermost-server/v5/mlog" "github.com/mattermost/mattermost-server/v5/model" + "github.com/mattermost/mattermost-server/v5/shared/i18n" ) type CustomStatusProvider struct { @@ -31,7 +30,7 @@ func (*CustomStatusProvider) GetTrigger() string { return CmdCustomStatus } -func (*CustomStatusProvider) GetCommand(a *app.App, T goi18n.TranslateFunc) *model.Command { +func (*CustomStatusProvider) GetCommand(a *app.App, T i18n.TranslateFunc) *model.Command { return &model.Command{ Trigger: CmdCustomStatus, AutoComplete: true, diff --git a/app/slashcommands/command_dnd.go b/app/slashcommands/command_dnd.go index 66e9573c85..45d4aafe32 100644 --- a/app/slashcommands/command_dnd.go +++ b/app/slashcommands/command_dnd.go @@ -4,10 +4,9 @@ package slashcommands import ( - goi18n "github.com/mattermost/go-i18n/i18n" - "github.com/mattermost/mattermost-server/v5/app" "github.com/mattermost/mattermost-server/v5/model" + "github.com/mattermost/mattermost-server/v5/shared/i18n" ) type DndProvider struct { @@ -25,7 +24,7 @@ func (*DndProvider) GetTrigger() string { return CmdDND } -func (*DndProvider) GetCommand(a *app.App, T goi18n.TranslateFunc) *model.Command { +func (*DndProvider) GetCommand(a *app.App, T i18n.TranslateFunc) *model.Command { return &model.Command{ Trigger: CmdDND, AutoComplete: true, diff --git a/app/slashcommands/command_echo.go b/app/slashcommands/command_echo.go index a0315e654e..dc06300743 100644 --- a/app/slashcommands/command_echo.go +++ b/app/slashcommands/command_echo.go @@ -8,11 +8,10 @@ import ( "strings" "time" - goi18n "github.com/mattermost/go-i18n/i18n" - "github.com/mattermost/mattermost-server/v5/app" "github.com/mattermost/mattermost-server/v5/mlog" "github.com/mattermost/mattermost-server/v5/model" + "github.com/mattermost/mattermost-server/v5/shared/i18n" ) var echoSem chan bool @@ -32,7 +31,7 @@ func (*EchoProvider) GetTrigger() string { return CmdEcho } -func (*EchoProvider) GetCommand(a *app.App, T goi18n.TranslateFunc) *model.Command { +func (*EchoProvider) GetCommand(a *app.App, T i18n.TranslateFunc) *model.Command { return &model.Command{ Trigger: CmdEcho, AutoComplete: true, diff --git a/app/slashcommands/command_expand_collapse.go b/app/slashcommands/command_expand_collapse.go index 4794e9c795..8f74e831bc 100644 --- a/app/slashcommands/command_expand_collapse.go +++ b/app/slashcommands/command_expand_collapse.go @@ -6,10 +6,9 @@ package slashcommands import ( "strconv" - goi18n "github.com/mattermost/go-i18n/i18n" - "github.com/mattermost/mattermost-server/v5/app" "github.com/mattermost/mattermost-server/v5/model" + "github.com/mattermost/mattermost-server/v5/shared/i18n" ) type ExpandProvider struct { @@ -36,7 +35,7 @@ func (*CollapseProvider) GetTrigger() string { return CmdCollapse } -func (*ExpandProvider) GetCommand(a *app.App, T goi18n.TranslateFunc) *model.Command { +func (*ExpandProvider) GetCommand(a *app.App, T i18n.TranslateFunc) *model.Command { return &model.Command{ Trigger: CmdExpand, AutoComplete: true, @@ -45,7 +44,7 @@ func (*ExpandProvider) GetCommand(a *app.App, T goi18n.TranslateFunc) *model.Com } } -func (*CollapseProvider) GetCommand(a *app.App, T goi18n.TranslateFunc) *model.Command { +func (*CollapseProvider) GetCommand(a *app.App, T i18n.TranslateFunc) *model.Command { return &model.Command{ Trigger: CmdCollapse, AutoComplete: true, diff --git a/app/slashcommands/command_groupmsg.go b/app/slashcommands/command_groupmsg.go index eec8c4d8b8..307ac99cea 100644 --- a/app/slashcommands/command_groupmsg.go +++ b/app/slashcommands/command_groupmsg.go @@ -7,11 +7,10 @@ import ( "fmt" "strings" - goi18n "github.com/mattermost/go-i18n/i18n" - "github.com/mattermost/mattermost-server/v5/app" "github.com/mattermost/mattermost-server/v5/mlog" "github.com/mattermost/mattermost-server/v5/model" + "github.com/mattermost/mattermost-server/v5/shared/i18n" ) type groupmsgProvider struct { @@ -29,7 +28,7 @@ func (*groupmsgProvider) GetTrigger() string { return CmdGroupMsg } -func (*groupmsgProvider) GetCommand(a *app.App, T goi18n.TranslateFunc) *model.Command { +func (*groupmsgProvider) GetCommand(a *app.App, T i18n.TranslateFunc) *model.Command { return &model.Command{ Trigger: CmdGroupMsg, AutoComplete: true, diff --git a/app/slashcommands/command_groupmsg_test.go b/app/slashcommands/command_groupmsg_test.go index e7c84f6e68..e351b9b4cb 100644 --- a/app/slashcommands/command_groupmsg_test.go +++ b/app/slashcommands/command_groupmsg_test.go @@ -6,10 +6,10 @@ package slashcommands import ( "testing" - "github.com/mattermost/go-i18n/i18n" "github.com/stretchr/testify/assert" "github.com/mattermost/mattermost-server/v5/model" + "github.com/mattermost/mattermost-server/v5/shared/i18n" ) func TestGroupMsgUsernames(t *testing.T) { diff --git a/app/slashcommands/command_help.go b/app/slashcommands/command_help.go index 2c4c94e05b..f1424b470f 100644 --- a/app/slashcommands/command_help.go +++ b/app/slashcommands/command_help.go @@ -4,10 +4,9 @@ package slashcommands import ( - goi18n "github.com/mattermost/go-i18n/i18n" - "github.com/mattermost/mattermost-server/v5/app" "github.com/mattermost/mattermost-server/v5/model" + "github.com/mattermost/mattermost-server/v5/shared/i18n" ) type HelpProvider struct { @@ -25,7 +24,7 @@ func (h *HelpProvider) GetTrigger() string { return CmdHelp } -func (h *HelpProvider) GetCommand(a *app.App, T goi18n.TranslateFunc) *model.Command { +func (h *HelpProvider) GetCommand(a *app.App, T i18n.TranslateFunc) *model.Command { return &model.Command{ Trigger: CmdHelp, AutoComplete: true, diff --git a/app/slashcommands/command_invite.go b/app/slashcommands/command_invite.go index 42e55bfcd0..4b54b5e833 100644 --- a/app/slashcommands/command_invite.go +++ b/app/slashcommands/command_invite.go @@ -6,11 +6,10 @@ package slashcommands import ( "strings" - goi18n "github.com/mattermost/go-i18n/i18n" - "github.com/mattermost/mattermost-server/v5/app" "github.com/mattermost/mattermost-server/v5/mlog" "github.com/mattermost/mattermost-server/v5/model" + "github.com/mattermost/mattermost-server/v5/shared/i18n" ) type InviteProvider struct { @@ -28,7 +27,7 @@ func (*InviteProvider) GetTrigger() string { return CmdInvite } -func (*InviteProvider) GetCommand(a *app.App, T goi18n.TranslateFunc) *model.Command { +func (*InviteProvider) GetCommand(a *app.App, T i18n.TranslateFunc) *model.Command { return &model.Command{ Trigger: CmdInvite, AutoComplete: true, diff --git a/app/slashcommands/command_invite_people.go b/app/slashcommands/command_invite_people.go index fcdd5cb746..c11f1d7f8e 100644 --- a/app/slashcommands/command_invite_people.go +++ b/app/slashcommands/command_invite_people.go @@ -6,11 +6,10 @@ package slashcommands import ( "strings" - goi18n "github.com/mattermost/go-i18n/i18n" - "github.com/mattermost/mattermost-server/v5/app" "github.com/mattermost/mattermost-server/v5/mlog" "github.com/mattermost/mattermost-server/v5/model" + "github.com/mattermost/mattermost-server/v5/shared/i18n" ) type InvitePeopleProvider struct { @@ -28,7 +27,7 @@ func (*InvitePeopleProvider) GetTrigger() string { return CmdInvite_PEOPLE } -func (*InvitePeopleProvider) GetCommand(a *app.App, T goi18n.TranslateFunc) *model.Command { +func (*InvitePeopleProvider) GetCommand(a *app.App, T i18n.TranslateFunc) *model.Command { autoComplete := true if !*a.Config().EmailSettings.SendEmailNotifications || !*a.Config().TeamSettings.EnableUserCreation || !*a.Config().ServiceSettings.EnableEmailInvitations { autoComplete = false diff --git a/app/slashcommands/command_join.go b/app/slashcommands/command_join.go index 642f929554..3765064fc4 100644 --- a/app/slashcommands/command_join.go +++ b/app/slashcommands/command_join.go @@ -6,10 +6,9 @@ package slashcommands import ( "strings" - goi18n "github.com/mattermost/go-i18n/i18n" - "github.com/mattermost/mattermost-server/v5/app" "github.com/mattermost/mattermost-server/v5/model" + "github.com/mattermost/mattermost-server/v5/shared/i18n" ) type JoinProvider struct { @@ -27,7 +26,7 @@ func (*JoinProvider) GetTrigger() string { return CmdJoin } -func (*JoinProvider) GetCommand(a *app.App, T goi18n.TranslateFunc) *model.Command { +func (*JoinProvider) GetCommand(a *app.App, T i18n.TranslateFunc) *model.Command { return &model.Command{ Trigger: CmdJoin, AutoComplete: true, diff --git a/app/slashcommands/command_join_test.go b/app/slashcommands/command_join_test.go index 10b33f92f2..e70da6ec13 100644 --- a/app/slashcommands/command_join_test.go +++ b/app/slashcommands/command_join_test.go @@ -6,10 +6,10 @@ package slashcommands import ( "testing" - "github.com/mattermost/go-i18n/i18n" "github.com/stretchr/testify/assert" "github.com/mattermost/mattermost-server/v5/model" + "github.com/mattermost/mattermost-server/v5/shared/i18n" ) func TestJoinCommandNoChannel(t *testing.T) { diff --git a/app/slashcommands/command_leave.go b/app/slashcommands/command_leave.go index 20b6635c66..e6c7b7314b 100644 --- a/app/slashcommands/command_leave.go +++ b/app/slashcommands/command_leave.go @@ -4,10 +4,9 @@ package slashcommands import ( - goi18n "github.com/mattermost/go-i18n/i18n" - "github.com/mattermost/mattermost-server/v5/app" "github.com/mattermost/mattermost-server/v5/model" + "github.com/mattermost/mattermost-server/v5/shared/i18n" ) type LeaveProvider struct { @@ -25,7 +24,7 @@ func (*LeaveProvider) GetTrigger() string { return CmdLeave } -func (*LeaveProvider) GetCommand(a *app.App, T goi18n.TranslateFunc) *model.Command { +func (*LeaveProvider) GetCommand(a *app.App, T i18n.TranslateFunc) *model.Command { return &model.Command{ Trigger: CmdLeave, AutoComplete: true, diff --git a/app/slashcommands/command_loadtest.go b/app/slashcommands/command_loadtest.go index a0eab1917b..f645aa0140 100644 --- a/app/slashcommands/command_loadtest.go +++ b/app/slashcommands/command_loadtest.go @@ -12,12 +12,12 @@ import ( "strconv" "strings" - goi18n "github.com/mattermost/go-i18n/i18n" "github.com/pkg/errors" "github.com/mattermost/mattermost-server/v5/app" "github.com/mattermost/mattermost-server/v5/mlog" "github.com/mattermost/mattermost-server/v5/model" + "github.com/mattermost/mattermost-server/v5/shared/i18n" "github.com/mattermost/mattermost-server/v5/utils" ) @@ -95,7 +95,7 @@ func (*LoadTestProvider) GetTrigger() string { return CmdTest } -func (*LoadTestProvider) GetCommand(a *app.App, T goi18n.TranslateFunc) *model.Command { +func (*LoadTestProvider) GetCommand(a *app.App, T i18n.TranslateFunc) *model.Command { if !*a.Config().ServiceSettings.EnableTesting { return nil } diff --git a/app/slashcommands/command_logout.go b/app/slashcommands/command_logout.go index 9ef2125517..b41d00e4e1 100644 --- a/app/slashcommands/command_logout.go +++ b/app/slashcommands/command_logout.go @@ -4,10 +4,9 @@ package slashcommands import ( - goi18n "github.com/mattermost/go-i18n/i18n" - "github.com/mattermost/mattermost-server/v5/app" "github.com/mattermost/mattermost-server/v5/model" + "github.com/mattermost/mattermost-server/v5/shared/i18n" ) type LogoutProvider struct { @@ -25,7 +24,7 @@ func (*LogoutProvider) GetTrigger() string { return CmdLogout } -func (*LogoutProvider) GetCommand(a *app.App, T goi18n.TranslateFunc) *model.Command { +func (*LogoutProvider) GetCommand(a *app.App, T i18n.TranslateFunc) *model.Command { return &model.Command{ Trigger: CmdLogout, AutoComplete: true, diff --git a/app/slashcommands/command_me.go b/app/slashcommands/command_me.go index c008b7d0cc..510b438ca9 100644 --- a/app/slashcommands/command_me.go +++ b/app/slashcommands/command_me.go @@ -4,10 +4,9 @@ package slashcommands import ( - goi18n "github.com/mattermost/go-i18n/i18n" - "github.com/mattermost/mattermost-server/v5/app" "github.com/mattermost/mattermost-server/v5/model" + "github.com/mattermost/mattermost-server/v5/shared/i18n" ) type MeProvider struct { @@ -25,7 +24,7 @@ func (*MeProvider) GetTrigger() string { return CmdMe } -func (*MeProvider) GetCommand(a *app.App, T goi18n.TranslateFunc) *model.Command { +func (*MeProvider) GetCommand(a *app.App, T i18n.TranslateFunc) *model.Command { return &model.Command{ Trigger: CmdMe, AutoComplete: true, diff --git a/app/slashcommands/command_msg.go b/app/slashcommands/command_msg.go index 2f9bdc1de0..2e63e5d295 100644 --- a/app/slashcommands/command_msg.go +++ b/app/slashcommands/command_msg.go @@ -7,11 +7,10 @@ import ( "errors" "strings" - goi18n "github.com/mattermost/go-i18n/i18n" - "github.com/mattermost/mattermost-server/v5/app" "github.com/mattermost/mattermost-server/v5/mlog" "github.com/mattermost/mattermost-server/v5/model" + "github.com/mattermost/mattermost-server/v5/shared/i18n" "github.com/mattermost/mattermost-server/v5/store" ) @@ -30,7 +29,7 @@ func (*msgProvider) GetTrigger() string { return CmdMsg } -func (*msgProvider) GetCommand(a *app.App, T goi18n.TranslateFunc) *model.Command { +func (*msgProvider) GetCommand(a *app.App, T i18n.TranslateFunc) *model.Command { return &model.Command{ Trigger: CmdMsg, AutoComplete: true, diff --git a/app/slashcommands/command_msg_test.go b/app/slashcommands/command_msg_test.go index 913eed2c14..defae6de58 100644 --- a/app/slashcommands/command_msg_test.go +++ b/app/slashcommands/command_msg_test.go @@ -6,10 +6,10 @@ package slashcommands import ( "testing" - "github.com/mattermost/go-i18n/i18n" "github.com/stretchr/testify/assert" "github.com/mattermost/mattermost-server/v5/model" + "github.com/mattermost/mattermost-server/v5/shared/i18n" ) func TestMsgProvider(t *testing.T) { diff --git a/app/slashcommands/command_mute.go b/app/slashcommands/command_mute.go index 2e8eef497e..5ade3df5c3 100644 --- a/app/slashcommands/command_mute.go +++ b/app/slashcommands/command_mute.go @@ -6,10 +6,9 @@ package slashcommands import ( "strings" - goi18n "github.com/mattermost/go-i18n/i18n" - "github.com/mattermost/mattermost-server/v5/app" "github.com/mattermost/mattermost-server/v5/model" + "github.com/mattermost/mattermost-server/v5/shared/i18n" ) type MuteProvider struct { @@ -27,7 +26,7 @@ func (*MuteProvider) GetTrigger() string { return CmdMute } -func (*MuteProvider) GetCommand(a *app.App, T goi18n.TranslateFunc) *model.Command { +func (*MuteProvider) GetCommand(a *app.App, T i18n.TranslateFunc) *model.Command { return &model.Command{ Trigger: CmdMute, AutoComplete: true, diff --git a/app/slashcommands/command_mute_test.go b/app/slashcommands/command_mute_test.go index 14674ebf8f..6c8000cbaf 100644 --- a/app/slashcommands/command_mute_test.go +++ b/app/slashcommands/command_mute_test.go @@ -7,10 +7,10 @@ import ( "testing" "time" - "github.com/mattermost/go-i18n/i18n" "github.com/stretchr/testify/assert" "github.com/mattermost/mattermost-server/v5/model" + "github.com/mattermost/mattermost-server/v5/shared/i18n" ) func TestMuteCommandNoChannel(t *testing.T) { diff --git a/app/slashcommands/command_offline.go b/app/slashcommands/command_offline.go index 8b13d4e661..b97ebbc07f 100644 --- a/app/slashcommands/command_offline.go +++ b/app/slashcommands/command_offline.go @@ -4,10 +4,9 @@ package slashcommands import ( - goi18n "github.com/mattermost/go-i18n/i18n" - "github.com/mattermost/mattermost-server/v5/app" "github.com/mattermost/mattermost-server/v5/model" + "github.com/mattermost/mattermost-server/v5/shared/i18n" ) type OfflineProvider struct { @@ -25,7 +24,7 @@ func (*OfflineProvider) GetTrigger() string { return CmdOffline } -func (*OfflineProvider) GetCommand(a *app.App, T goi18n.TranslateFunc) *model.Command { +func (*OfflineProvider) GetCommand(a *app.App, T i18n.TranslateFunc) *model.Command { return &model.Command{ Trigger: CmdOffline, AutoComplete: true, diff --git a/app/slashcommands/command_online.go b/app/slashcommands/command_online.go index dc07a34e22..d60e003f82 100644 --- a/app/slashcommands/command_online.go +++ b/app/slashcommands/command_online.go @@ -4,10 +4,9 @@ package slashcommands import ( - goi18n "github.com/mattermost/go-i18n/i18n" - "github.com/mattermost/mattermost-server/v5/app" "github.com/mattermost/mattermost-server/v5/model" + "github.com/mattermost/mattermost-server/v5/shared/i18n" ) type OnlineProvider struct { @@ -25,7 +24,7 @@ func (*OnlineProvider) GetTrigger() string { return CmdOnline } -func (*OnlineProvider) GetCommand(a *app.App, T goi18n.TranslateFunc) *model.Command { +func (*OnlineProvider) GetCommand(a *app.App, T i18n.TranslateFunc) *model.Command { return &model.Command{ Trigger: CmdOnline, AutoComplete: true, diff --git a/app/slashcommands/command_open.go b/app/slashcommands/command_open.go index 927c46e64a..3b41daf261 100644 --- a/app/slashcommands/command_open.go +++ b/app/slashcommands/command_open.go @@ -4,10 +4,9 @@ package slashcommands import ( - goi18n "github.com/mattermost/go-i18n/i18n" - "github.com/mattermost/mattermost-server/v5/app" "github.com/mattermost/mattermost-server/v5/model" + "github.com/mattermost/mattermost-server/v5/shared/i18n" ) type OpenProvider struct { @@ -26,7 +25,7 @@ func (open *OpenProvider) GetTrigger() string { return CmdOpen } -func (open *OpenProvider) GetCommand(a *app.App, T goi18n.TranslateFunc) *model.Command { +func (open *OpenProvider) GetCommand(a *app.App, T i18n.TranslateFunc) *model.Command { cmd := open.JoinProvider.GetCommand(a, T) cmd.Trigger = CmdOpen cmd.DisplayName = T("api.command_open.name") diff --git a/app/slashcommands/command_remove.go b/app/slashcommands/command_remove.go index 4950b51fb8..e786287671 100644 --- a/app/slashcommands/command_remove.go +++ b/app/slashcommands/command_remove.go @@ -6,11 +6,10 @@ package slashcommands import ( "strings" - goi18n "github.com/mattermost/go-i18n/i18n" - "github.com/mattermost/mattermost-server/v5/app" "github.com/mattermost/mattermost-server/v5/mlog" "github.com/mattermost/mattermost-server/v5/model" + "github.com/mattermost/mattermost-server/v5/shared/i18n" ) type RemoveProvider struct { @@ -37,7 +36,7 @@ func (*KickProvider) GetTrigger() string { return CmdKick } -func (*RemoveProvider) GetCommand(a *app.App, T goi18n.TranslateFunc) *model.Command { +func (*RemoveProvider) GetCommand(a *app.App, T i18n.TranslateFunc) *model.Command { return &model.Command{ Trigger: CmdRemove, AutoComplete: true, @@ -47,7 +46,7 @@ func (*RemoveProvider) GetCommand(a *app.App, T goi18n.TranslateFunc) *model.Com } } -func (*KickProvider) GetCommand(a *app.App, T goi18n.TranslateFunc) *model.Command { +func (*KickProvider) GetCommand(a *app.App, T i18n.TranslateFunc) *model.Command { return &model.Command{ Trigger: CmdKick, AutoComplete: true, diff --git a/app/slashcommands/command_search.go b/app/slashcommands/command_search.go index aaa79fdb05..a0892c7e8f 100644 --- a/app/slashcommands/command_search.go +++ b/app/slashcommands/command_search.go @@ -4,10 +4,9 @@ package slashcommands import ( - goi18n "github.com/mattermost/go-i18n/i18n" - "github.com/mattermost/mattermost-server/v5/app" "github.com/mattermost/mattermost-server/v5/model" + "github.com/mattermost/mattermost-server/v5/shared/i18n" ) type SearchProvider struct { @@ -25,7 +24,7 @@ func (search *SearchProvider) GetTrigger() string { return CmdSearch } -func (search *SearchProvider) GetCommand(a *app.App, T goi18n.TranslateFunc) *model.Command { +func (search *SearchProvider) GetCommand(a *app.App, T i18n.TranslateFunc) *model.Command { return &model.Command{ Trigger: CmdSearch, AutoComplete: true, diff --git a/app/slashcommands/command_settings.go b/app/slashcommands/command_settings.go index 311cb55741..814266f5e3 100644 --- a/app/slashcommands/command_settings.go +++ b/app/slashcommands/command_settings.go @@ -4,10 +4,9 @@ package slashcommands import ( - goi18n "github.com/mattermost/go-i18n/i18n" - "github.com/mattermost/mattermost-server/v5/app" "github.com/mattermost/mattermost-server/v5/model" + "github.com/mattermost/mattermost-server/v5/shared/i18n" ) type SettingsProvider struct { @@ -25,7 +24,7 @@ func (settings *SettingsProvider) GetTrigger() string { return CmdSettings } -func (settings *SettingsProvider) GetCommand(a *app.App, T goi18n.TranslateFunc) *model.Command { +func (settings *SettingsProvider) GetCommand(a *app.App, T i18n.TranslateFunc) *model.Command { return &model.Command{ Trigger: CmdSettings, AutoComplete: true, diff --git a/app/slashcommands/command_shortcuts.go b/app/slashcommands/command_shortcuts.go index def6f9948c..07bcfe2d31 100644 --- a/app/slashcommands/command_shortcuts.go +++ b/app/slashcommands/command_shortcuts.go @@ -4,10 +4,9 @@ package slashcommands import ( - goi18n "github.com/mattermost/go-i18n/i18n" - "github.com/mattermost/mattermost-server/v5/app" "github.com/mattermost/mattermost-server/v5/model" + "github.com/mattermost/mattermost-server/v5/shared/i18n" ) type ShortcutsProvider struct { @@ -25,7 +24,7 @@ func (*ShortcutsProvider) GetTrigger() string { return CmdShortcuts } -func (*ShortcutsProvider) GetCommand(a *app.App, T goi18n.TranslateFunc) *model.Command { +func (*ShortcutsProvider) GetCommand(a *app.App, T i18n.TranslateFunc) *model.Command { return &model.Command{ Trigger: CmdShortcuts, AutoComplete: true, diff --git a/app/slashcommands/command_shrug.go b/app/slashcommands/command_shrug.go index 8e226d381f..138308ff50 100644 --- a/app/slashcommands/command_shrug.go +++ b/app/slashcommands/command_shrug.go @@ -4,10 +4,9 @@ package slashcommands import ( - goi18n "github.com/mattermost/go-i18n/i18n" - "github.com/mattermost/mattermost-server/v5/app" "github.com/mattermost/mattermost-server/v5/model" + "github.com/mattermost/mattermost-server/v5/shared/i18n" ) type ShrugProvider struct { @@ -25,7 +24,7 @@ func (*ShrugProvider) GetTrigger() string { return CmdShrug } -func (*ShrugProvider) GetCommand(a *app.App, T goi18n.TranslateFunc) *model.Command { +func (*ShrugProvider) GetCommand(a *app.App, T i18n.TranslateFunc) *model.Command { return &model.Command{ Trigger: CmdShrug, AutoComplete: true, diff --git a/app/team.go b/app/team.go index 8f745b3945..4633221a92 100644 --- a/app/team.go +++ b/app/team.go @@ -21,8 +21,8 @@ import ( "github.com/mattermost/mattermost-server/v5/mlog" "github.com/mattermost/mattermost-server/v5/model" "github.com/mattermost/mattermost-server/v5/plugin" + "github.com/mattermost/mattermost-server/v5/shared/i18n" "github.com/mattermost/mattermost-server/v5/store" - "github.com/mattermost/mattermost-server/v5/utils" ) func (a *App) CreateTeam(team *model.Team) (*model.Team, *model.AppError) { @@ -1325,7 +1325,7 @@ func (a *App) LeaveTeam(team *model.Team, user *model.User, requestorId string) func (a *App) postLeaveTeamMessage(user *model.User, channel *model.Channel) *model.AppError { post := &model.Post{ ChannelId: channel.Id, - Message: fmt.Sprintf(utils.T("api.team.leave.left"), user.Username), + Message: fmt.Sprintf(i18n.T("api.team.leave.left"), user.Username), Type: model.POST_LEAVE_TEAM, UserId: user.Id, Props: model.StringInterface{ @@ -1343,7 +1343,7 @@ func (a *App) postLeaveTeamMessage(user *model.User, channel *model.Channel) *mo func (a *App) postRemoveFromTeamMessage(user *model.User, channel *model.Channel) *model.AppError { post := &model.Post{ ChannelId: channel.Id, - Message: fmt.Sprintf(utils.T("api.team.remove_user_from_team.removed"), user.Username), + Message: fmt.Sprintf(i18n.T("api.team.remove_user_from_team.removed"), user.Username), Type: model.POST_REMOVE_FROM_TEAM, UserId: user.Id, Props: model.StringInterface{ diff --git a/app/user.go b/app/user.go index 94cc5cd376..e8b80c9b8c 100644 --- a/app/user.go +++ b/app/user.go @@ -34,8 +34,8 @@ import ( "github.com/mattermost/mattermost-server/v5/model" "github.com/mattermost/mattermost-server/v5/plugin" "github.com/mattermost/mattermost-server/v5/services/mfa" + "github.com/mattermost/mattermost-server/v5/shared/i18n" "github.com/mattermost/mattermost-server/v5/store" - "github.com/mattermost/mattermost-server/v5/utils" "github.com/mattermost/mattermost-server/v5/utils/fileutils" ) @@ -266,7 +266,7 @@ func (a *App) createUserOrGuest(user *model.User, guest bool) (*model.User, *mod user.Roles = model.SYSTEM_ADMIN_ROLE_ID + " " + model.SYSTEM_USER_ROLE_ID } - if _, ok := utils.GetSupportedLocales()[user.Locale]; !ok { + if _, ok := i18n.GetSupportedLocales()[user.Locale]; !ok { user.Locale = *a.Config().LocalizationSettings.DefaultClientLocale } @@ -1046,7 +1046,7 @@ func (a *App) UpdatePasswordAsUser(userID, currentPassword, newPassword string) return err } - T := utils.GetUserTranslations(user.Locale) + T := i18n.GetUserTranslations(user.Locale) return a.UpdatePasswordSendEmail(user, newPassword, T("api.user.update_password.menu")) } @@ -1463,7 +1463,7 @@ func (a *App) ResetPasswordFromToken(userSuppliedTokenString, newPassword string return model.NewAppError("ResetPasswordFromCode", "api.user.reset_password.sso.app_error", nil, "userId="+user.Id, http.StatusBadRequest) } - T := utils.GetUserTranslations(user.Locale) + T := i18n.GetUserTranslations(user.Locale) if err := a.UpdatePasswordSendEmail(user, newPassword, T("api.user.reset_password.method")); err != nil { return err diff --git a/app/web_conn.go b/app/web_conn.go index c460275495..1a33e37be7 100644 --- a/app/web_conn.go +++ b/app/web_conn.go @@ -18,11 +18,11 @@ import ( "github.com/gobwas/ws" "github.com/gobwas/ws/wsutil" "github.com/mailru/easygo/netpoll" - goi18n "github.com/mattermost/go-i18n/i18n" "github.com/pkg/errors" "github.com/mattermost/mattermost-server/v5/mlog" "github.com/mattermost/mattermost-server/v5/model" + "github.com/mattermost/mattermost-server/v5/shared/i18n" ) const ( @@ -43,7 +43,7 @@ type WebConn struct { sessionExpiresAt int64 // This should stay at the top for 64-bit alignment of 64-bit words accessed atomically App *App WebSocket net.Conn - T goi18n.TranslateFunc + T i18n.TranslateFunc Locale string Sequence int64 UserId string @@ -61,7 +61,7 @@ type WebConn struct { } // NewWebConn returns a new WebConn instance. -func (a *App) NewWebConn(ws net.Conn, session model.Session, t goi18n.TranslateFunc, locale string) *WebConn { +func (a *App) NewWebConn(ws net.Conn, session model.Session, t i18n.TranslateFunc, locale string) *WebConn { if session.UserId != "" { a.Srv().Go(func() { a.SetStatusOnline(session.UserId, false) diff --git a/app/web_conn_test.go b/app/web_conn_test.go index 5672bc6a96..d289ee9f1c 100644 --- a/app/web_conn_test.go +++ b/app/web_conn_test.go @@ -10,7 +10,7 @@ import ( "github.com/stretchr/testify/require" "github.com/mattermost/mattermost-server/v5/model" - "github.com/mattermost/mattermost-server/v5/utils" + "github.com/mattermost/mattermost-server/v5/shared/i18n" ) func TestWebConnShouldSendEvent(t *testing.T) { @@ -28,7 +28,7 @@ func TestWebConnShouldSendEvent(t *testing.T) { basicUserWc := &WebConn{ App: th.App, UserId: th.BasicUser.Id, - T: utils.T, + T: i18n.T, } basicUserWc.SetSession(session) @@ -47,7 +47,7 @@ func TestWebConnShouldSendEvent(t *testing.T) { basicUser2Wc := &WebConn{ App: th.App, UserId: th.BasicUser2.Id, - T: utils.T, + T: i18n.T, } basicUser2Wc.SetSession(session2) @@ -60,7 +60,7 @@ func TestWebConnShouldSendEvent(t *testing.T) { adminUserWc := &WebConn{ App: th.App, UserId: th.SystemAdminUser.Id, - T: utils.T, + T: i18n.T, } adminUserWc.SetSession(session3) diff --git a/app/web_hub_test.go b/app/web_hub_test.go index 18c4679d31..e7d0935cdf 100644 --- a/app/web_hub_test.go +++ b/app/web_hub_test.go @@ -15,12 +15,12 @@ import ( "github.com/gobwas/ws" "github.com/gobwas/ws/wsutil" - goi18n "github.com/mattermost/go-i18n/i18n" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" "github.com/mattermost/mattermost-server/v5/model" + "github.com/mattermost/mattermost-server/v5/shared/i18n" "github.com/mattermost/mattermost-server/v5/store/storetest/mocks" ) @@ -68,7 +68,7 @@ func registerDummyWebConn(t *testing.T, a *App, addr net.Addr, userID string) *W c, _, _, err := ws.Dial(context.Background(), "ws://"+addr.String()+"/ws") require.NoError(t, err) - wc := a.NewWebConn(c, *session, goi18n.IdentityTfunc(), "en") + wc := a.NewWebConn(c, *session, i18n.IdentityTfunc(), "en") a.HubRegister(wc) go wc.Pump() return wc diff --git a/app/webhub_fuzz.go b/app/webhub_fuzz.go index 74e59f152d..5387c12df3 100644 --- a/app/webhub_fuzz.go +++ b/app/webhub_fuzz.go @@ -17,9 +17,9 @@ import ( "time" "github.com/gorilla/websocket" - goi18n "github.com/mattermost/go-i18n/i18n" "github.com/mattermost/mattermost-server/v5/model" + "github.com/mattermost/mattermost-server/v5/shared/i18n" "github.com/mattermost/mattermost-server/v5/testlib" ) @@ -87,7 +87,7 @@ func registerDummyWebConn(a *App, addr net.Addr, userID string) *WebConn { panic(err) } - wc := a.NewWebConn(c, *session, goi18n.IdentityTfunc(), "en") + wc := a.NewWebConn(c, *session, i18n.IdentityTfunc(), "en") a.HubRegister(wc) go wc.Pump() return wc diff --git a/app/websocket_router.go b/app/websocket_router.go index 203e9cefb1..1fb1b7ff4a 100644 --- a/app/websocket_router.go +++ b/app/websocket_router.go @@ -8,7 +8,7 @@ import ( "github.com/mattermost/mattermost-server/v5/mlog" "github.com/mattermost/mattermost-server/v5/model" - "github.com/mattermost/mattermost-server/v5/utils" + "github.com/mattermost/mattermost-server/v5/shared/i18n" ) type webSocketHandler interface { @@ -103,7 +103,7 @@ func returnWebSocketError(app *App, conn *WebConn, r *model.WebSocketRequest, er "websocket routing error.", mlog.Int64("seq", r.Seq), mlog.String("user_id", conn.UserId), - mlog.String("system_message", err.SystemMessage(utils.T)), + mlog.String("system_message", err.SystemMessage(i18n.T)), mlog.Err(err), ) diff --git a/cmd/mattermost/commands/config.go b/cmd/mattermost/commands/config.go index 39b3f476eb..6458036ec2 100644 --- a/cmd/mattermost/commands/config.go +++ b/cmd/mattermost/commands/config.go @@ -17,6 +17,7 @@ import ( "github.com/mattermost/mattermost-server/v5/config" "github.com/mattermost/mattermost-server/v5/mlog" "github.com/mattermost/mattermost-server/v5/model" + "github.com/mattermost/mattermost-server/v5/shared/i18n" "github.com/mattermost/mattermost-server/v5/utils" ) @@ -106,7 +107,7 @@ func init() { func configValidateCmdF(command *cobra.Command, args []string) error { utils.TranslationsPreInit() - model.AppErrorInit(utils.T) + model.AppErrorInit(i18n.T) _, err := getConfigStore(command) if err != nil { diff --git a/cmd/mattermost/commands/init.go b/cmd/mattermost/commands/init.go index 1b912051c7..ea25d694be 100644 --- a/cmd/mattermost/commands/init.go +++ b/cmd/mattermost/commands/init.go @@ -9,6 +9,7 @@ import ( "github.com/mattermost/mattermost-server/v5/app" "github.com/mattermost/mattermost-server/v5/config" "github.com/mattermost/mattermost-server/v5/model" + "github.com/mattermost/mattermost-server/v5/shared/i18n" "github.com/mattermost/mattermost-server/v5/utils" ) @@ -37,7 +38,7 @@ func initDBCommandContext(configDSN string, readOnlyConfigStore bool) (*app.App, if err := utils.TranslationsPreInit(); err != nil { return nil, err } - model.AppErrorInit(utils.T) + model.AppErrorInit(i18n.T) s, err := app.NewServer( app.Config(configDSN, false, readOnlyConfigStore, nil), diff --git a/cmd/mattermost/commands/permissions.go b/cmd/mattermost/commands/permissions.go index 7e78e944bb..fd11b36c17 100644 --- a/cmd/mattermost/commands/permissions.go +++ b/cmd/mattermost/commands/permissions.go @@ -11,7 +11,7 @@ import ( "github.com/spf13/cobra" "github.com/mattermost/mattermost-server/v5/audit" - "github.com/mattermost/mattermost-server/v5/utils" + "github.com/mattermost/mattermost-server/v5/shared/i18n" ) var PermissionsCmd = &cobra.Command{ @@ -102,7 +102,7 @@ func exportPermissionsCmdF(command *cobra.Command, args []string) error { defer a.Srv().Shutdown() if license := a.Srv().License(); license == nil { - return errors.New(utils.T("cli.license.critical")) + return errors.New(i18n.T("cli.license.critical")) } if err = a.ExportPermissions(os.Stdout); err != nil { @@ -123,7 +123,7 @@ func importPermissionsCmdF(command *cobra.Command, args []string) error { defer a.Srv().Shutdown() if license := a.Srv().License(); license == nil { - return errors.New(utils.T("cli.license.critical")) + return errors.New(i18n.T("cli.license.critical")) } file, err := os.Open(args[0]) diff --git a/cmd/mattermost/commands/permissions_test.go b/cmd/mattermost/commands/permissions_test.go index 7768a2d5a5..1e0740026f 100644 --- a/cmd/mattermost/commands/permissions_test.go +++ b/cmd/mattermost/commands/permissions_test.go @@ -6,9 +6,8 @@ package commands import ( "testing" + "github.com/mattermost/mattermost-server/v5/shared/i18n" "github.com/stretchr/testify/assert" - - "github.com/mattermost/mattermost-server/v5/utils" ) func TestPermissionsExport_rejectsUnlicensed(t *testing.T) { @@ -16,7 +15,7 @@ func TestPermissionsExport_rejectsUnlicensed(t *testing.T) { defer th.TearDown() actual, _ := th.RunCommandWithOutput(t, "permissions", "export") - assert.Contains(t, actual, utils.T("cli.license.critical")) + assert.Contains(t, actual, i18n.T("cli.license.critical")) } func TestPermissionsImport_rejectsUnlicensed(t *testing.T) { @@ -25,5 +24,5 @@ func TestPermissionsImport_rejectsUnlicensed(t *testing.T) { actual, _ := th.RunCommandWithOutput(t, "permissions", "import") - assert.Contains(t, actual, utils.T("cli.license.critical")) + assert.Contains(t, actual, i18n.T("cli.license.critical")) } diff --git a/cmd/mattermost/commands/test.go b/cmd/mattermost/commands/test.go index 0d5b068705..5e6fb5943c 100644 --- a/cmd/mattermost/commands/test.go +++ b/cmd/mattermost/commands/test.go @@ -15,7 +15,7 @@ import ( "github.com/mattermost/mattermost-server/v5/api4" "github.com/mattermost/mattermost-server/v5/model" - "github.com/mattermost/mattermost-server/v5/utils" + "github.com/mattermost/mattermost-server/v5/shared/i18n" "github.com/mattermost/mattermost-server/v5/wsapi" ) @@ -52,7 +52,7 @@ func webClientTestsCmdF(command *cobra.Command, args []string) error { } defer a.Srv().Shutdown() - utils.InitTranslations(a.Config().LocalizationSettings) + i18n.InitTranslations(*a.Config().LocalizationSettings.DefaultServerLocale, *a.Config().LocalizationSettings.DefaultClientLocale) serverErr := a.Srv().Start() if serverErr != nil { return serverErr @@ -73,7 +73,7 @@ func serverForWebClientTestsCmdF(command *cobra.Command, args []string) error { } defer a.Srv().Shutdown() - utils.InitTranslations(a.Config().LocalizationSettings) + i18n.InitTranslations(*a.Config().LocalizationSettings.DefaultServerLocale, *a.Config().LocalizationSettings.DefaultClientLocale) serverErr := a.Srv().Start() if serverErr != nil { return serverErr diff --git a/config/utils.go b/config/utils.go index 17f3159650..b28e56308d 100644 --- a/config/utils.go +++ b/config/utils.go @@ -10,6 +10,7 @@ import ( "github.com/mattermost/mattermost-server/v5/mlog" "github.com/mattermost/mattermost-server/v5/model" + "github.com/mattermost/mattermost-server/v5/shared/i18n" "github.com/mattermost/mattermost-server/v5/utils" ) @@ -110,7 +111,7 @@ func fixConfig(cfg *model.Config) { func FixInvalidLocales(cfg *model.Config) bool { var changed bool - locales := utils.GetSupportedLocales() + locales := i18n.GetSupportedLocales() if _, ok := locales[*cfg.LocalizationSettings.DefaultServerLocale]; !ok { *cfg.LocalizationSettings.DefaultServerLocale = model.DEFAULT_LOCALE mlog.Warn("DefaultServerLocale must be one of the supported locales. Setting DefaultServerLocale to en as default value.") diff --git a/model/command_args.go b/model/command_args.go index 15a6372a1c..45239d2cb5 100644 --- a/model/command_args.go +++ b/model/command_args.go @@ -7,21 +7,21 @@ import ( "encoding/json" "io" - goi18n "github.com/mattermost/go-i18n/i18n" + "github.com/mattermost/mattermost-server/v5/shared/i18n" ) type CommandArgs struct { - UserId string `json:"user_id"` - ChannelId string `json:"channel_id"` - TeamId string `json:"team_id"` - RootId string `json:"root_id"` - ParentId string `json:"parent_id"` - TriggerId string `json:"trigger_id,omitempty"` - Command string `json:"command"` - SiteURL string `json:"-"` - T goi18n.TranslateFunc `json:"-"` - UserMentions UserMentionMap `json:"-"` - ChannelMentions ChannelMentionMap `json:"-"` + UserId string `json:"user_id"` + ChannelId string `json:"channel_id"` + TeamId string `json:"team_id"` + RootId string `json:"root_id"` + ParentId string `json:"parent_id"` + TriggerId string `json:"trigger_id,omitempty"` + Command string `json:"command"` + SiteURL string `json:"-"` + T i18n.TranslateFunc `json:"-"` + UserMentions UserMentionMap `json:"-"` + ChannelMentions ChannelMentionMap `json:"-"` // DO NOT USE Session field is deprecated. MM-26398 Session Session `json:"-"` diff --git a/model/utils.go b/model/utils.go index c3761a6822..147e7dba56 100644 --- a/model/utils.go +++ b/model/utils.go @@ -22,7 +22,7 @@ import ( "time" "unicode" - goi18n "github.com/mattermost/go-i18n/i18n" + "github.com/mattermost/mattermost-server/v5/shared/i18n" "github.com/pborman/uuid" ) @@ -73,10 +73,10 @@ func (sa StringArray) Equals(input StringArray) bool { return true } -var translateFunc goi18n.TranslateFunc +var translateFunc i18n.TranslateFunc var translateFuncOnce sync.Once -func AppErrorInit(t goi18n.TranslateFunc) { +func AppErrorInit(t i18n.TranslateFunc) { translateFuncOnce.Do(func() { translateFunc = t }) @@ -97,7 +97,7 @@ func (er *AppError) Error() string { return er.Where + ": " + er.Message + ", " + er.DetailedError } -func (er *AppError) Translate(T goi18n.TranslateFunc) { +func (er *AppError) Translate(T i18n.TranslateFunc) { if T == nil { er.Message = er.Id return @@ -110,7 +110,7 @@ func (er *AppError) Translate(T goi18n.TranslateFunc) { } } -func (er *AppError) SystemMessage(T goi18n.TranslateFunc) string { +func (er *AppError) SystemMessage(T i18n.TranslateFunc) string { if er.params == nil { return T(er.Id) } diff --git a/model/websocket_request.go b/model/websocket_request.go index 6628a5c90b..f18f128552 100644 --- a/model/websocket_request.go +++ b/model/websocket_request.go @@ -7,7 +7,7 @@ import ( "encoding/json" "io" - goi18n "github.com/mattermost/go-i18n/i18n" + "github.com/mattermost/mattermost-server/v5/shared/i18n" ) // WebSocketRequest represents a request made to the server through a websocket. @@ -18,9 +18,9 @@ type WebSocketRequest struct { Data map[string]interface{} `json:"data"` // The metadata for an action. // Server-provided fields - Session Session `json:"-"` - T goi18n.TranslateFunc `json:"-"` - Locale string `json:"-"` + Session Session `json:"-"` + T i18n.TranslateFunc `json:"-"` + Locale string `json:"-"` } func (o *WebSocketRequest) ToJson() string { diff --git a/services/slackimport/slackimport.go b/services/slackimport/slackimport.go index d981b49a32..8c0f2fc8db 100644 --- a/services/slackimport/slackimport.go +++ b/services/slackimport/slackimport.go @@ -19,6 +19,7 @@ import ( "github.com/mattermost/mattermost-server/v5/mlog" "github.com/mattermost/mattermost-server/v5/model" + "github.com/mattermost/mattermost-server/v5/shared/i18n" "github.com/mattermost/mattermost-server/v5/store" "github.com/mattermost/mattermost-server/v5/utils" ) @@ -114,11 +115,11 @@ func New(store store.Store, actions Actions, config *model.Config) *SlackImporte func (si *SlackImporter) SlackImport(fileData multipart.File, fileSize int64, teamID string) (*model.AppError, *bytes.Buffer) { // Create log file - log := bytes.NewBufferString(utils.T("api.slackimport.slack_import.log")) + log := bytes.NewBufferString(i18n.T("api.slackimport.slack_import.log")) zipreader, err := zip.NewReader(fileData, fileSize) if err != nil || zipreader.File == nil { - log.WriteString(utils.T("api.slackimport.slack_import.zip.app_error")) + log.WriteString(i18n.T("api.slackimport.slack_import.zip.app_error")) return model.NewAppError("SlackImport", "api.slackimport.slack_import.zip.app_error", nil, err.Error(), http.StatusBadRequest), log } @@ -133,12 +134,12 @@ func (si *SlackImporter) SlackImport(fileData multipart.File, fileSize int64, te uploads := make(map[string]*zip.File) for _, file := range zipreader.File { if file.UncompressedSize64 > slackImportMaxFileSize { - log.WriteString(utils.T("api.slackimport.slack_import.zip.file_too_large", map[string]interface{}{"Filename": file.Name})) + log.WriteString(i18n.T("api.slackimport.slack_import.zip.file_too_large", map[string]interface{}{"Filename": file.Name})) continue } reader, err := file.Open() if err != nil { - log.WriteString(utils.T("api.slackimport.slack_import.open.app_error", map[string]interface{}{"Filename": file.Name})) + log.WriteString(i18n.T("api.slackimport.slack_import.open.app_error", map[string]interface{}{"Filename": file.Name})) return model.NewAppError("SlackImport", "api.slackimport.slack_import.open.app_error", map[string]interface{}{"Filename": file.Name}, err.Error(), http.StatusInternalServerError), log } if file.Name == "channels.json" { @@ -186,12 +187,12 @@ func (si *SlackImporter) SlackImport(fileData multipart.File, fileSize int64, te si.actions.InvalidateAllCaches() - log.WriteString(utils.T("api.slackimport.slack_import.notes")) + log.WriteString(i18n.T("api.slackimport.slack_import.notes")) log.WriteString("=======\r\n\r\n") - log.WriteString(utils.T("api.slackimport.slack_import.note1")) - log.WriteString(utils.T("api.slackimport.slack_import.note2")) - log.WriteString(utils.T("api.slackimport.slack_import.note3")) + log.WriteString(i18n.T("api.slackimport.slack_import.note1")) + log.WriteString(i18n.T("api.slackimport.slack_import.note2")) + log.WriteString(i18n.T("api.slackimport.slack_import.note3")) return nil, log } @@ -206,7 +207,7 @@ func truncateRunes(s string, i int) string { func (si *SlackImporter) slackAddUsers(teamId string, slackusers []slackUser, importerLog *bytes.Buffer) map[string]*model.User { // Log header - importerLog.WriteString(utils.T("api.slackimport.slack_add_users.created")) + importerLog.WriteString(i18n.T("api.slackimport.slack_add_users.created")) importerLog.WriteString("===============\r\n\r\n") addedUsers := make(map[string]*model.User) @@ -214,7 +215,7 @@ func (si *SlackImporter) slackAddUsers(teamId string, slackusers []slackUser, im // Need the team team, err := si.store.Team().Get(teamId) if err != nil { - importerLog.WriteString(utils.T("api.slackimport.slack_import.team_fail")) + importerLog.WriteString(i18n.T("api.slackimport.slack_import.team_fail")) return addedUsers } @@ -224,7 +225,7 @@ func (si *SlackImporter) slackAddUsers(teamId string, slackusers []slackUser, im email := sUser.Profile.Email if email == "" { email = sUser.Username + "@example.com" - importerLog.WriteString(utils.T("api.slackimport.slack_add_users.missing_email_address", map[string]interface{}{"Email": email, "Username": sUser.Username})) + importerLog.WriteString(i18n.T("api.slackimport.slack_add_users.missing_email_address", map[string]interface{}{"Email": email, "Username": sUser.Username})) mlog.Warn("Slack Import: User does not have an email address in the Slack export. Used username as a placeholder. The user should update their email address once logged in to the system.", mlog.String("user_email", email), mlog.String("user_name", sUser.Username)) } @@ -234,9 +235,9 @@ func (si *SlackImporter) slackAddUsers(teamId string, slackusers []slackUser, im if existingUser, err := si.store.User().GetByEmail(email); err == nil { addedUsers[sUser.Id] = existingUser if err := si.actions.JoinUserToTeam(team, addedUsers[sUser.Id], ""); err != nil { - importerLog.WriteString(utils.T("api.slackimport.slack_add_users.merge_existing_failed", map[string]interface{}{"Email": existingUser.Email, "Username": existingUser.Username})) + importerLog.WriteString(i18n.T("api.slackimport.slack_add_users.merge_existing_failed", map[string]interface{}{"Email": existingUser.Email, "Username": existingUser.Username})) } else { - importerLog.WriteString(utils.T("api.slackimport.slack_add_users.merge_existing", map[string]interface{}{"Email": existingUser.Email, "Username": existingUser.Username})) + importerLog.WriteString(i18n.T("api.slackimport.slack_add_users.merge_existing", map[string]interface{}{"Email": existingUser.Email, "Username": existingUser.Username})) } continue } @@ -252,11 +253,11 @@ func (si *SlackImporter) slackAddUsers(teamId string, slackusers []slackUser, im mUser := si.oldImportUser(team, &newUser) if mUser == nil { - importerLog.WriteString(utils.T("api.slackimport.slack_add_users.unable_import", map[string]interface{}{"Username": sUser.Username})) + importerLog.WriteString(i18n.T("api.slackimport.slack_add_users.unable_import", map[string]interface{}{"Username": sUser.Username})) continue } addedUsers[sUser.Id] = mUser - importerLog.WriteString(utils.T("api.slackimport.slack_add_users.email_pwd", map[string]interface{}{"Email": newUser.Email, "Password": password})) + importerLog.WriteString(i18n.T("api.slackimport.slack_add_users.email_pwd", map[string]interface{}{"Email": newUser.Email, "Password": password})) } return addedUsers @@ -265,7 +266,7 @@ func (si *SlackImporter) slackAddUsers(teamId string, slackusers []slackUser, im func (si *SlackImporter) slackAddBotUser(teamId string, log *bytes.Buffer) *model.User { team, err := si.store.Team().Get(teamId) if err != nil { - log.WriteString(utils.T("api.slackimport.slack_import.team_fail")) + log.WriteString(i18n.T("api.slackimport.slack_import.team_fail")) return nil } @@ -283,11 +284,11 @@ func (si *SlackImporter) slackAddBotUser(teamId string, log *bytes.Buffer) *mode mUser := si.oldImportUser(team, &botUser) if mUser == nil { - log.WriteString(utils.T("api.slackimport.slack_add_bot_user.unable_import", map[string]interface{}{"Username": username})) + log.WriteString(i18n.T("api.slackimport.slack_add_bot_user.unable_import", map[string]interface{}{"Username": username})) return nil } - log.WriteString(utils.T("api.slackimport.slack_add_bot_user.email_pwd", map[string]interface{}{"Email": botUser.Email, "Password": password})) + log.WriteString(i18n.T("api.slackimport.slack_add_bot_user.email_pwd", map[string]interface{}{"Email": botUser.Email, "Password": password})) return mUser } @@ -531,11 +532,11 @@ func (si *SlackImporter) addSlackUsersToChannel(members []string, users map[stri for _, member := range members { user, ok := users[member] if !ok { - log.WriteString(utils.T("api.slackimport.slack_add_channels.failed_to_add_user", map[string]interface{}{"Username": "?"})) + log.WriteString(i18n.T("api.slackimport.slack_add_channels.failed_to_add_user", map[string]interface{}{"Username": "?"})) continue } if _, err := si.actions.AddUserToChannel(user, channel); err != nil { - log.WriteString(utils.T("api.slackimport.slack_add_channels.failed_to_add_user", map[string]interface{}{"Username": user.Username})) + log.WriteString(i18n.T("api.slackimport.slack_add_channels.failed_to_add_user", map[string]interface{}{"Username": user.Username})) } } } @@ -566,7 +567,7 @@ func slackSanitiseChannelProperties(channel model.Channel) model.Channel { func (si *SlackImporter) slackAddChannels(teamId string, slackchannels []slackChannel, posts map[string][]slackPost, users map[string]*model.User, uploads map[string]*zip.File, botUser *model.User, importerLog *bytes.Buffer) map[string]*model.Channel { // Write Header - importerLog.WriteString(utils.T("api.slackimport.slack_add_channels.added")) + importerLog.WriteString(i18n.T("api.slackimport.slack_add_channels.added")) importerLog.WriteString("=================\r\n\r\n") addedChannels := make(map[string]*model.Channel) @@ -591,7 +592,7 @@ func (si *SlackImporter) slackAddChannels(teamId string, slackchannels []slackCh var err error if mChannel, err = si.store.Channel().GetByName(teamId, sChannel.Name, true); err == nil { // The channel already exists as an active channel. Merge with the existing one. - importerLog.WriteString(utils.T("api.slackimport.slack_add_channels.merge", map[string]interface{}{"DisplayName": newChannel.DisplayName})) + importerLog.WriteString(i18n.T("api.slackimport.slack_add_channels.merge", map[string]interface{}{"DisplayName": newChannel.DisplayName})) } else if _, nErr := si.store.Channel().GetDeletedByName(teamId, sChannel.Name); nErr == nil { // The channel already exists but has been deleted. Generate a random string for the handle instead. newChannel.Name = model.NewId() @@ -603,7 +604,7 @@ func (si *SlackImporter) slackAddChannels(teamId string, slackchannels []slackCh mChannel = si.oldImportChannel(&newChannel, sChannel, users) if mChannel == nil { mlog.Warn("Slack Import: Unable to import Slack channel.", mlog.String("channel_display_name", newChannel.DisplayName)) - importerLog.WriteString(utils.T("api.slackimport.slack_add_channels.import_failed", map[string]interface{}{"DisplayName": newChannel.DisplayName})) + importerLog.WriteString(i18n.T("api.slackimport.slack_add_channels.import_failed", map[string]interface{}{"DisplayName": newChannel.DisplayName})) continue } } diff --git a/shared/i18n/i18n.go b/shared/i18n/i18n.go new file mode 100644 index 0000000000..7740f52284 --- /dev/null +++ b/shared/i18n/i18n.go @@ -0,0 +1,185 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +package i18n + +import ( + "fmt" + "html/template" + "io/ioutil" + "net/http" + "path/filepath" + "reflect" + "strings" + + "github.com/mattermost/go-i18n/i18n" + + "github.com/mattermost/mattermost-server/v5/mlog" +) + +const defaultLocale = "en" + +// TranslateFunc is the type of the translate functions +type TranslateFunc func(translationID string, args ...interface{}) string + +// T is the translate function using the default server language as fallback language +var T TranslateFunc + +// TDefault is the translate function using english as fallback language +var TDefault TranslateFunc + +var locales map[string]string = make(map[string]string) +var defaultServerLocale string +var defaultClientLocale string + +// TranslationsPreInit loads translations from filesystem if they are not +// loaded already and assigns english while loading server config +func TranslationsPreInit(translationsDir string) error { + if T != nil { + return nil + } + + // Set T even if we fail to load the translations. Lots of shutdown handling code will + // segfault trying to handle the error, and the untranslated IDs are strictly better. + T = tfuncWithFallback(defaultLocale) + TDefault = tfuncWithFallback(defaultLocale) + + return initTranslationsWithDir(translationsDir) +} + +// InitTranslations set the defaults configured in the server and initialize +// the T function using the server default as fallback language +func InitTranslations(serverLocale, clientLocale string) error { + defaultServerLocale = serverLocale + defaultClientLocale = clientLocale + + var err error + T, err = getTranslationsBySystemLocale() + return err +} + +func initTranslationsWithDir(dir string) error { + files, _ := ioutil.ReadDir(dir) + for _, f := range files { + if filepath.Ext(f.Name()) == ".json" { + filename := f.Name() + locales[strings.Split(filename, ".")[0]] = filepath.Join(dir, filename) + + if err := i18n.LoadTranslationFile(filepath.Join(dir, filename)); err != nil { + return err + } + } + } + + return nil +} + +func getTranslationsBySystemLocale() (TranslateFunc, error) { + locale := defaultServerLocale + if _, ok := locales[locale]; !ok { + mlog.Warn("Failed to load system translations for", mlog.String("locale", locale), mlog.String("attempting to fall back to default locale", defaultLocale)) + locale = defaultLocale + } + + if locales[locale] == "" { + return nil, fmt.Errorf("failed to load system translations for '%v'", defaultLocale) + } + + translations := tfuncWithFallback(locale) + if translations == nil { + return nil, fmt.Errorf("failed to load system translations") + } + + mlog.Info("Loaded system translations", mlog.String("for locale", locale), mlog.String("from locale", locales[locale])) + return translations, nil +} + +// GetUserTranslations get the translation function for an specific locale +func GetUserTranslations(locale string) TranslateFunc { + if _, ok := locales[locale]; !ok { + locale = defaultLocale + } + + translations := tfuncWithFallback(locale) + return translations +} + +// GetTranslationsAndLocaleFromRequest return the translation function and the +// locale based on a request headers +func GetTranslationsAndLocaleFromRequest(r *http.Request) (TranslateFunc, string) { + // This is for checking against locales like pt_BR or zn_CN + headerLocaleFull := strings.Split(r.Header.Get("Accept-Language"), ",")[0] + // This is for checking against locales like en, es + headerLocale := strings.Split(strings.Split(r.Header.Get("Accept-Language"), ",")[0], "-")[0] + defaultLocale := defaultClientLocale + if locales[headerLocaleFull] != "" { + translations := tfuncWithFallback(headerLocaleFull) + return translations, headerLocaleFull + } else if locales[headerLocale] != "" { + translations := tfuncWithFallback(headerLocale) + return translations, headerLocale + } else if locales[defaultLocale] != "" { + translations := tfuncWithFallback(defaultLocale) + return translations, headerLocale + } + + translations := tfuncWithFallback(defaultLocale) + return translations, defaultLocale +} + +// GetSupportedLocales return a map of locale code and the file path with the +// translations +func GetSupportedLocales() map[string]string { + return locales +} + +func tfuncWithFallback(pref string) TranslateFunc { + t, _ := i18n.Tfunc(pref) + return func(translationID string, args ...interface{}) string { + if translated := t(translationID, args...); translated != translationID { + return translated + } + + t, _ := i18n.Tfunc(defaultLocale) + return t(translationID, args...) + } +} + +// TranslateAsHTML translates the translationID provided and return a +// template.HTML object +func TranslateAsHTML(t TranslateFunc, translationID string, args map[string]interface{}) template.HTML { + message := t(translationID, escapeForHTML(args)) + message = strings.Replace(message, "[[", "", -1) + message = strings.Replace(message, "]]", "", -1) + return template.HTML(message) +} + +func escapeForHTML(arg interface{}) interface{} { + switch typedArg := arg.(type) { + case string: + return template.HTMLEscapeString(typedArg) + case *string: + return template.HTMLEscapeString(*typedArg) + case map[string]interface{}: + safeArg := make(map[string]interface{}, len(typedArg)) + for key, value := range typedArg { + safeArg[key] = escapeForHTML(value) + } + return safeArg + default: + mlog.Warn( + "Unable to escape value for HTML template", + mlog.Any("html_template", arg), + mlog.String("template_type", reflect.ValueOf(arg).Type().String()), + ) + return "" + } +} + +// IdentityTfunc returns a translation function that don't translate, only +// returns the same id +func IdentityTfunc() TranslateFunc { + return func(translationID string, args ...interface{}) string { + return translationID + } +} diff --git a/shared/i18n/i18n_test.go b/shared/i18n/i18n_test.go new file mode 100644 index 0000000000..89a228d4e1 --- /dev/null +++ b/shared/i18n/i18n_test.go @@ -0,0 +1,69 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +package i18n + +import ( + "testing" + + "github.com/mattermost/go-i18n/i18n/bundle" + "github.com/mattermost/go-i18n/i18n/language" + "github.com/mattermost/go-i18n/i18n/translation" + "github.com/stretchr/testify/assert" +) + +var htmlTestTranslationBundle *bundle.Bundle + +func init() { + htmlTestTranslationBundle = bundle.New() + fooBold, _ := translation.NewTranslation(map[string]interface{}{ + "id": "foo.bold", + "translation": "

[[{{ .Foo }}]]

", + }) + htmlTestTranslationBundle.AddTranslation(&language.Language{Tag: "en"}, fooBold) +} + +func TestTranslateAsHTML(t *testing.T) { + assert.EqualValues(t, "

<i>foo</i>

", TranslateAsHTML(TranslateFunc(htmlTestTranslationBundle.MustTfunc("en")), "foo.bold", map[string]interface{}{ + "Foo": "foo", + })) +} + +func TestEscapeForHTML(t *testing.T) { + stringForPointer := "abc" + for name, tc := range map[string]struct { + In interface{} + Expected interface{} + }{ + "NoHTML": { + In: "abc", + Expected: "abc", + }, + "String": { + In: "abc", + Expected: "<b>abc</b>", + }, + "StringPointer": { + In: &stringForPointer, + Expected: "<b>abc</b>", + }, + "Map": { + In: map[string]interface{}{ + "abc": "abc", + "123": "123", + }, + Expected: map[string]interface{}{ + "abc": "abc", + "123": "<b>123</b>", + }, + }, + "Unsupported": { + In: struct{ string }{"abc"}, + Expected: "", + }, + } { + t.Run(name, func(t *testing.T) { + assert.Equal(t, tc.Expected, escapeForHTML(tc.In)) + }) + } +} diff --git a/store/sqlstore/store.go b/store/sqlstore/store.go index c3451c97c6..d801756115 100644 --- a/store/sqlstore/store.go +++ b/store/sqlstore/store.go @@ -35,8 +35,8 @@ import ( "github.com/mattermost/mattermost-server/v5/einterfaces" "github.com/mattermost/mattermost-server/v5/mlog" "github.com/mattermost/mattermost-server/v5/model" + "github.com/mattermost/mattermost-server/v5/shared/i18n" "github.com/mattermost/mattermost-server/v5/store" - "github.com/mattermost/mattermost-server/v5/utils" ) type migrationDirection string @@ -1322,7 +1322,7 @@ func (me mattermConverter) FromDb(target interface{}) (gorp.CustomScanner, bool) binder := func(holder, target interface{}) error { s, ok := holder.(*string) if !ok { - return errors.New(utils.T("store.sql.convert_string_map")) + return errors.New(i18n.T("store.sql.convert_string_map")) } b := []byte(*s) return json.Unmarshal(b, target) @@ -1332,7 +1332,7 @@ func (me mattermConverter) FromDb(target interface{}) (gorp.CustomScanner, bool) binder := func(holder, target interface{}) error { s, ok := holder.(*string) if !ok { - return errors.New(utils.T("store.sql.convert_string_map")) + return errors.New(i18n.T("store.sql.convert_string_map")) } b := []byte(*s) return json.Unmarshal(b, target) @@ -1342,7 +1342,7 @@ func (me mattermConverter) FromDb(target interface{}) (gorp.CustomScanner, bool) binder := func(holder, target interface{}) error { s, ok := holder.(*string) if !ok { - return errors.New(utils.T("store.sql.convert_string_array")) + return errors.New(i18n.T("store.sql.convert_string_array")) } b := []byte(*s) return json.Unmarshal(b, target) @@ -1352,7 +1352,7 @@ func (me mattermConverter) FromDb(target interface{}) (gorp.CustomScanner, bool) binder := func(holder, target interface{}) error { s, ok := holder.(*string) if !ok { - return errors.New(utils.T("store.sql.convert_string_interface")) + return errors.New(i18n.T("store.sql.convert_string_interface")) } b := []byte(*s) return json.Unmarshal(b, target) @@ -1362,7 +1362,7 @@ func (me mattermConverter) FromDb(target interface{}) (gorp.CustomScanner, bool) binder := func(holder, target interface{}) error { s, ok := holder.(*string) if !ok { - return errors.New(utils.T("store.sql.convert_string_interface")) + return errors.New(i18n.T("store.sql.convert_string_interface")) } b := []byte(*s) return json.Unmarshal(b, target) diff --git a/utils/api.go b/utils/api.go index 0312e061c4..310796b35d 100644 --- a/utils/api.go +++ b/utils/api.go @@ -16,6 +16,7 @@ import ( "unicode/utf8" "github.com/mattermost/mattermost-server/v5/model" + "github.com/mattermost/mattermost-server/v5/shared/i18n" ) func CheckOrigin(r *http.Request, allowedOrigins string) bool { @@ -121,9 +122,9 @@ func RenderMobileAuthComplete(w http.ResponseWriter, redirectURL string) {
-

`+T("api.oauth.auth_complete")+`

-

`+T("api.oauth.redirecting_back")+`

- +

`+i18n.T("api.oauth.auth_complete")+`

+

`+i18n.T("api.oauth.redirecting_back")+`

+