diff --git a/api/channel.go b/api/channel.go index 4c9e514acb..ae92ab6189 100644 --- a/api/channel.go +++ b/api/channel.go @@ -826,47 +826,42 @@ func deleteChannel(c *Context, w http.ResponseWriter, r *http.Request) { return } + post := &model.Post{ + ChannelId: channel.Id, + Message: fmt.Sprintf(c.T("api.channel.delete_channel.archived"), user.Username), + Type: model.POST_CHANNEL_DELETED, + UserId: c.Session.UserId, + } + + if _, err := CreatePost(c, post, false); err != nil { + l4g.Error(utils.T("api.channel.delete_channel.failed_post.error"), err) + } + now := model.GetMillis() for _, hook := range incomingHooks { - go func() { - if result := <-Srv.Store.Webhook().DeleteIncoming(hook.Id, now); result.Err != nil { - l4g.Error(utils.T("api.channel.delete_channel.incoming_webhook.error"), hook.Id) - } - }() + if result := <-Srv.Store.Webhook().DeleteIncoming(hook.Id, now); result.Err != nil { + l4g.Error(utils.T("api.channel.delete_channel.incoming_webhook.error"), hook.Id) + } } for _, hook := range outgoingHooks { - go func() { - if result := <-Srv.Store.Webhook().DeleteOutgoing(hook.Id, now); result.Err != nil { - l4g.Error(utils.T("api.channel.delete_channel.outgoing_webhook.error"), hook.Id) - } - }() + if result := <-Srv.Store.Webhook().DeleteOutgoing(hook.Id, now); result.Err != nil { + l4g.Error(utils.T("api.channel.delete_channel.outgoing_webhook.error"), hook.Id) + } } - InvalidateCacheForChannel(channel.Id) if dresult := <-Srv.Store.Channel().Delete(channel.Id, model.GetMillis()); dresult.Err != nil { c.Err = dresult.Err return } + InvalidateCacheForChannel(channel.Id) c.LogAudit("name=" + channel.Name) - go func() { - message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_CHANNEL_DELETED, c.TeamId, "", "", nil) - message.Add("channel_id", channel.Id) + message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_CHANNEL_DELETED, c.TeamId, "", "", nil) + message.Add("channel_id", channel.Id) - go Publish(message) - - post := &model.Post{ - ChannelId: channel.Id, - Message: fmt.Sprintf(c.T("api.channel.delete_channel.archived"), user.Username), - Type: model.POST_CHANNEL_DELETED, - UserId: c.Session.UserId, - } - if _, err := CreatePost(c, post, false); err != nil { - l4g.Error(utils.T("api.channel.delete_channel.failed_post.error"), err) - } - }() + Publish(message) result := make(map[string]string) result["id"] = channel.Id diff --git a/api/command.go b/api/command.go index 842d678432..9c8f60be5e 100644 --- a/api/command.go +++ b/api/command.go @@ -134,7 +134,6 @@ func executeCommand(c *Context, w http.ResponseWriter, r *http.Request) { return } else { team = tr.Data.(*model.Team) - } var user *model.User @@ -247,23 +246,7 @@ func handleResponse(c *Context, w http.ResponseWriter, response *model.CommandRe } } - if response.ResponseType == model.COMMAND_RESPONSE_TYPE_IN_CHANNEL { - post.Message = response.Text - post.UserId = c.Session.UserId - if _, err := CreatePost(c, post, true); err != nil { - c.Err = model.NewLocAppError("command", "api.command.execute_command.save.app_error", nil, "") - } - } else if response.ResponseType == model.COMMAND_RESPONSE_TYPE_EPHEMERAL && response.Text != "" { - post.Message = response.Text - post.CreateAt = model.GetMillis() - post.UserId = c.Session.UserId - post.ParentId = "" - SendEphemeralPost( - c.TeamId, - c.Session.UserId, - post, - ) - } + CreateCommandPost(c, post, response) w.Write([]byte(response.ToJson())) } diff --git a/api/command_invite_people.go b/api/command_invite_people.go index ca2a2633ab..e6ad252f6d 100644 --- a/api/command_invite_people.go +++ b/api/command_invite_people.go @@ -72,7 +72,7 @@ func (me *InvitePeopleProvider) DoCommand(c *Context, args *model.CommandArgs, m user = result.Data.(*model.User) } - go InviteMembers(team, user.GetDisplayName(), emailList) + go InviteMembers(team, user.GetDisplayName(), emailList, c.GetSiteURL()) return &model.CommandResponse{ResponseType: model.COMMAND_RESPONSE_TYPE_EPHEMERAL, Text: c.T("api.command.invite_people.sent")} } diff --git a/api/post.go b/api/post.go index e8aef2f86a..8d255649e8 100644 --- a/api/post.go +++ b/api/post.go @@ -174,11 +174,9 @@ func CreatePost(c *Context, post *model.Post, triggerWebhooks bool) (*model.Post return rpost, nil } -func CreateWebhookPost(c *Context, channelId, text, overrideUsername, overrideIconUrl string, props model.StringInterface, postType string) (*model.Post, *model.AppError) { - // parse links into Markdown format - linkWithTextRegex := regexp.MustCompile(`<([^<\|]+)\|([^>]+)>`) - text = linkWithTextRegex.ReplaceAllString(text, "[${2}](${1})") +var linkWithTextRegex *regexp.Regexp = regexp.MustCompile(`<([^<\|]+)\|([^>]+)>`) +func CreateWebhookPost(c *Context, channelId, text, overrideUsername, overrideIconUrl string, props model.StringInterface, postType string) (*model.Post, *model.AppError) { post := &model.Post{UserId: c.Session.UserId, ChannelId: channelId, Message: text, Type: postType} post.AddProp("from_webhook", "true") @@ -196,41 +194,12 @@ func CreateWebhookPost(c *Context, channelId, text, overrideUsername, overrideIc } } + post.Message = parseSlackLinksToMarkdown(post.Message) + if len(props) > 0 { for key, val := range props { if key == "attachments" { - if list, success := val.([]interface{}); success { - // parse attachment links into Markdown format - for i, aInt := range list { - attachment := aInt.(map[string]interface{}) - if aText, ok := attachment["text"].(string); ok { - aText = linkWithTextRegex.ReplaceAllString(aText, "[${2}](${1})") - attachment["text"] = aText - list[i] = attachment - } - if aText, ok := attachment["pretext"].(string); ok { - aText = linkWithTextRegex.ReplaceAllString(aText, "[${2}](${1})") - attachment["pretext"] = aText - list[i] = attachment - } - if fVal, ok := attachment["fields"]; ok { - if fields, ok := fVal.([]interface{}); ok { - // parse attachment field links into Markdown format - for j, fInt := range fields { - field := fInt.(map[string]interface{}) - if fValue, ok := field["value"].(string); ok { - fValue = linkWithTextRegex.ReplaceAllString(fValue, "[${2}](${1})") - field["value"] = fValue - fields[j] = field - } - } - attachment["fields"] = fields - list[i] = attachment - } - } - } - post.AddProp(key, list) - } + parseSlackAttachment(post, val) } else if key != "override_icon_url" && key != "override_username" && key != "from_webhook" { post.AddProp(key, val) } @@ -244,6 +213,72 @@ func CreateWebhookPost(c *Context, channelId, text, overrideUsername, overrideIc return post, nil } +func CreateCommandPost(c *Context, post *model.Post, response *model.CommandResponse) { + post.Message = parseSlackLinksToMarkdown(response.Text) + post.UserId = c.Session.UserId + post.CreateAt = model.GetMillis() + + if response.Attachments != nil { + parseSlackAttachment(post, response.Attachments) + } + + switch response.ResponseType { + case model.COMMAND_RESPONSE_TYPE_IN_CHANNEL: + if _, err := CreatePost(c, post, true); err != nil { + c.Err = model.NewLocAppError("command", "api.command.execute_command.save.app_error", nil, "") + } + case model.COMMAND_RESPONSE_TYPE_EPHEMERAL: + if response.Text == "" { + return + } + + post.ParentId = "" + SendEphemeralPost(c.TeamId, c.Session.UserId, post) + } +} + +// This method only parses and processes the attachments, +// all else should be set in the post which is passed +func parseSlackAttachment(post *model.Post, attachments interface{}) { + post.Type = model.POST_SLACK_ATTACHMENT + + if list, success := attachments.([]interface{}); success { + for i, aInt := range list { + attachment := aInt.(map[string]interface{}) + if aText, ok := attachment["text"].(string); ok { + aText = linkWithTextRegex.ReplaceAllString(aText, "[${2}](${1})") + attachment["text"] = aText + list[i] = attachment + } + if aText, ok := attachment["pretext"].(string); ok { + aText = linkWithTextRegex.ReplaceAllString(aText, "[${2}](${1})") + attachment["pretext"] = aText + list[i] = attachment + } + if fVal, ok := attachment["fields"]; ok { + if fields, ok := fVal.([]interface{}); ok { + // parse attachment field links into Markdown format + for j, fInt := range fields { + field := fInt.(map[string]interface{}) + if fValue, ok := field["value"].(string); ok { + fValue = linkWithTextRegex.ReplaceAllString(fValue, "[${2}](${1})") + field["value"] = fValue + fields[j] = field + } + } + attachment["fields"] = fields + list[i] = attachment + } + } + } + post.AddProp("attachments", list) + } +} + +func parseSlackLinksToMarkdown(text string) string { + return linkWithTextRegex.ReplaceAllString(text, "[${2}](${1})") +} + func handlePostEvents(c *Context, post *model.Post, triggerWebhooks bool) { tchan := Srv.Store.Team().Get(c.TeamId) cchan := Srv.Store.Channel().Get(post.ChannelId, true) @@ -573,190 +608,190 @@ func getExplicitMentions(message string, keywords map[string][]string) (map[stri } func sendNotifications(c *Context, post *model.Post, team *model.Team, channel *model.Channel) []string { - pchan := Srv.Store.User().GetProfilesInChannel(channel.Id, -1, -1, true) - fchan := Srv.Store.FileInfo().GetForPost(post.Id) + mentionedUsersList := make([]string, 0) + var fchan store.StoreChannel + var senderUsername string - var profileMap map[string]*model.User - if result := <-pchan; result.Err != nil { - l4g.Error(utils.T("api.post.handle_post_events_and_forget.profiles.error"), c.TeamId, result.Err) - return nil + if post.IsSystemMessage() { + senderUsername = c.T("system.message.name") } else { - profileMap = result.Data.(map[string]*model.User) - } + pchan := Srv.Store.User().GetProfilesInChannel(channel.Id, -1, -1, true) + fchan = Srv.Store.FileInfo().GetForPost(post.Id) - // If the user who made the post is mention don't send a notification - if _, ok := profileMap[post.UserId]; !ok { - l4g.Error(utils.T("api.post.send_notifications_and_forget.user_id.error"), post.UserId) - return nil - } - - mentionedUserIds := make(map[string]bool) - allActivityPushUserIds := []string{} - hereNotification := false - channelNotification := false - allNotification := false - updateMentionChans := []store.StoreChannel{} - - if channel.Type == model.CHANNEL_DIRECT { - var otherUserId string - if userIds := strings.Split(channel.Name, "__"); userIds[0] == post.UserId { - otherUserId = userIds[1] + var profileMap map[string]*model.User + if result := <-pchan; result.Err != nil { + l4g.Error(utils.T("api.post.handle_post_events_and_forget.profiles.error"), c.TeamId, result.Err) + return nil } else { - otherUserId = userIds[0] + profileMap = result.Data.(map[string]*model.User) } - mentionedUserIds[otherUserId] = true - if post.Props["from_webhook"] == "true" { - mentionedUserIds[post.UserId] = true + // If the user who made the post is mention don't send a notification + if _, ok := profileMap[post.UserId]; !ok { + l4g.Error(utils.T("api.post.send_notifications_and_forget.user_id.error"), post.UserId) + return nil } - } else { - keywords := getMentionKeywordsInChannel(profileMap) - var potentialOtherMentions []string - mentionedUserIds, potentialOtherMentions, hereNotification, channelNotification, allNotification = getExplicitMentions(post.Message, keywords) + mentionedUserIds := make(map[string]bool) + allActivityPushUserIds := []string{} + hereNotification := false + channelNotification := false + allNotification := false + updateMentionChans := []store.StoreChannel{} - // get users that have comment thread mentions enabled - if len(post.RootId) > 0 { - if result := <-Srv.Store.Post().Get(post.RootId); result.Err != nil { - l4g.Error(utils.T("api.post.send_notifications_and_forget.comment_thread.error"), post.RootId, result.Err) - return nil + if channel.Type == model.CHANNEL_DIRECT { + var otherUserId string + if userIds := strings.Split(channel.Name, "__"); userIds[0] == post.UserId { + otherUserId = userIds[1] } else { - list := result.Data.(*model.PostList) + otherUserId = userIds[0] + } - for _, threadPost := range list.Posts { - profile := profileMap[threadPost.UserId] - if profile.NotifyProps["comments"] == "any" || (profile.NotifyProps["comments"] == "root" && threadPost.Id == list.Order[0]) { - mentionedUserIds[threadPost.UserId] = true + mentionedUserIds[otherUserId] = true + if post.Props["from_webhook"] == "true" { + mentionedUserIds[post.UserId] = true + } + } else { + keywords := getMentionKeywordsInChannel(profileMap) + + var potentialOtherMentions []string + mentionedUserIds, potentialOtherMentions, hereNotification, channelNotification, allNotification = getExplicitMentions(post.Message, keywords) + + // get users that have comment thread mentions enabled + if len(post.RootId) > 0 { + if result := <-Srv.Store.Post().Get(post.RootId); result.Err != nil { + l4g.Error(utils.T("api.post.send_notifications_and_forget.comment_thread.error"), post.RootId, result.Err) + return nil + } else { + list := result.Data.(*model.PostList) + + for _, threadPost := range list.Posts { + if profile, ok := profileMap[threadPost.UserId]; ok { + if profile.NotifyProps["comments"] == "any" || (profile.NotifyProps["comments"] == "root" && threadPost.Id == list.Order[0]) { + mentionedUserIds[threadPost.UserId] = true + } + } } } } - } - // prevent the user from mentioning themselves - if post.Props["from_webhook"] != "true" { - delete(mentionedUserIds, post.UserId) - } - - if len(potentialOtherMentions) > 0 { - if result := <-Srv.Store.User().GetProfilesByUsernames(potentialOtherMentions, team.Id); result.Err == nil { - outOfChannelMentions := result.Data.(map[string]*model.User) - go sendOutOfChannelMentions(c, post, outOfChannelMentions) + // prevent the user from mentioning themselves + if post.Props["from_webhook"] != "true" { + delete(mentionedUserIds, post.UserId) } - } - // find which users in the channel are set up to always receive mobile notifications - for _, profile := range profileMap { - if profile.NotifyProps["push"] == model.USER_NOTIFY_ALL && - (post.UserId != profile.Id || post.Props["from_webhook"] == "true") && - !post.IsSystemMessage() { - allActivityPushUserIds = append(allActivityPushUserIds, profile.Id) - } - } - } - - mentionedUsersList := make([]string, 0, len(mentionedUserIds)) - for id := range mentionedUserIds { - mentionedUsersList = append(mentionedUsersList, id) - updateMentionChans = append(updateMentionChans, Srv.Store.Channel().IncrementMentionCount(post.ChannelId, id)) - } - - var sender *model.User - senderName := make(map[string]string) - for _, id := range mentionedUsersList { - senderName[id] = "" - if post.IsSystemMessage() { - senderName[id] = c.T("system.message.name") - } else if profile, ok := profileMap[post.UserId]; ok { - if value, ok := post.Props["override_username"]; ok && post.Props["from_webhook"] == "true" { - senderName[id] = value.(string) - } else { - //Get the Display name preference from the receiver - if result := <-Srv.Store.Preference().Get(id, model.PREFERENCE_CATEGORY_DISPLAY_SETTINGS, "name_format"); result.Err != nil { - // Show default sender's name if user doesn't set display settings. - senderName[id] = profile.Username - } else { - senderName[id] = profile.GetDisplayNameForPreference(result.Data.(model.Preference).Value) + if len(potentialOtherMentions) > 0 { + if result := <-Srv.Store.User().GetProfilesByUsernames(potentialOtherMentions, team.Id); result.Err == nil { + outOfChannelMentions := result.Data.(map[string]*model.User) + go sendOutOfChannelMentions(c, post, outOfChannelMentions) + } + } + + // find which users in the channel are set up to always receive mobile notifications + for _, profile := range profileMap { + if profile.NotifyProps["push"] == model.USER_NOTIFY_ALL && + (post.UserId != profile.Id || post.Props["from_webhook"] == "true") { + allActivityPushUserIds = append(allActivityPushUserIds, profile.Id) } } - sender = profile } - } - var senderUsername string - if value, ok := post.Props["override_username"]; ok && post.Props["from_webhook"] == "true" { - senderUsername = value.(string) - } else { - senderUsername = profileMap[post.UserId].Username - } + mentionedUsersList = make([]string, 0, len(mentionedUserIds)) + for id := range mentionedUserIds { + mentionedUsersList = append(mentionedUsersList, id) + updateMentionChans = append(updateMentionChans, Srv.Store.Channel().IncrementMentionCount(post.ChannelId, id)) + } - if utils.Cfg.EmailSettings.SendEmailNotifications { + var sender *model.User + senderName := make(map[string]string) for _, id := range mentionedUsersList { - userAllowsEmails := profileMap[id].NotifyProps["email"] != "false" - - var status *model.Status - var err *model.AppError - if status, err = GetStatus(id); err != nil { - status = &model.Status{ - UserId: id, - Status: model.STATUS_OFFLINE, - Manual: false, - LastActivityAt: 0, - ActiveChannel: "", + senderName[id] = "" + if profile, ok := profileMap[post.UserId]; ok { + if value, ok := post.Props["override_username"]; ok && post.Props["from_webhook"] == "true" { + senderName[id] = value.(string) + } else { + //Get the Display name preference from the receiver + if result := <-Srv.Store.Preference().Get(id, model.PREFERENCE_CATEGORY_DISPLAY_SETTINGS, "name_format"); result.Err != nil { + // Show default sender's name if user doesn't set display settings. + senderName[id] = profile.Username + } else { + senderName[id] = profile.GetDisplayNameForPreference(result.Data.(model.Preference).Value) + } } - } - - if userAllowsEmails && status.Status != model.STATUS_ONLINE { - sendNotificationEmail(c, post, profileMap[id], channel, team, senderName[id], sender) + sender = profile } } - } - // If the channel has more than 1K users then @here is disabled - if hereNotification && int64(len(profileMap)) > *utils.Cfg.TeamSettings.MaxNotificationsPerChannel { - hereNotification = false - SendEphemeralPost( - c.TeamId, - post.UserId, - &model.Post{ - ChannelId: post.ChannelId, - Message: c.T("api.post.disabled_here", map[string]interface{}{"Users": *utils.Cfg.TeamSettings.MaxNotificationsPerChannel}), - CreateAt: post.CreateAt + 1, - }, - ) - } - - // If the channel has more than 1K users then @channel is disabled - if channelNotification && int64(len(profileMap)) > *utils.Cfg.TeamSettings.MaxNotificationsPerChannel { - SendEphemeralPost( - c.TeamId, - post.UserId, - &model.Post{ - ChannelId: post.ChannelId, - Message: c.T("api.post.disabled_channel", map[string]interface{}{"Users": *utils.Cfg.TeamSettings.MaxNotificationsPerChannel}), - CreateAt: post.CreateAt + 1, - }, - ) - } - - // If the channel has more than 1K users then @all is disabled - if allNotification && int64(len(profileMap)) > *utils.Cfg.TeamSettings.MaxNotificationsPerChannel { - SendEphemeralPost( - c.TeamId, - post.UserId, - &model.Post{ - ChannelId: post.ChannelId, - Message: c.T("api.post.disabled_all", map[string]interface{}{"Users": *utils.Cfg.TeamSettings.MaxNotificationsPerChannel}), - CreateAt: post.CreateAt + 1, - }, - ) - } - - if hereNotification { - if result := <-Srv.Store.Status().GetOnline(); result.Err != nil { - l4g.Warn(utils.T("api.post.notification.here.warn"), result.Err) - return nil + if value, ok := post.Props["override_username"]; ok && post.Props["from_webhook"] == "true" { + senderUsername = value.(string) } else { - statuses := result.Data.([]*model.Status) + senderUsername = profileMap[post.UserId].Username + } + + if utils.Cfg.EmailSettings.SendEmailNotifications { + for _, id := range mentionedUsersList { + userAllowsEmails := profileMap[id].NotifyProps["email"] != "false" + + var status *model.Status + var err *model.AppError + if status, err = GetStatus(id); err != nil { + status = &model.Status{ + UserId: id, + Status: model.STATUS_OFFLINE, + Manual: false, + LastActivityAt: 0, + ActiveChannel: "", + } + } + + if userAllowsEmails && status.Status != model.STATUS_ONLINE { + sendNotificationEmail(c, post, profileMap[id], channel, team, senderName[id], sender) + } + } + } + + // If the channel has more than 1K users then @here is disabled + if hereNotification && int64(len(profileMap)) > *utils.Cfg.TeamSettings.MaxNotificationsPerChannel { + hereNotification = false + SendEphemeralPost( + c.TeamId, + post.UserId, + &model.Post{ + ChannelId: post.ChannelId, + Message: c.T("api.post.disabled_here", map[string]interface{}{"Users": *utils.Cfg.TeamSettings.MaxNotificationsPerChannel}), + CreateAt: post.CreateAt + 1, + }, + ) + } + + // If the channel has more than 1K users then @channel is disabled + if channelNotification && int64(len(profileMap)) > *utils.Cfg.TeamSettings.MaxNotificationsPerChannel { + SendEphemeralPost( + c.TeamId, + post.UserId, + &model.Post{ + ChannelId: post.ChannelId, + Message: c.T("api.post.disabled_channel", map[string]interface{}{"Users": *utils.Cfg.TeamSettings.MaxNotificationsPerChannel}), + CreateAt: post.CreateAt + 1, + }, + ) + } + + // If the channel has more than 1K users then @all is disabled + if allNotification && int64(len(profileMap)) > *utils.Cfg.TeamSettings.MaxNotificationsPerChannel { + SendEphemeralPost( + c.TeamId, + post.UserId, + &model.Post{ + ChannelId: post.ChannelId, + Message: c.T("api.post.disabled_all", map[string]interface{}{"Users": *utils.Cfg.TeamSettings.MaxNotificationsPerChannel}), + CreateAt: post.CreateAt + 1, + }, + ) + } + + if hereNotification { + statuses := GetAllStatuses() for _, status := range statuses { if status.UserId == post.UserId { continue @@ -771,43 +806,29 @@ func sendNotifications(c *Context, post *model.Post, team *model.Team, channel * } } } - } - // Make sure all mention updates are complete to prevent race - // Probably better to batch these DB updates in the future - // MUST be completed before push notifications send - for _, uchan := range updateMentionChans { - if result := <-uchan; result.Err != nil { - l4g.Warn(utils.T("api.post.update_mention_count_and_forget.update_error"), post.Id, post.ChannelId, result.Err) - } - } - - sendPushNotifications := false - if *utils.Cfg.EmailSettings.SendPushNotifications { - pushServer := *utils.Cfg.EmailSettings.PushNotificationServer - if pushServer == model.MHPNS && (!utils.IsLicensed || !*utils.License.Features.MHPNS) { - l4g.Warn(utils.T("api.post.send_notifications_and_forget.push_notification.mhpnsWarn")) - sendPushNotifications = false - } else { - sendPushNotifications = true - } - } - - if sendPushNotifications { - for _, id := range mentionedUsersList { - var status *model.Status - var err *model.AppError - if status, err = GetStatus(id); err != nil { - status = &model.Status{id, model.STATUS_OFFLINE, false, 0, ""} - } - - if DoesStatusAllowPushNotification(profileMap[id], status, post.ChannelId) { - sendPushNotification(post, profileMap[id], channel, senderName[id], true) + // Make sure all mention updates are complete to prevent race + // Probably better to batch these DB updates in the future + // MUST be completed before push notifications send + for _, uchan := range updateMentionChans { + if result := <-uchan; result.Err != nil { + l4g.Warn(utils.T("api.post.update_mention_count_and_forget.update_error"), post.Id, post.ChannelId, result.Err) } } - for _, id := range allActivityPushUserIds { - if _, ok := mentionedUserIds[id]; !ok { + sendPushNotifications := false + if *utils.Cfg.EmailSettings.SendPushNotifications { + pushServer := *utils.Cfg.EmailSettings.PushNotificationServer + if pushServer == model.MHPNS && (!utils.IsLicensed || !*utils.License.Features.MHPNS) { + l4g.Warn(utils.T("api.post.send_notifications_and_forget.push_notification.mhpnsWarn")) + sendPushNotifications = false + } else { + sendPushNotifications = true + } + } + + if sendPushNotifications { + for _, id := range mentionedUsersList { var status *model.Status var err *model.AppError if status, err = GetStatus(id); err != nil { @@ -815,7 +836,21 @@ func sendNotifications(c *Context, post *model.Post, team *model.Team, channel * } if DoesStatusAllowPushNotification(profileMap[id], status, post.ChannelId) { - sendPushNotification(post, profileMap[id], channel, senderName[id], false) + sendPushNotification(post, profileMap[id], channel, senderName[id], true) + } + } + + for _, id := range allActivityPushUserIds { + if _, ok := mentionedUserIds[id]; !ok { + var status *model.Status + var err *model.AppError + if status, err = GetStatus(id); err != nil { + status = &model.Status{id, model.STATUS_OFFLINE, false, 0, ""} + } + + if DoesStatusAllowPushNotification(profileMap[id], status, post.ChannelId) { + sendPushNotification(post, profileMap[id], channel, senderName[id], false) + } } } } @@ -829,7 +864,7 @@ func sendNotifications(c *Context, post *model.Post, team *model.Team, channel * message.Add("sender_name", senderUsername) message.Add("team_id", team.Id) - if len(post.FileIds) != 0 { + if len(post.FileIds) != 0 && fchan != nil { message.Add("otherFile", "true") var infos []*model.FileInfo @@ -874,15 +909,18 @@ func sendNotificationEmail(c *Context, post *model.Post, user *model.User, chann for i := range teams { if teams[i].Id == team.Id { found = true + team = teams[i] break } } - if !found && len(teams) > 0 { - team = teams[0] - } else { - // in case the user hasn't joined any teams we send them to the select_team page - team = &model.Team{Name: "select_team", DisplayName: utils.Cfg.TeamSettings.SiteName} + if !found { + if len(teams) > 0 { + team = teams[0] + } else { + // in case the user hasn't joined any teams we send them to the select_team page + team = &model.Team{Name: "select_team", DisplayName: utils.Cfg.TeamSettings.SiteName} + } } } } diff --git a/api/status.go b/api/status.go index 99d5bc4172..909ab50ece 100644 --- a/api/status.go +++ b/api/status.go @@ -42,38 +42,31 @@ func InitStatus() { } func getStatusesHttp(c *Context, w http.ResponseWriter, r *http.Request) { - statusMap, err := GetAllStatuses() - if err != nil { - c.Err = err - return - } - + statusMap := model.StatusMapToInterfaceMap(GetAllStatuses()) w.Write([]byte(model.StringInterfaceToJson(statusMap))) } func getStatusesWebSocket(req *model.WebSocketRequest) (map[string]interface{}, *model.AppError) { - statusMap, err := GetAllStatuses() - if err != nil { - return nil, err - } - - return statusMap, nil + statusMap := GetAllStatuses() + return model.StatusMapToInterfaceMap(statusMap), nil } -// Only returns 300 statuses max -func GetAllStatuses() (map[string]interface{}, *model.AppError) { - if result := <-Srv.Store.Status().GetOnlineAway(); result.Err != nil { - return nil, result.Err - } else { - statuses := result.Data.([]*model.Status) +func GetAllStatuses() map[string]*model.Status { + userIds := statusCache.Keys() + statusMap := map[string]*model.Status{} - statusMap := map[string]interface{}{} - for _, s := range statuses { - statusMap[s.UserId] = s.Status + for _, userId := range userIds { + if id, ok := userId.(string); !ok { + continue + } else { + status := GetStatusFromCache(id) + if status != nil { + statusMap[id] = status + } } - - return statusMap, nil } + + return statusMap } func getStatusesByIdsHttp(c *Context, w http.ResponseWriter, r *http.Request) { @@ -268,12 +261,21 @@ func SetStatusAwayIfNeeded(userId string, manual bool) { go Publish(event) } -func GetStatus(userId string) (*model.Status, *model.AppError) { +func GetStatusFromCache(userId string) *model.Status { if result, ok := statusCache.Get(userId); ok { status := result.(*model.Status) statusCopy := &model.Status{} *statusCopy = *status - return statusCopy, nil + return statusCopy + } + + return nil +} + +func GetStatus(userId string) (*model.Status, *model.AppError) { + status := GetStatusFromCache(userId) + if status != nil { + return status, nil } if result := <-Srv.Store.Status().Get(userId); result.Err != nil { diff --git a/api/team.go b/api/team.go index c17bf87afb..c855a515d7 100644 --- a/api/team.go +++ b/api/team.go @@ -48,7 +48,7 @@ func InitTeam() { // These should be moved to the global admin console BaseRoutes.NeedTeam.Handle("/import_team", ApiUserRequired(importTeam)).Methods("POST") - BaseRoutes.Teams.Handle("/add_user_to_team_from_invite", ApiUserRequired(addUserToTeamFromInvite)).Methods("POST") + BaseRoutes.Teams.Handle("/add_user_to_team_from_invite", ApiUserRequiredMfa(addUserToTeamFromInvite)).Methods("POST") } func createTeam(c *Context, w http.ResponseWriter, r *http.Request) { @@ -378,7 +378,7 @@ func inviteMembers(c *Context, w http.ResponseWriter, r *http.Request) { emailList = append(emailList, invite["email"]) } - InviteMembers(team, user.GetDisplayName(), emailList) + InviteMembers(team, user.GetDisplayName(), emailList, c.GetSiteURL()) w.Write([]byte(invites.ToJson())) } @@ -640,7 +640,7 @@ func getMyTeamsUnread(c *Context, w http.ResponseWriter, r *http.Request) { } } -func InviteMembers(team *model.Team, senderName string, invites []string) { +func InviteMembers(team *model.Team, senderName string, invites []string, siteURL string) { for _, invite := range invites { if len(invite) > 0 { senderRole := utils.T("api.team.invite_members.member") @@ -649,13 +649,13 @@ func InviteMembers(team *model.Team, senderName string, invites []string) { map[string]interface{}{"SenderName": senderName, "TeamDisplayName": team.DisplayName, "SiteName": utils.ClientCfg["SiteName"]}) bodyPage := utils.NewHTMLTemplate("invite_body", model.DEFAULT_LOCALE) - bodyPage.Props["SiteURL"] = *utils.Cfg.ServiceSettings.SiteURL + bodyPage.Props["SiteURL"] = siteURL bodyPage.Props["Title"] = utils.T("api.templates.invite_body.title") bodyPage.Html["Info"] = template.HTML(utils.T("api.templates.invite_body.info", map[string]interface{}{"SenderStatus": senderRole, "SenderName": senderName, "TeamDisplayName": team.DisplayName})) bodyPage.Props["Button"] = utils.T("api.templates.invite_body.button") bodyPage.Html["ExtraInfo"] = template.HTML(utils.T("api.templates.invite_body.extra_info", - map[string]interface{}{"TeamDisplayName": team.DisplayName, "TeamURL": *utils.Cfg.ServiceSettings.SiteURL + "/" + team.Name})) + map[string]interface{}{"TeamDisplayName": team.DisplayName, "TeamURL": siteURL + "/" + team.Name})) props := make(map[string]string) props["email"] = invite @@ -665,7 +665,7 @@ func InviteMembers(team *model.Team, senderName string, invites []string) { props["time"] = fmt.Sprintf("%v", model.GetMillis()) data := model.MapToJson(props) hash := model.HashPassword(fmt.Sprintf("%v:%v", data, utils.Cfg.EmailSettings.InviteSalt)) - bodyPage.Props["Link"] = fmt.Sprintf("%s/signup_user_complete/?d=%s&h=%s", *utils.Cfg.ServiceSettings.SiteURL, url.QueryEscape(data), url.QueryEscape(hash)) + bodyPage.Props["Link"] = fmt.Sprintf("%s/signup_user_complete/?d=%s&h=%s", siteURL, url.QueryEscape(data), url.QueryEscape(hash)) if !utils.Cfg.EmailSettings.SendEmailNotifications { l4g.Info(utils.T("api.team.invite_members.sending.info"), invite, bodyPage.Props["Link"]) diff --git a/cmd/platform/oldcommands.go b/cmd/platform/oldcommands.go index 1cf8988829..a599fa47ed 100644 --- a/cmd/platform/oldcommands.go +++ b/cmd/platform/oldcommands.go @@ -319,7 +319,8 @@ func cmdInviteUser() { } invites := []string{flagEmail} - api.InviteMembers(team, user.GetDisplayName(), invites) + c := getMockContext() + api.InviteMembers(team, user.GetDisplayName(), invites, c.GetSiteURL()) os.Exit(0) } diff --git a/cmd/platform/user.go b/cmd/platform/user.go index 43a00e68df..373274241c 100644 --- a/cmd/platform/user.go +++ b/cmd/platform/user.go @@ -261,7 +261,7 @@ func inviteUser(email string, team *model.Team, teamArg string) { CommandPrintErrorln("Can't find team '" + teamArg + "'") return } - api.InviteMembers(team, "Administrator", invites) + api.InviteMembers(team, "Administrator", invites, *utils.Cfg.ServiceSettings.SiteURL) CommandPrettyPrintln("Invites may or may not have been sent.") } diff --git a/i18n/de.json b/i18n/de.json index 03cea6f10f..311798c745 100644 --- a/i18n/de.json +++ b/i18n/de.json @@ -737,11 +737,11 @@ }, { "id": "api.command_shortcuts.msgs.reprint_next", - "translation": "{{.CmdOrCtrl}}+HOCH (im leeren Eingabefeld): Die letzte Nachricht oder den letzten Slash-Befehl anzeigen\n" + "translation": "{{.CmdOrCtrl}}+RUNTER (im leeren Eingabefeld): Die nächste Nachricht oder den nächsten Slash-Befehl anzeigen\n" }, { "id": "api.command_shortcuts.msgs.reprint_prev", - "translation": "{{.CmdOrCtrl}}+HOCH (im leeren Eingabefeld): Die letzte Nachricht oder den letzten Slash-Befehl anzeigen\n" + "translation": "{{.CmdOrCtrl}}+HOCH (im leeren Eingabefeld): Die vorherige Nachricht oder den vorherigen Slash-Befehl anzeigen\n" }, { "id": "api.command_shortcuts.name", @@ -1173,6 +1173,10 @@ "id": "api.general.init.debug", "translation": "Initialisiere allgemeine API-Routen" }, + { + "id": "api.import.import_post.attach_files.error", + "translation": "Fehler beim Anfügen der Dateien an Nachricht. postId=%v, fileIds=%v, message=%v" + }, { "id": "api.import.import_post.saving.debug", "translation": "Nachricht konnte nicht gespeichert werden. Benutzer=%v, Nachricht=%v" diff --git a/i18n/es.json b/i18n/es.json index 9fd52e88ab..436788d4fd 100644 --- a/i18n/es.json +++ b/i18n/es.json @@ -1173,6 +1173,10 @@ "id": "api.general.init.debug", "translation": "Inicializando rutas generales del API" }, + { + "id": "api.import.import_post.attach_files.error", + "translation": "Error de adjuntar archivos al mensaje. postId=%v, fileIds=%v, mensaje=%v" + }, { "id": "api.import.import_post.saving.debug", "translation": "Error guardando el mensaje. user=%v, message=%v" @@ -2729,7 +2733,7 @@ }, { "id": "api.webhook.delete_outgoing.permissions.app_error", - "translation": "Permisos inapropiados para eliminar el webhook de salida" + "translation": "Permisos no válidos para eliminar el webhook de salida" }, { "id": "api.webhook.get_incoming.disabled.app_error", @@ -2757,7 +2761,7 @@ }, { "id": "api.webhook.regen_outgoing_token.permissions.app_error", - "translation": "Permisos inapropiados para regenerar un token para el webhook de salida" + "translation": "Permisos no válidos para regenerar un token para el webhook de salida" }, { "id": "api.webrtc.disabled.app_error", @@ -5185,7 +5189,7 @@ }, { "id": "store.sql_user.update_auth_data.email_exists.app_error", - "translation": "No se puede cambiar la cuenta a {{.Servicio}}. Ya existe una cuenta con el correo electrónico {{.Email}}." + "translation": "No se puede cambiar la cuenta a {{.Service}}. Ya existe una cuenta con el correo electrónico {{.Email}}." }, { "id": "store.sql_user.update_failed_pwd_attempts.app_error", diff --git a/i18n/fr.json b/i18n/fr.json index b86bc3d6e3..e4b73ca9fd 100644 --- a/i18n/fr.json +++ b/i18n/fr.json @@ -73,7 +73,7 @@ }, { "id": "api.admin.init.debug", - "translation": "Initialisation des routes API d'administration" + "translation": "Initialisation du routage des API d'administration" }, { "id": "api.admin.recycle_db_end.warn", @@ -93,7 +93,7 @@ }, { "id": "api.admin.test_email.body", - "translation": "


Votre messagerie Mattermost semble être bien configurée !" + "translation": "


La configuration e-mail de Mattermost s'est déroulée avec succès !" }, { "id": "api.admin.test_email.missing_server", @@ -105,7 +105,7 @@ }, { "id": "api.admin.test_email.subject", - "translation": "Mattermost - Test des réglages de messagerie" + "translation": "Mattermost - Test des réglages e-mail" }, { "id": "api.admin.upload_brand_image.array.app_error", @@ -197,7 +197,7 @@ }, { "id": "api.channel.create_channel.direct_channel.app_error", - "translation": "Vous devez utilisez le service api createDirectChannel pour la création d'un canal de messages privés" + "translation": "Vous devez utiliser le service d'API createDirectChannel pour la création d'un canal de messages privés" }, { "id": "api.channel.create_channel.invalid_character.app_error", @@ -217,7 +217,7 @@ }, { "id": "api.channel.create_direct_channel.invalid_user.app_error", - "translation": "Autre id utilisateur invalide" + "translation": "L'autre utilisateur a une ID invalide " }, { "id": "api.channel.delete_channel.archived", @@ -301,7 +301,7 @@ }, { "id": "api.channel.post_update_channel_displayname_message_and_forget.create_post.error", - "translation": "Failed to post displayname update message %v" + "translation": "Echec de l'envoi de la mise à jour du message de %v" }, { "id": "api.channel.post_update_channel_displayname_message_and_forget.retrieve_user.error", @@ -337,7 +337,7 @@ }, { "id": "api.channel.remove.default.app_error", - "translation": "Impossible de quitter le canal par défaut {{.Channel}}" + "translation": "Impossible de supprimer l'utilisateur du canal par défaut {{.Channel}}" }, { "id": "api.channel.remove_member.permissions.app_error", @@ -421,19 +421,19 @@ }, { "id": "api.command.init.debug", - "translation": "Initialisation des routes de l'api des commandes" + "translation": "Initialisation des routes de l'API des commandes" }, { "id": "api.command.invite_people.desc", - "translation": "Envoyer un courriel d'invitation à votre équipe" + "translation": "Envoyer un e-mail d'invitation à votre équipe" }, { "id": "api.command.invite_people.email_off", - "translation": "La messagerie n'est pas configurée, aucun courriel envoyé." + "translation": "Les e-mails n'ont pas été configurés, aucune invitation envoyée." }, { "id": "api.command.invite_people.fail", - "translation": "Un problème s'est produit à l'envoi du courriel d'invitation." + "translation": "Un problème s'est produit à l'envoi de l'e-mail d'invitation." }, { "id": "api.command.invite_people.hint", @@ -445,23 +445,23 @@ }, { "id": "api.command.invite_people.no_email", - "translation": "S'il vous plaît spécifier une ou plusieurs adresses e-mail valides" + "translation": "Veuillez spécifier une ou plusieurs adresses e-mail valides" }, { "id": "api.command.invite_people.sent", - "translation": "Mail d'invitation envoyé" + "translation": "E-mail(s) d'invitation envoyé(s)" }, { "id": "api.command.regen.app_error", - "translation": "Droits insuffisants pour regénérer la clé de commande" + "translation": "Droits insuffisants pour regénérer le jeton de commande" }, { "id": "api.command.team_mismatch.app_error", - "translation": "Cannot update commands across teams" + "translation": "Impossible de mettre à jour les commandes entre équipes" }, { "id": "api.command.update.app_error", - "translation": "Droits insuffisants pour supprimer la commande" + "translation": "Droits insuffisants pour mettre à jour la commande" }, { "id": "api.command_away.desc", @@ -485,7 +485,7 @@ }, { "id": "api.command_collapse.success", - "translation": "Image links now collapse by default" + "translation": "Les liens vers les images se réduisent maintenant par défaut" }, { "id": "api.command_echo.create.app_error", @@ -509,7 +509,7 @@ }, { "id": "api.command_echo.message.app_error", - "translation": "A message must be provided with the /echo command." + "translation": "Un message doit être fourni avec la commande /echo." }, { "id": "api.command_echo.name", @@ -525,7 +525,7 @@ }, { "id": "api.command_expand.success", - "translation": "Image links now expand by default" + "translation": "Les liens vers les images s'étendent maintenant par défaut" }, { "id": "api.command_expand_collapse.fail.app_error", @@ -545,7 +545,7 @@ }, { "id": "api.command_join.list.app_error", - "translation": "Une erreur s'est produite lors de l'énumération des canaux." + "translation": "Une erreur s'est produite lors de la récupération de la liste des canaux." }, { "id": "api.command_join.missing.app_error", @@ -593,7 +593,7 @@ }, { "id": "api.command_msg.fail.app_error", - "translation": "Erreur lors de l'envoi du message à l'utilisateur." + "translation": "Une erreur s'est produite lors de l'envoi du message à l'utilisateur." }, { "id": "api.command_msg.hint", @@ -601,7 +601,7 @@ }, { "id": "api.command_msg.list.app_error", - "translation": "Erreur de récupération du listing des utilisateurs." + "translation": "Une erreur s'est produite lors de la récupération de la liste des utilisateurs." }, { "id": "api.command_msg.missing.app_error", @@ -641,11 +641,11 @@ }, { "id": "api.command_shortcuts.browser.channel_next", - "translation": "{{.ChannelNextCmd}}: Next channel in your history\n" + "translation": "{{.ChannelNextCmd}}: Canal suivant dans votre historique\n" }, { "id": "api.command_shortcuts.browser.channel_next.cmd", - "translation": "ALT+RIGHT" + "translation": "ALT+DROITE" }, { "id": "api.command_shortcuts.browser.channel_next.cmd_mac", @@ -653,11 +653,11 @@ }, { "id": "api.command_shortcuts.browser.channel_prev", - "translation": "{{.ChannelPrevCmd}}: Previous channel in your history\n" + "translation": "{{.ChannelPrevCmd}} : Canal précédent dans votre historique\n" }, { "id": "api.command_shortcuts.browser.channel_prev.cmd", - "translation": "ALT+LEFT" + "translation": "ALT+GAUCHE" }, { "id": "api.command_shortcuts.browser.channel_prev.cmd_mac", @@ -665,27 +665,27 @@ }, { "id": "api.command_shortcuts.browser.font_decrease", - "translation": "{{.CmdOrCtrl}}+MINUS: Decrease font size (zoom out)\n" + "translation": "{{.CmdOrCtrl}}+MOINS : Diminue la taille de la police de caractères (zoom arrière)\n" }, { "id": "api.command_shortcuts.browser.font_increase", - "translation": "{{.CmdOrCtrl}}+PLUS: Increase font size (zoom in)\n" + "translation": "{{.CmdOrCtrl}}+PLUS: Augmente la taille de la police de caractères (zoom avant)\n" }, { "id": "api.command_shortcuts.browser.header", - "translation": "#### Built-in Browser Commands\n\n" + "translation": "#### Commandes intégrées au navigateur\n\n" }, { "id": "api.command_shortcuts.browser.highlight_next", - "translation": "SHIFT+DOWN (in input field): Highlight text to the next line\n" + "translation": "MAJ+BAS (dans le champ de saisie) : Sélectionne le texte jusqu'à la ligne suivante\n" }, { "id": "api.command_shortcuts.browser.highlight_prev", - "translation": "SHIFT+UP (in input field): Highlight text to the previous line\n" + "translation": "MAJ+HAUT (dans le champ de saisie) : Sélectionne le texte jusqu'à la ligne précédente\n" }, { "id": "api.command_shortcuts.browser.newline", - "translation": "SHIFT+ENTER (in input field): Create a new line\n" + "translation": "MAJ+ENTREE (dans le champ de saisie) : Crée une nouvelle ligne\n" }, { "id": "api.command_shortcuts.cmd", @@ -701,31 +701,31 @@ }, { "id": "api.command_shortcuts.files.header", - "translation": "#### Files\n\n" + "translation": "#### Fichiers\n\n" }, { "id": "api.command_shortcuts.files.upload", - "translation": "{{.CmdOrCtrl}}+U: Upload file(s)\n\n" + "translation": "{{.CmdOrCtrl}}+U : Envoie des fichiers\n\n" }, { "id": "api.command_shortcuts.header", - "translation": "### Keyboard Shortcuts\n\n" + "translation": "### Raccourcis clavier\n\n" }, { "id": "api.command_shortcuts.msgs.comp_channel", - "translation": "~[character]+TAB: Autocomplete channel beginning with [character]\n" + "translation": "~[caractère]+TAB: Saisi automatiquement le nom du canal commencant par [caractère]\n" }, { "id": "api.command_shortcuts.msgs.comp_emoji", - "translation": ":[character]+TAB: Autocomplete emoji beginning with [character]\n\n" + "translation": ":[caractère]+TAB: Saisi automatiquement l'émoticône commencant par [caractère]\n\n" }, { "id": "api.command_shortcuts.msgs.comp_username", - "translation": "@[character]+TAB: Autocomplete @username beginning with [character]\n" + "translation": "@[caractère]+TAB: Saisi automatiquement le nom d'@utilisateur commencant par [caractère]\n" }, { "id": "api.command_shortcuts.msgs.edit", - "translation": "UP (in empty input field): Edit your last message in the current channel\n" + "translation": "HAUT (dans le champ de saisie vide): Édite le denier message du canal en cours\n" }, { "id": "api.command_shortcuts.msgs.header", @@ -733,15 +733,15 @@ }, { "id": "api.command_shortcuts.msgs.mark_as_read", - "translation": "ESC: Mark all messages in the current channel as read\n" + "translation": "ECHAP: Marque tous les messages du canal en cours comme lus\n" }, { "id": "api.command_shortcuts.msgs.reprint_next", - "translation": "{{.CmdOrCtrl}}+DOWN (in empty input field): Reprint the next message or slash command you entered\n" + "translation": "{{.CmdOrCtrl}}+BAS (dans le champ de saisie vide): Affiche à nouveau le message ou la commande slash suivants que vous avez saisis\n" }, { "id": "api.command_shortcuts.msgs.reprint_prev", - "translation": "{{.CmdOrCtrl}}+UP (in empty input field): Reprint the previous message or slash command you entered\n" + "translation": "{{.CmdOrCtrl}}+HAUT (dans le champ de saisie vide): Affiche à nouveau le message ou la commande slash précédents que vous avez saisis\n" }, { "id": "api.command_shortcuts.name", @@ -753,31 +753,31 @@ }, { "id": "api.command_shortcuts.nav.next", - "translation": "ALT+DOWN: Next channel or direct message in left hand sidebar\n" + "translation": "ALT+BAS: Canal ou message privé suivants de la barre latérale gauche\n" }, { "id": "api.command_shortcuts.nav.prev", - "translation": "ALT+UP: Previous channel or direct message in left hand sidebar\n" + "translation": "ALT+HAUT: Canal ou message privé précédents de la barre latérale gauche\n" }, { "id": "api.command_shortcuts.nav.recent_mentions", - "translation": "{{.CmdOrCtrl}}+SHIFT+M: Open recent mentions\n\n" + "translation": "{{.CmdOrCtrl}}+MAJ+M: Ouvre les mentions récentes\n\n" }, { "id": "api.command_shortcuts.nav.settings", - "translation": "{{.CmdOrCtrl}}+SHIFT+A: Open account settings\n" + "translation": "{{.CmdOrCtrl}}+SHIFT+A: Ouvre les paramètres du compte\n" }, { "id": "api.command_shortcuts.nav.switcher", - "translation": "{{.CmdOrCtrl}}+K: Open a quick channel switcher dialog\n" + "translation": "{{.CmdOrCtrl}}+K: Ouvre une une boite de dialogue permettant de passer rapidement d'un canal à l'autre\n" }, { "id": "api.command_shortcuts.nav.unread_next", - "translation": "ALT+SHIFT+DOWN: Next channel or direct message in left hand sidebar with unread messages\n" + "translation": "ALT+MAJ+BAS: Canal ou message privé suivants de la barre latérale gauche comportant des messages non lus\n" }, { "id": "api.command_shortcuts.nav.unread_prev", - "translation": "ALT+SHIFT+UP: Previous channel or direct message in left hand sidebar with unread messages\n" + "translation": "ALT+MAJ+HAUT: Canal ou message précédent de la barre latérale gauche comportant des messages non lus\n" }, { "id": "api.command_shrug.desc", @@ -801,7 +801,7 @@ }, { "id": "api.context.invalid_team_url.debug", - "translation": "L'URL d'équipe accédée n'est pas valide. l'URL d'équipe ne devrait pas être utilisée dans des fonctions d'api ou des fonctions indépendantes d'une équipe" + "translation": "URL d'équipe utilisée si l'appel est invalide. L'URL d'équipe ne devrait pas être utilisée dans des fonctions d'API ou des fonctions indépendantes d'une équipe" }, { "id": "api.context.invalid_token.error", @@ -809,7 +809,7 @@ }, { "id": "api.context.invalidate_all_caches", - "translation": "Purging all caches" + "translation": "Purger tous les caches" }, { "id": "api.context.last_activity_at.error", @@ -821,11 +821,11 @@ }, { "id": "api.context.mfa_required.app_error", - "translation": "Multi-factor authentication is required on this server." + "translation": "L'authentification multi-facteurs est requise sur ce serveur." }, { "id": "api.context.missing_teamid.app_error", - "translation": "Missing Team Id" + "translation": "ID d'équipe manquant" }, { "id": "api.context.permissions.app_error", @@ -849,23 +849,23 @@ }, { "id": "api.email_batching.add_notification_email_to_batch.channel_full.app_error", - "translation": "Le canal recevant les courriels envoyés par lot est plein. Veuillez augmenter le paramètre EmailBatchingBufferSize." + "translation": "Le canal recevant les e-mail envoyés par lot est plein. Veuillez augmenter le paramètre EmailBatchingBufferSize." }, { "id": "api.email_batching.add_notification_email_to_batch.disabled.app_error", - "translation": "Les liens publics sont désactivés par l'administrateur système." + "translation": "L'envoi d'e-mails par lot a été désactivé par l'administrateur système." }, { "id": "api.email_batching.check_pending_emails.finished_running", - "translation": "Le job d'envoi de courriels par lot vient de s'exécuter. %v utilisateur(s) ont encore des notifications en attente." + "translation": "La tâche d'envoi d'e-mails par lot vient de s'exécuter. %v utilisateur(s) ont encore des notifications en attente." }, { "id": "api.email_batching.check_pending_emails.status.app_error", - "translation": "Impossible de trouver le statut du destinataire pour l'envoi par lot des notifications par courriel" + "translation": "Impossible de trouver le statut du destinataire pour l'envoi par lot des notifications par e-mail" }, { "id": "api.email_batching.render_batched_post.channel.app_error", - "translation": "Impossible de trouver le canal du message pour l'envoi par lot des notifications par courriel" + "translation": "Impossible de trouver le canal du message pour l'envoi par lot des notifications par e-mail" }, { "id": "api.email_batching.render_batched_post.date", @@ -881,7 +881,7 @@ }, { "id": "api.email_batching.render_batched_post.sender.app_error", - "translation": "Impossible de trouver l’expéditeur du message pour l'envoi de courriels groupés" + "translation": "Impossible de trouver l’expéditeur du message pour l'envoi d'e-mails groupés" }, { "id": "api.email_batching.send_batched_email_notification.body_text", @@ -892,11 +892,11 @@ }, { "id": "api.email_batching.send_batched_email_notification.preferences.app_error", - "translation": "Impossible de trouver les préférences d'affichage du destinataire pour l'envoi de courriels groupés" + "translation": "Impossible de trouver les préférences d'affichage du destinataire pour l'envoi de e-mails groupés" }, { "id": "api.email_batching.send_batched_email_notification.send.app_error", - "translation": "Impossible d'envoyer le courriel groupé à %v: %v" + "translation": "Impossible d'envoyer l'e-mail groupé à %v: %v" }, { "id": "api.email_batching.send_batched_email_notification.subject", @@ -907,11 +907,11 @@ }, { "id": "api.email_batching.send_batched_email_notification.user.app_error", - "translation": "Impossible de trouver un destinataire pour l'envoi de courriels groupés" + "translation": "Impossible de trouver un destinataire pour l'envoi d'e-mails groupés" }, { "id": "api.email_batching.start.starting", - "translation": "Début de l'envoi de courriels groupés. Vérification des courriels en attente toutes les %v secondes." + "translation": "Début de l'envoi d'e-mails groupés. Vérification des e-mails en attente toutes les %v secondes." }, { "id": "api.emoji.create.duplicate.app_error", @@ -927,11 +927,11 @@ }, { "id": "api.emoji.create.too_large.app_error", - "translation": "Impossible de créer l'émoticône. L'image doit faire moins de 64Kio." + "translation": "Impossible de créer l'émoticône. L'image doit faire moins de 1 Mio." }, { "id": "api.emoji.delete.delete_reactions.app_error", - "translation": "Unable to delete reactions when deleting emoji with emoji name %v" + "translation": "Impossible de supprimer les réactions lors de la suppression de l'émotiĉone portant le nom %v" }, { "id": "api.emoji.delete.permissions.app_error", @@ -951,7 +951,7 @@ }, { "id": "api.emoji.init.debug", - "translation": "Initialisation des routes de l'api des émoticônes" + "translation": "Initialisation des routes de l'API des émoticônes" }, { "id": "api.emoji.storage.app_error", @@ -963,19 +963,19 @@ }, { "id": "api.emoji.upload.large_image.decode_error", - "translation": "Unable to create emoji. An error occurred when trying to decode the image." + "translation": "Impossible de créer l'émoticône. Une erreur est survenue durant le décodage de l'image." }, { "id": "api.emoji.upload.large_image.encode_error", - "translation": "Unable to create emoji. An error occurred when trying to encode the image." + "translation": "Impossible de créer l'émoticône. Une erreur est survenue durant l'encodage de l'image." }, { "id": "api.emoji.upload.large_image.gif_decode_error", - "translation": "Unable to create emoji. An error occurred when trying to decode the GIF image." + "translation": "Impossible de créer l'émoticône. Une erreur est survenue durant le décodage de l'image GIF." }, { "id": "api.emoji.upload.large_image.gif_encode_error", - "translation": "Unable to create emoji. An error occurred when trying to encode the GIF image." + "translation": "Impossible de créer l'émoticône. Une erreur est survenue durant l'encodage de l'image GIF." }, { "id": "api.file.get_file.public_disabled.app_error", @@ -1039,7 +1039,7 @@ }, { "id": "api.file.init.debug", - "translation": "Initialisation des routes de l'api des fichiers" + "translation": "Initialisation des routes de l'API des fichiers" }, { "id": "api.file.migrate_filenames_to_file_infos.channel.app_error", @@ -1143,7 +1143,7 @@ }, { "id": "api.file.upload_file.large_image.app_error", - "translation": "File above maximum dimensions could not be uploaded: {{.Filename}}" + "translation": "Le fichier est au-dessus des limites de dimensions, il n'a pas pu être envoyé : {{.Filename}}" }, { "id": "api.file.upload_file.storage.app_error", @@ -1171,7 +1171,11 @@ }, { "id": "api.general.init.debug", - "translation": "Initialisation des routes de l'api" + "translation": "Initialisation des routes générales de l'API" + }, + { + "id": "api.import.import_post.attach_files.error", + "translation": "Une erreur s'est produite lors de l'ajout des fichiers au message. postId=%v, fileIds=%v, message=%v" }, { "id": "api.import.import_post.saving.debug", @@ -1191,7 +1195,7 @@ }, { "id": "api.import.import_user.set_email.error", - "translation": "Impossible de marquer l'adresse électronique comme vérifiée err=%v" + "translation": "Impossible de marquer l'adresse e-mail comme vérifiée err=%v" }, { "id": "api.license.add_license.array.app_error", @@ -1227,11 +1231,11 @@ }, { "id": "api.license.add_license.unique_users.app_error", - "translation": "Cette licence supporte {{.Users}} utilisateur, mais votre système compte {{.Count}} utilisateurs uniques. Les utilisateurs uniques sont comptabilisés par adresse électronique distincte. Vous pouvez voir le nombre d'utilisateurs uniques dans le menu \"Rapports -> Statistiques\"." + "translation": "Cette licence supporte {{.Users}} utilisateurs, mais votre système compte {{.Count}} utilisateurs uniques. Les utilisateurs uniques sont comptabilisés par adresse e-mail distincte. Vous pouvez voir le nombre d'utilisateurs uniques dans le menu \"Rapports -> Statistiques\"." }, { "id": "api.license.init.debug", - "translation": "Initialisation des routes de l'api des licences" + "translation": "Initialisation des routes de l'API des licences" }, { "id": "api.license.remove_license.remove.app_error", @@ -1275,7 +1279,7 @@ }, { "id": "api.oauth.delete.permissions.app_error", - "translation": "Permissions insuffisantes pour supprimer l'application OAuth 2" + "translation": "Permissions insuffisantes pour supprimer l'application OAuth2" }, { "id": "api.oauth.get_access_token.bad_client_id.app_error", @@ -1339,11 +1343,11 @@ }, { "id": "api.oauth.init.debug", - "translation": "Initialisation des routes de l'api oauth" + "translation": "Initialisation des routes de l'API OAuth" }, { "id": "api.oauth.regenerate_secret.app_error", - "translation": "Permissions insuffisantes pour supprimer l'application OAuth 2" + "translation": "Permissions insuffisantes pour regénérer la clé secrète de l'application OAuth2" }, { "id": "api.oauth.register_oauth_app.turn_off.app_error", @@ -1383,7 +1387,7 @@ }, { "id": "api.post.create_post.attach_files.error", - "translation": "Une erreur s'est produite en ajoutant les fichiers au message, post_id=%s, user_id=%s, file_ids=%v, err=%v" + "translation": "Une erreur s'est produite lors de l'ajout des fichiers au message, post_id=%s, user_id=%s, file_ids=%v, err=%v" }, { "id": "api.post.create_post.bad_filename.error", @@ -1427,15 +1431,15 @@ }, { "id": "api.post.disabled_all", - "translation": "@all has been disabled because the channel has more than {{.Users}} users." + "translation": "@all a été désactivé car le canal a plus de {{.Users}} utilisateurs." }, { "id": "api.post.disabled_channel", - "translation": "@channel has been disabled because the channel has more than {{.Users}} users." + "translation": "@channel a été désactivé car le canal a plus de {{.Users}} utilisateurs." }, { "id": "api.post.disabled_here", - "translation": "@here has been disabled because the channel has more than {{.Users}} users." + "translation": "@here a été désactivé car le canal a plus de {{.Users}} utilisateurs." }, { "id": "api.post.get_message_for_notification.files_sent", @@ -1497,7 +1501,7 @@ }, { "id": "api.post.init.debug", - "translation": "Initialisation des routes de l'api des messages" + "translation": "Initialisation des routes de l'API des messages" }, { "id": "api.post.make_direct_channel_visible.get_2_members.error", @@ -1581,7 +1585,7 @@ }, { "id": "api.post.send_notifications_and_forget.send.error", - "translation": "Impossible d'envoyer le courriel de mention email=%v err=%v" + "translation": "Impossible d'envoyer l'e-mail de mention email=%v err=%v" }, { "id": "api.post.send_notifications_and_forget.sent", @@ -1629,7 +1633,7 @@ }, { "id": "api.preference.init.debug", - "translation": "Initialisation des routes de l'api des préférences" + "translation": "Initialisation des routes de l'API des préférences" }, { "id": "api.preference.save_preferences.decode.app_error", @@ -1645,23 +1649,23 @@ }, { "id": "api.reaction.delete_reaction.mismatched_channel_id.app_error", - "translation": "Failed to delete reaction because channel ID does not match post ID in the URL" + "translation": "Impossible de supprimer la réaction car l'ID du canal ne correspond pas à l'ID du message dans l'URL" }, { "id": "api.reaction.init.debug", - "translation": "Initialisation des routes API d'administration" + "translation": "Initialisation des routes de l'API des réactions" }, { "id": "api.reaction.list_reactions.mismatched_channel_id.app_error", - "translation": "Failed to get reactions because channel ID does not match post ID in the URL" + "translation": "Impossible de récupérer les réactions car l'ID du canal ne correspond pas à l'ID du message dans l'URL" }, { "id": "api.reaction.save_reaction.mismatched_channel_id.app_error", - "translation": "Failed to save reaction because channel ID does not match post ID in the URL" + "translation": "Impossible de sauvegarder la réaction car l'ID du canal ne correspond pas à l'ID du message dans l'URL" }, { "id": "api.reaction.send_reaction_event.post.app_error", - "translation": "Failed to get post when sending websocket event for reaction" + "translation": "Impossible de récupérer le message lorsqu'un événement de réaction est en cours d'envoi par le websocket" }, { "id": "api.saml.save_certificate.app_error", @@ -1713,7 +1717,7 @@ }, { "id": "api.slackimport.slack_add_bot_user.email_pwd", - "translation": "Importation de l'utilisateur pour le Bot Slack/messages d'intégration : adresse email, mot de passe : {{.Email}}, {{.Password}}\r\n" + "translation": "Importation de l'utilisateur pour le Bot Slack/messages d'intégration : adresse e-mail, mot de passe : {{.Email}}, {{.Password}}\r\n" }, { "id": "api.slackimport.slack_add_bot_user.unable_import", @@ -1741,7 +1745,7 @@ }, { "id": "api.slackimport.slack_add_posts.attach_files.error", - "translation": "Une erreur s'est produite lors en ajoutant les fichiers au message, post_id=%s, file_ids=%v, err=%v" + "translation": "Une erreur s'est produite lors de l'ajout des fichiers au message, post_id=%s, file_ids=%v, err=%v" }, { "id": "api.slackimport.slack_add_posts.bot.warn", @@ -1797,7 +1801,7 @@ }, { "id": "api.slackimport.slack_add_users.email_pwd", - "translation": "Courriel, Mot de passe : {{.Email}}, {{.Password}}\r\n" + "translation": "E-mail, Mot de passe : {{.Email}}, {{.Password}}\r\n" }, { "id": "api.slackimport.slack_add_users.merge_existing", @@ -1805,7 +1809,7 @@ }, { "id": "api.slackimport.slack_add_users.merge_existing_failed", - "translation": "Tried to merge user with existing account: {{.Email}}, {{.Username}}, but failed to add the user to this team.\r\n" + "translation": "Impossible de fusionner l'utilisateur avec le compte existant: {{.Email}}, {{.Username}}, l'utilisateur n'a pas été ajouté à cette équipe.\r\n" }, { "id": "api.slackimport.slack_add_users.unable_import", @@ -1885,7 +1889,7 @@ }, { "id": "api.status.init.debug", - "translation": "Initialisation des routes de l'api des messages" + "translation": "Initialisation des routes de l'API des statuts" }, { "id": "api.status.last_activity.error", @@ -1897,11 +1901,11 @@ }, { "id": "api.team.create_team.email_disabled.app_error", - "translation": "L'inscription d'équipe via adresse électronique est désactivée." + "translation": "L'inscription d'équipe via adresse e-mail est désactivée." }, { "id": "api.team.create_team_from_signup.email_disabled.app_error", - "translation": "L'inscription d'équipe via adresse électronique est désactivée." + "translation": "L'inscription d'équipe via adresse e-mail est désactivée." }, { "id": "api.team.create_team_from_signup.expired_link.app_error", @@ -1917,7 +1921,7 @@ }, { "id": "api.team.email_teams.sending.error", - "translation": "Une erreur est survenue durant l'envoi d'un courriel dans emailTeams err=%v" + "translation": "Une erreur est survenue durant l'envoi d'un e-mail dans emailTeams err=%v" }, { "id": "api.team.get_invite_info.not_open_team", @@ -1949,11 +1953,11 @@ }, { "id": "api.team.import_team.unavailable.app_error", - "translation": "Malformed request: filesize field is not present." + "translation": "Requête malformée : le champ de taille de fichier n'est pas présent." }, { "id": "api.team.init.debug", - "translation": "Initialisation des routes de l'api des équipes" + "translation": "Initialisation des routes de l'API des équipes" }, { "id": "api.team.invite_members.admin", @@ -1981,7 +1985,7 @@ }, { "id": "api.team.invite_members.send.error", - "translation": "Impossible d'envoyer le courriel d'invitation err=%v" + "translation": "Impossible d'envoyer l'e-mail d'invitation err=%v" }, { "id": "api.team.invite_members.sending.info", @@ -1993,7 +1997,7 @@ }, { "id": "api.team.is_team_creation_allowed.domain.app_error", - "translation": "Le courriel doit être rattaché à un domaine spécifique (ex. @exemple.com). Veuillez demander les détails à votre administrateur système." + "translation": "L'adresse e-mail doit être rattachée à un domaine spécifique (ex. @exemple.com). Veuillez demander à votre administrateur système pour plus d'informations." }, { "id": "api.team.permanent_delete_team.attempting.warn", @@ -2009,7 +2013,7 @@ }, { "id": "api.team.signup_team.email_disabled.app_error", - "translation": "L'inscription avec une adresse électronique est désactivée." + "translation": "L'inscription avec une adresse e-mail est désactivée." }, { "id": "api.team.update_member_roles.not_a_member", @@ -2021,31 +2025,31 @@ }, { "id": "api.templates.email_change_body.info", - "translation": "Votre adresse électronique pour {{.TeamDisplayName}} a été remplacée par {{.NewEmail}}.
Si vous n'êtes pas à l'origine de cette action, veuillez contacter votre administrateur système." + "translation": "Votre adresse e-mail pour {{.TeamDisplayName}} a été remplacée par {{.NewEmail}}.
Si vous n'êtes pas à l'origine de cette action, veuillez contacter votre administrateur système." }, { "id": "api.templates.email_change_body.title", - "translation": "Vous avez mis à jour votre adresse électronique." + "translation": "Vous avez mis à jour votre adresse e-mail." }, { "id": "api.templates.email_change_subject", - "translation": "Votre adresse électronique a été modifiée pour {{.TeamDisplayName}}" + "translation": "Votre adresse e-mail a été modifiée pour {{.TeamDisplayName}}" }, { "id": "api.templates.email_change_verify_body.button", - "translation": "Vérifier votre adresse électronique" + "translation": "Vérifier votre adresse e-mail" }, { "id": "api.templates.email_change_verify_body.info", - "translation": "Pour terminer la mise à jour de votre adresse électronique pour {{.TeamDisplayName}}, merci de cliquer sur le lien ci-dessous afin de valider votre adresse." + "translation": "Pour terminer votre changement d'adresse e-mail pour {{.TeamDisplayName}}, veuillez cliquer sur le lien ci-dessous afin de valider votre adresse." }, { "id": "api.templates.email_change_verify_body.title", - "translation": "Vous avez mis à jour votre adresse électronique." + "translation": "Vous avez mis à jour votre adresse e-mail." }, { "id": "api.templates.email_change_verify_subject", - "translation": "Vérifier la nouvelle adresse électronique pour {{.TeamDisplayName}}" + "translation": "Vérifier la nouvelle adresse e-mail pour {{.TeamDisplayName}}" }, { "id": "api.templates.email_footer", @@ -2053,7 +2057,7 @@ }, { "id": "api.templates.email_info", - "translation": "Pour toutes vos questions, contactez-nous par courrriel : {{.SupportEmail}}.
Cordialement,
L'équipe {{.SiteName}}
" + "translation": "Pour toutes questions, contactez-nous par e-mail : {{.SupportEmail}}.
Cordialement,
L'équipe {{.SiteName}}
" }, { "id": "api.templates.email_organization", @@ -2069,11 +2073,11 @@ }, { "id": "api.templates.find_teams_body.found", - "translation": "Votre requête de récupération des équipes associées à votre adresse électronique donne le résultat suivant:" + "translation": "Votre requête de récupération des équipes associées à votre adresse e-mail donne le résultat suivant :" }, { "id": "api.templates.find_teams_body.not_found", - "translation": "Nous n'avons trouvé aucune équipe correspondant à l'adresse électronique donnée." + "translation": "Nous n'avons trouvé aucune équipe correspondant à l'adresse e-mail spécifiée." }, { "id": "api.templates.find_teams_body.title", @@ -2105,23 +2109,23 @@ }, { "id": "api.templates.mfa_activated_body.info", - "translation": "Multi-factor authentication has been added to your account on {{ .SiteURL }}.
If this change wasn't initiated by you, please contact your system administrator." + "translation": "L'authentification multi-facteurs a été ajoutée à votre compte sur {{ .SiteURL }}.
Si vous n'êtes pas à l'origine de ce changement, veuillez contacter votre administrateur système." }, { "id": "api.templates.mfa_activated_body.title", - "translation": "Multi-factor authentication was added" + "translation": "L'authentification multi-facteurs a été activée" }, { "id": "api.templates.mfa_change_subject", - "translation": "Your MFA has been updated on {{ .SiteName }}" + "translation": "Votre authentification multi-facteur a été mise à jour sur {{ .SiteName }}" }, { "id": "api.templates.mfa_deactivated_body.info", - "translation": "Multi-factor authentication has been removed from your account on {{ .SiteURL }}.
If this change wasn't initiated by you, please contact your system administrator." + "translation": "L'authentification multi-facteurs a été supprimée de votre compte sur {{ .SiteURL }}.
Si vous n'êtes pas à l'origine de ce changement, veuillez contacter votre administrateur système." }, { "id": "api.templates.mfa_deactivated_body.title", - "translation": "Multi-factor authentication was removed" + "translation": "L'authentification multi-facteurs a été désactivée" }, { "id": "api.templates.password_change_body.info", @@ -2169,7 +2173,7 @@ }, { "id": "api.templates.signin_change_email.body.method_email", - "translation": "Adresse électronique et mot de passe" + "translation": "Adresse e-mail et mot de passe" }, { "id": "api.templates.signin_change_email.body.title", @@ -2221,11 +2225,11 @@ }, { "id": "api.templates.verify_body.button", - "translation": "Vérifier l'adresse électronique" + "translation": "Vérifier l'adresse e-mail" }, { "id": "api.templates.verify_body.info", - "translation": "Veuillez vérifier votre adresse électronique en cliquant ci-dessous." + "translation": "Veuillez vérifier votre adresse e-mail en cliquant ci-dessous." }, { "id": "api.templates.verify_body.title", @@ -2233,7 +2237,7 @@ }, { "id": "api.templates.verify_subject", - "translation": "Vérification de l'adresse électronique pour [{{ .SiteName }}]" + "translation": "Vérification de l'adresse e-mail pour [{{ .SiteName }}]" }, { "id": "api.templates.welcome_body.app_download_info", @@ -2241,11 +2245,11 @@ }, { "id": "api.templates.welcome_body.button", - "translation": "Vérifier l'adresse électronique" + "translation": "Vérifier l'adresse e-mail" }, { "id": "api.templates.welcome_body.info", - "translation": "Veuillez vérifier votre adresse électronique en cliquant ci-dessous." + "translation": "Veuillez vérifier votre adresse e-mail en cliquant ci-dessous." }, { "id": "api.templates.welcome_body.info2", @@ -2321,7 +2325,7 @@ }, { "id": "api.user.complete_switch_with_oauth.blank_email.app_error", - "translation": "Courriel vide" + "translation": "Adresse e-mail vide" }, { "id": "api.user.complete_switch_with_oauth.parse.app_error", @@ -2333,7 +2337,7 @@ }, { "id": "api.user.create_oauth_user.already_attached.app_error", - "translation": "Il existe déjà un compte associé à cette adresse e-mail utilisant une méthode de connexion autre que {{.Service}}. S'il vous plaît connectez-vous en utilisant {{.Auth}}." + "translation": "Il existe déjà un compte associé à cette adresse e-mail utilisant une méthode de connexion autre que {{.Service}}. Veuillez vous connecter en utilisant {{.Auth}}." }, { "id": "api.user.create_oauth_user.already_used.app_error", @@ -2361,7 +2365,7 @@ }, { "id": "api.user.create_user.accepted_domain.app_error", - "translation": "Votre adresse électronique ne correspond pas à un domaine valide. Veuillez contacter votre administrateur ou enregistrez-vous avec une autre adresse électronique." + "translation": "Votre adresse e-mail ne correspond pas à un domaine valide. Veuillez contacter votre administrateur ou enregistrez-vous avec une autre adresse e-mail." }, { "id": "api.user.create_user.joining.error", @@ -2377,7 +2381,7 @@ }, { "id": "api.user.create_user.signup_email_disabled.app_error", - "translation": "L'inscription avec adresse électronique est désactivée." + "translation": "L'inscription par adresse e-mail est désactivée." }, { "id": "api.user.create_user.signup_link_expired.app_error", @@ -2397,7 +2401,7 @@ }, { "id": "api.user.create_user.verified.error", - "translation": "Impossible de marquer l'adresse électronique comme valide err=%v" + "translation": "Impossible de marquer l'adresse e-mail comme valide err=%v" }, { "id": "api.user.email_to_ldap.not_available.app_error", @@ -2417,7 +2421,7 @@ }, { "id": "api.user.init.debug", - "translation": "Initialisation des routes de l'api utilisateur" + "translation": "Initialisation des routes de l'API utilisateur" }, { "id": "api.user.ldap_to_email.not_available.app_error", @@ -2441,7 +2445,7 @@ }, { "id": "api.user.login.not_provided.app_error", - "translation": "Must provide either user ID, or team name and user email" + "translation": "Un ID utilisateur, ou le nom d'équipe accompagné d'une adresse e-mail doivent être spécifiés." }, { "id": "api.user.login.not_verified.app_error", @@ -2521,19 +2525,19 @@ }, { "id": "api.user.send_email_change_email_and_forget.error", - "translation": "Impossible d'envoyer le courriel de changement d'adresse électronique err=%v" + "translation": "Impossible d'envoyer l'e-mail de notification de changement d'adresse e-mail err=%v" }, { "id": "api.user.send_email_change_username_and_forget.error", - "translation": "Impossible d'envoyer le courriel de changement d'adresse électronique err=%v" + "translation": "Impossible d'envoyer l'e-mail de changement de nom d'utilisateur err=%v" }, { "id": "api.user.send_email_change_verify_email_and_forget.error", - "translation": "Impossible d'envoyer le courriel de changement d'adresse électronique err=%v" + "translation": "Impossible d'envoyer l'e-mail de vérification de changement d'adresse e-mail err=%v" }, { "id": "api.user.send_password_change_email_and_forget.error", - "translation": "Impossible d'envoyer le courriel de mise à jour du mot de passe err=%v" + "translation": "Impossible d'envoyer l'e-mail de mise à jour du mot de passe err=%v" }, { "id": "api.user.send_password_reset.find.app_error", @@ -2541,7 +2545,7 @@ }, { "id": "api.user.send_password_reset.send.app_error", - "translation": "Impossible d'envoyer le courriel de réinitialisation du mot de passe" + "translation": "Impossible d'envoyer l'e-mail de réinitialisation du mot de passe" }, { "id": "api.user.send_password_reset.sso.app_error", @@ -2549,15 +2553,15 @@ }, { "id": "api.user.send_sign_in_change_email_and_forget.error", - "translation": "Impossible d'envoyer le courriel de mise à jour du mot de passe err=%v" + "translation": "Impossible d'envoyer l'e-mail de mise à jour du mot de passe err=%v" }, { "id": "api.user.send_verify_email_and_forget.failed.error", - "translation": "Impossible d'envoyer le courriel de vérification err=%v" + "translation": "Impossible d'envoyer l'e-mail de vérification err=%v" }, { "id": "api.user.send_welcome_email_and_forget.failed.error", - "translation": "Impossible d'envoyer le courriel de bienvenue err=%v" + "translation": "Impossible d'envoyer l'e-mail de bienvenue err=%v" }, { "id": "api.user.update_active.no_deactivate_ldap.app_error", @@ -2677,7 +2681,7 @@ }, { "id": "api.web_socket.init.debug", - "translation": "Initialisation des routes de l'api web socket" + "translation": "Initialisation des routes de l'API web socket" }, { "id": "api.web_socket_handler.log.error", @@ -2709,7 +2713,7 @@ }, { "id": "api.webhook.create_outgoing.permissions.app_error", - "translation": "Droits insuffisants pour supprimer le webhook sortant." + "translation": "Droits insuffisants pour créer le webhook sortant." }, { "id": "api.webhook.create_outgoing.triggers.app_error", @@ -2749,7 +2753,7 @@ }, { "id": "api.webhook.init.debug", - "translation": "Initialisation des routes de l'api webhook" + "translation": "Initialisation des routes de l'API webhook" }, { "id": "api.webhook.regen_outgoing_token.disabled.app_error", @@ -2765,7 +2769,7 @@ }, { "id": "api.webrtc.init.debug", - "translation": "Initialisation des routes de l'api WebRTC" + "translation": "Initialisation des routes de l'API WebRTC" }, { "id": "api.webrtc.register_token.app_error", @@ -2949,11 +2953,11 @@ }, { "id": "ent.metrics.starting.info", - "translation": "Metrics and profiling server is listening on %v" + "translation": "Le serveur de métriques et d'analyses d'exécution écoute sur %v" }, { "id": "ent.metrics.stopping.info", - "translation": "Metrics and profiling server is stopping on %v" + "translation": "Le serveur de métriques et d'analyses d'exécution est en cours d'arrêt sur %v" }, { "id": "ent.mfa.activate.authenticate.app_error", @@ -3077,7 +3081,7 @@ }, { "id": "error.generic.message", - "translation": "Une erreur est survenue." + "translation": "Une erreur s'est produite." }, { "id": "error.generic.title", @@ -3133,7 +3137,7 @@ }, { "id": "manaultesting.manual_test.uid.debug", - "translation": "Pas de uid dans l'url" + "translation": "Pas d'uid dans l'URL" }, { "id": "manaultesting.test_autolink.info", @@ -3161,7 +3165,7 @@ }, { "id": "mattermost.load_license.find.warn", - "translation": "License key from https://mattermost.com required to unlock enterprise features." + "translation": "Un clé de licence de https://mattermost.com est requise pour déverrouiller les fonctionnalités d'entreprises." }, { "id": "mattermost.security_bulletin.error", @@ -3345,7 +3349,7 @@ }, { "id": "model.command.is_valid.team_id.app_error", - "translation": "Id équipe invalide" + "translation": "ID d'équipe invalide" }, { "id": "model.command.is_valid.token.app_error", @@ -3361,7 +3365,7 @@ }, { "id": "model.command.is_valid.url.app_error", - "translation": "Invalid URL" + "translation": "URL non valide" }, { "id": "model.command.is_valid.url_http.app_error", @@ -3397,15 +3401,15 @@ }, { "id": "model.config.is_valid.cluster_email_batching.app_error", - "translation": "Impossible d'activer l'envoi de courriels groupé lorsque le clustering est activé" + "translation": "Impossible d'activer l'envoi d'e-mails groupés lorsque le clustering est activé" }, { "id": "model.config.is_valid.email_batching_buffer_size.app_error", - "translation": "Taille du buffer d'envoi de courriels groupé invalide. Doit être 0 ou un nombre positif." + "translation": "Taille du buffer d'envoi d'e-mails groupés invalide. Doit être 0 ou un nombre positif." }, { "id": "model.config.is_valid.email_batching_interval.app_error", - "translation": "Intervalle d'envoi de courriels groupé invalide pour les réglages de courriels. Doit être égal ou supérieur à 30 secondes." + "translation": "Intervalle d'envoi d'e-mails groupés invalide pour les réglages de courriels. Doit être égal ou supérieur à 30 secondes." }, { "id": "model.config.is_valid.email_reset_salt.app_error", @@ -3533,7 +3537,7 @@ }, { "id": "model.config.is_valid.max_notify_per_channel.app_error", - "translation": "Le nombre maximum de canaux par équipe défini dans les paramètres d'équipe est invalide. Doit être un entier positif." + "translation": "Le nombre maximum de notifications par canal pour les paramètres d'équipe. Doit être un entier positif." }, { "id": "model.config.is_valid.max_users.app_error", @@ -3601,7 +3605,7 @@ }, { "id": "model.config.is_valid.site_url_email_batching.app_error", - "translation": "Impossible d'activer l'envoi de courriels groupé si SiteURL n'est pas défini." + "translation": "Impossible d'activer l'envoi d'e-mails groupés si SiteURL n'est pas défini." }, { "id": "model.config.is_valid.sitename_length.app_error", @@ -3705,7 +3709,7 @@ }, { "id": "model.incoming_hook.team_id.app_error", - "translation": "Id équipe invalide" + "translation": "ID d'équipe invalide" }, { "id": "model.incoming_hook.update_at.app_error", @@ -3757,7 +3761,7 @@ }, { "id": "model.outgoing_hook.is_valid.callback.app_error", - "translation": "Urls de callback invalides" + "translation": "URLs de callback invalides" }, { "id": "model.outgoing_hook.is_valid.channel_id.app_error", @@ -3781,7 +3785,7 @@ }, { "id": "model.outgoing_hook.is_valid.team_id.app_error", - "translation": "Id équipe invalide" + "translation": "ID d'équipe invalide" }, { "id": "model.outgoing_hook.is_valid.token.app_error", @@ -3853,7 +3857,7 @@ }, { "id": "model.post.is_valid.root_parent.app_error", - "translation": "Id racine doit être renseigné si l'id parent est renseigné" + "translation": "L'ID racine invalide doit être spécifié si un ID parent est défini" }, { "id": "model.post.is_valid.type.app_error", @@ -3893,15 +3897,15 @@ }, { "id": "model.reaction.is_valid.emoji_name.app_error", - "translation": "Id d'émoticône invalide" + "translation": "Nom d'émoticône invalide" }, { "id": "model.reaction.is_valid.post_id.app_error", - "translation": "Id racine invalide" + "translation": "ID de message invalide" }, { "id": "model.reaction.is_valid.user_id.app_error", - "translation": "Id utilisateur invalide" + "translation": "ID utilisateur invalide" }, { "id": "model.team.is_valid.characters.app_error", @@ -3925,7 +3929,7 @@ }, { "id": "model.team.is_valid.email.app_error", - "translation": "Courriel invalide" + "translation": "Adresse e-mail invalide" }, { "id": "model.team.is_valid.id.app_error", @@ -3957,7 +3961,7 @@ }, { "id": "model.team_member.is_valid.team_id.app_error", - "translation": "Id équipe invalide" + "translation": "ID d'équipe invalide" }, { "id": "model.team_member.is_valid.user_id.app_error", @@ -3981,7 +3985,7 @@ }, { "id": "model.user.is_valid.email.app_error", - "translation": "Courriel invalide" + "translation": "Adresse e-mail invalide" }, { "id": "model.user.is_valid.first_name.app_error", @@ -4001,7 +4005,7 @@ }, { "id": "model.user.is_valid.position.app_error", - "translation": "Invalid position: must not be longer than 35 characters." + "translation": "Poste invalide : ne doit pas faire plus de 35 caractères." }, { "id": "model.user.is_valid.pwd.app_error", @@ -4069,7 +4073,7 @@ }, { "id": "model.user.is_valid.team_id.app_error", - "translation": "Id équipe invalide" + "translation": "ID d'équipe invalide" }, { "id": "model.user.is_valid.update_at.app_error", @@ -4161,19 +4165,19 @@ }, { "id": "store.sql.open_conn.critical", - "translation": "Échec de l'ouverture de la connexion sql vers err:%v" + "translation": "Impossible d'ouvrir une connexion SQL vers err:%v" }, { "id": "store.sql.open_conn.panic", - "translation": "Échec de l'ouverture de la connexion sql %v" + "translation": "Impossible d'ouvrir une connexion SQL %v" }, { "id": "store.sql.ping.critical", - "translation": "Échec du ping db err:%v" + "translation": "Impossible de pinger base de données err:%v" }, { "id": "store.sql.pinging.info", - "translation": "Ping de la base de données sql %v" + "translation": "Ping de la base de données SQL %v" }, { "id": "store.sql.read_replicas_not_licensed.critical", @@ -4309,7 +4313,7 @@ }, { "id": "store.sql_channel.get_member.missing.app_error", - "translation": "Aucun élément de canal trouvé pour cet id d'utilisateur et cet id de canal" + "translation": "Aucun membre de canal trouvé pour cet ID utilisateur et cet ID de canal" }, { "id": "store.sql_channel.get_member_count.app_error", @@ -4325,7 +4329,7 @@ }, { "id": "store.sql_channel.get_members_by_ids.app_error", - "translation": "Nous n'avons pas pu obtenir les membres du canal" + "translation": "Impossible de récupérer les membres du canal" }, { "id": "store.sql_channel.get_more_channels.get.app_error", @@ -4365,7 +4369,7 @@ }, { "id": "store.sql_channel.save_channel.existing.app_error", - "translation": "L'enregistrement doit être appelé pour un canal existant" + "translation": "La mise à jour doit être appelée pour un canal existant" }, { "id": "store.sql_channel.save_channel.exists.app_error", @@ -4405,7 +4409,7 @@ }, { "id": "store.sql_channel.save_member.exists.app_error", - "translation": "Un membre de canal avec cet id existe déjà" + "translation": "Un membre de canal avec cet ID existe déjà" }, { "id": "store.sql_channel.save_member.open_transaction.app_error", @@ -4417,7 +4421,7 @@ }, { "id": "store.sql_channel.search.app_error", - "translation": "Nous avons rencontré une erreur durant la mise à jour du canal" + "translation": "Nous avons rencontré une erreur durant la recherche des canaux" }, { "id": "store.sql_channel.set_last_viewed_at.app_error", @@ -4785,43 +4789,43 @@ }, { "id": "store.sql_reaction.delete.begin.app_error", - "translation": "Unable to open transaction while deleting reaction" + "translation": "Impossible d'ouvrir une transaction pendant qu'une réaction est en cours de suppression" }, { "id": "store.sql_reaction.delete.commit.app_error", - "translation": "Unable to commit transaction while deleting reaction" + "translation": "Impossible de valider la transaction pendant qu'une réaction est en cours de suppression" }, { "id": "store.sql_reaction.delete.save.app_error", - "translation": "Unable to delete reaction" + "translation": "Impossible de supprimer la réaction" }, { "id": "store.sql_reaction.delete_all_with_emoj_name.delete_reactions.app_error", - "translation": "Unable to delete reactions with the given emoji name" + "translation": "Impossible de supprimer la réaction avec le nom d'émoticône donné" }, { "id": "store.sql_reaction.delete_all_with_emoj_name.get_reactions.app_error", - "translation": "Unable to get reactions with the given emoji name" + "translation": "Impossible de récupérer les réactions avec le nom d'émoticône donné" }, { "id": "store.sql_reaction.delete_all_with_emoji_name.update_post.warn", - "translation": "Unable to update Post.HasReactions while removing reactions post_id=%v, error=%v" + "translation": "Impossible de mettre à jour Post.HasReactions pendant que des réactions sont en cours de suppression post_id=%v, error=%v" }, { "id": "store.sql_reaction.get_for_post.app_error", - "translation": "Unable to get reactions for post" + "translation": "Impossible de récupérer les réactions du message" }, { "id": "store.sql_reaction.save.begin.app_error", - "translation": "Unable to open transaction while saving reaction" + "translation": "Impossible d'ouvrir une transaction pendant qu'une réaction est en cours de sauvegarde" }, { "id": "store.sql_reaction.save.commit.app_error", - "translation": "Unable to commit transaction while saving reaction" + "translation": "Impossible de valider une transaction pendant qu'une réaction est en cours de sauvegarde" }, { "id": "store.sql_reaction.save.save.app_error", - "translation": "Unable to save reaction" + "translation": "Impossible de sauvegarder cette réaction" }, { "id": "store.sql_session.analytics_session_count.app_error", @@ -4973,7 +4977,7 @@ }, { "id": "store.sql_team.get_member.missing.app_error", - "translation": "Aucun membre d'équipe trouvé pour cet id d'utilisateur et cet id d'équipe" + "translation": "Aucun membre d'équipe trouvé pour cet ID utilisateur et cet ID d'équipe" }, { "id": "store.sql_team.get_member_count.app_error", @@ -4993,7 +4997,7 @@ }, { "id": "store.sql_team.get_unread.app_error", - "translation": "We couldn't get the teams unread messages" + "translation": "Impossible de récupérer la liste des messages non lus des équipes" }, { "id": "store.sql_team.permanent_delete.app_error", @@ -5017,7 +5021,7 @@ }, { "id": "store.sql_team.save_member.exists.app_error", - "translation": "Un membre de l'équipe avec cet id existe déjà" + "translation": "Un membre d'équipe existe déjà avec cet ID" }, { "id": "store.sql_team.save_member.save.app_error", @@ -5105,7 +5109,7 @@ }, { "id": "store.sql_user.missing_account.const", - "translation": "Nous n'avons pas pu trouver un compte existant correspondant à votre courriel pour cette équipe. Cette équipe nécessite peut-être une invitation de la part du propriétaire pour pouvoir la rejoindre." + "translation": "Nous n'avons pas pu trouver un compte existant correspondant à l'adresse e-mail pour cette équipe. Cette équipe nécessite peut-être une invitation de la part du propriétaire pour pouvoir la rejoindre." }, { "id": "store.sql_user.permanent_delete.app_error", @@ -5129,7 +5133,7 @@ }, { "id": "store.sql_user.save.existing.app_error", - "translation": "La mise à jour doit être appelée pour un utilisateur existant." + "translation": "La mise à jour doit être appelée pour un utilisateur existant" }, { "id": "store.sql_user.save.max_accounts.app_error", @@ -5377,11 +5381,11 @@ }, { "id": "utils.mail.send_mail.msg_data.app_error", - "translation": "Échec de l'ajout des données du courriel" + "translation": "Impossible d'ajouter les données du message à l'e-mail" }, { "id": "utils.mail.send_mail.sending.debug", - "translation": "envoi du courriel vers %v avec comme sujet '%v'" + "translation": "Envoi de l'e-mail à %v avec comme sujet '%v'" }, { "id": "utils.mail.send_mail.to_address.app_error", @@ -5405,7 +5409,7 @@ }, { "id": "web.check_browser_compatibility.app_error", - "translation": "Votre navigateur courant n'est pas supporté, veuillez vous mettre à jour vers l'un des navigateurs suivants : Google Chrome 21 ou plus, Internet Explorer 11 ou plus, Firefox 14 ou plus, Safari 9 ou plus" + "translation": "Votre navigateur actuel n'est pas supporté, veuillez vous mettre à niveau vers l'un des navigateurs suivants : Google Chrome 21 ou supérieur, Internet Explorer 11 ou supérieur, Firefox 14 ou supérieur, Safari 9 ou supérieur" }, { "id": "web.claim_account.team.error", @@ -5449,7 +5453,7 @@ }, { "id": "web.incoming_webhook.attachment.app_error", - "translation": "Maximum attachments length is {{.Max}} characters, received size is {{.Actual}}" + "translation": "La longueur maximale des pièces jointes est de {{.Max}} caractères, la taille reçue est de {{.Actual}}" }, { "id": "web.incoming_webhook.channel.app_error", @@ -5477,7 +5481,7 @@ }, { "id": "web.incoming_webhook.text.length.app_error", - "translation": "Maximum text length is {{.Max}} characters, received size is {{.Actual}}" + "translation": "La longueur maximale du texte est de {{.Max}} caractères, la taille reçue est de {{.Actual}}" }, { "id": "web.incoming_webhook.user.app_error", @@ -5545,7 +5549,7 @@ }, { "id": "web.signup_team_confirm.title", - "translation": "Courriel d'inscription envoyé" + "translation": "E-mail d'inscription envoyé" }, { "id": "web.signup_user_complete.link_expired.app_error", diff --git a/i18n/ja.json b/i18n/ja.json index 41f45ca08a..8dee0b47d0 100644 --- a/i18n/ja.json +++ b/i18n/ja.json @@ -1173,6 +1173,10 @@ "id": "api.general.init.debug", "translation": "全般APIルートを初期化しています" }, + { + "id": "api.import.import_post.attach_files.error", + "translation": "投稿へのファイル添付エラー。 postId=%v, fileIds=%v, message=%v" + }, { "id": "api.import.import_post.saving.debug", "translation": "投稿の保存エラー user=%v, message=%v" diff --git a/i18n/ko.json b/i18n/ko.json index 54e98e8458..26d164a5ac 100644 --- a/i18n/ko.json +++ b/i18n/ko.json @@ -1173,6 +1173,10 @@ "id": "api.general.init.debug", "translation": "일반 API 경로 초기화 중" }, + { + "id": "api.import.import_post.attach_files.error", + "translation": "Error attaching files to post. postId=%v, fileIds=%v, message=%v" + }, { "id": "api.import.import_post.saving.debug", "translation": "글 저장 오류. 사용자=%v, 메시지=%v" diff --git a/i18n/nl.json b/i18n/nl.json index 7efc9c4913..f6193aee89 100644 --- a/i18n/nl.json +++ b/i18n/nl.json @@ -73,7 +73,7 @@ }, { "id": "api.admin.init.debug", - "translation": "Initialisatie van de admin-api-routes" + "translation": "Initialisatie van de admin API routes" }, { "id": "api.admin.recycle_db_end.warn", @@ -197,7 +197,7 @@ }, { "id": "api.channel.create_channel.direct_channel.app_error", - "translation": "U moet de api-service createDirectChallel gebruiken voor het creëren van een direct kanaal" + "translation": "U moet de 'createDirectChannel' API service gebruiken om een direct kanaal aan te maken" }, { "id": "api.channel.create_channel.invalid_character.app_error", @@ -205,7 +205,7 @@ }, { "id": "api.channel.create_channel.max_channel_limit.app_error", - "translation": "Cannot create more than {{.MaxChannelsPerTeam}} channels for current team" + "translation": "Kan niet meer dan {{.MaxChannelsPerTeam}} kanalen aanmaken voor het huidige team" }, { "id": "api.channel.create_default_channels.off_topic", @@ -273,7 +273,7 @@ }, { "id": "api.channel.init.debug", - "translation": "Initialisatie van de kanaal-api-routes" + "translation": "Initialisatie van de kanaal API routes" }, { "id": "api.channel.join_channel.permissions.app_error", @@ -301,7 +301,7 @@ }, { "id": "api.channel.post_update_channel_displayname_message_and_forget.create_post.error", - "translation": "Failed to post displayname update message %v" + "translation": "Fout bij het weergeven van het bericht over de bijgewerkte weergavenaam %v" }, { "id": "api.channel.post_update_channel_displayname_message_and_forget.retrieve_user.error", @@ -309,7 +309,7 @@ }, { "id": "api.channel.post_update_channel_displayname_message_and_forget.updated_from", - "translation": "%s heeft de kanaalkoptekst veranderd van \"%s\" naar \"%s\"" + "translation": "%s heeft de kanaalkoptekst veranderd van: %s naar: %s" }, { "id": "api.channel.post_update_channel_header_message_and_forget.join_leave.error", @@ -421,7 +421,7 @@ }, { "id": "api.command.init.debug", - "translation": "Initialisatie van de opdracht api routes" + "translation": "Initialisatie van de opdracht API routes" }, { "id": "api.command.invite_people.desc", @@ -457,7 +457,7 @@ }, { "id": "api.command.team_mismatch.app_error", - "translation": "Cannot update commands across teams" + "translation": "Fout bij het bijwerken van commando's voor meerdere teams" }, { "id": "api.command.update.app_error", @@ -485,7 +485,7 @@ }, { "id": "api.command_collapse.success", - "translation": "Image links now collapse by default" + "translation": "Afbeelding links klappen nu standaard in" }, { "id": "api.command_echo.create.app_error", @@ -509,7 +509,7 @@ }, { "id": "api.command_echo.message.app_error", - "translation": "A message must be provided with the /echo command." + "translation": "Een bericht moet worden opgegeven met het /echo commando." }, { "id": "api.command_echo.name", @@ -525,7 +525,7 @@ }, { "id": "api.command_expand.success", - "translation": "Image links now expand by default" + "translation": "Afbeelding links klappen nu standaard uit" }, { "id": "api.command_expand_collapse.fail.app_error", @@ -593,7 +593,7 @@ }, { "id": "api.command_msg.fail.app_error", - "translation": "Er is een foute upgetreden tijdens het sturen van een bericht naar de gebruiker." + "translation": "Er is een fout opgetreden tijdens het sturen van een bericht naar de gebruiker." }, { "id": "api.command_msg.hint", @@ -641,11 +641,11 @@ }, { "id": "api.command_shortcuts.browser.channel_next", - "translation": "{{.ChannelNextCmd}}: Next channel in your history\n" + "translation": "{{.ChannelNextCmd}}: Volgende kanaal uit je geschiedenis\n" }, { "id": "api.command_shortcuts.browser.channel_next.cmd", - "translation": "ALT+RIGHT" + "translation": "ALT+RECHTS" }, { "id": "api.command_shortcuts.browser.channel_next.cmd_mac", @@ -653,11 +653,11 @@ }, { "id": "api.command_shortcuts.browser.channel_prev", - "translation": "{{.ChannelPrevCmd}}: Previous channel in your history\n" + "translation": "{{.ChannelPrevCmd}}: Vorige kanaal in je geschiedenis\n" }, { "id": "api.command_shortcuts.browser.channel_prev.cmd", - "translation": "ALT+LEFT" + "translation": "ALT+LINKS" }, { "id": "api.command_shortcuts.browser.channel_prev.cmd_mac", @@ -701,7 +701,7 @@ }, { "id": "api.command_shortcuts.files.header", - "translation": "#### Files\n\n" + "translation": "#### Bestanden\n\n" }, { "id": "api.command_shortcuts.files.upload", @@ -729,7 +729,7 @@ }, { "id": "api.command_shortcuts.msgs.header", - "translation": "#### Messages\n\n" + "translation": "#### Berichten\n\n" }, { "id": "api.command_shortcuts.msgs.mark_as_read", @@ -753,19 +753,19 @@ }, { "id": "api.command_shortcuts.nav.next", - "translation": "ALT+DOWN: Next channel or direct message in left hand sidebar\n" + "translation": "ALT+OMLAAG: Volgende kanaal of direct bericht in linker zijbalk\n" }, { "id": "api.command_shortcuts.nav.prev", - "translation": "ALT+UP: Previous channel or direct message in left hand sidebar\n" + "translation": "ALT+OMHOOG: Vorige kanaal of direct bericht in linker zijbalk\n" }, { "id": "api.command_shortcuts.nav.recent_mentions", - "translation": "{{.CmdOrCtrl}}+SHIFT+M: Open recent mentions\n\n" + "translation": "{{.CmdOrCtrl}}+SHIFT+M: Open recente vermeldingen\n\n" }, { "id": "api.command_shortcuts.nav.settings", - "translation": "{{.CmdOrCtrl}}+SHIFT+A: Open account settings\n" + "translation": "{{.CmdOrCtrl}}+SHIFT+A: Open account instellingen\n" }, { "id": "api.command_shortcuts.nav.switcher", @@ -927,7 +927,7 @@ }, { "id": "api.emoji.create.too_large.app_error", - "translation": "Kon emoji niet aanmaken. Afbeelding moet minstens 64 KB groot zijn." + "translation": "Kon emoji niet aanmaken. Afbeelding moet minstens 1MB groot zijn." }, { "id": "api.emoji.delete.delete_reactions.app_error", @@ -951,7 +951,7 @@ }, { "id": "api.emoji.init.debug", - "translation": "Initialiseer emoji api routes" + "translation": "Initialiseer emoji API routes" }, { "id": "api.emoji.storage.app_error", @@ -1039,7 +1039,7 @@ }, { "id": "api.file.init.debug", - "translation": "Initialisatie bestand api routes" + "translation": "Initialisatie bestand API routes" }, { "id": "api.file.migrate_filenames_to_file_infos.channel.app_error", @@ -1059,11 +1059,11 @@ }, { "id": "api.file.migrate_filenames_to_file_infos.info.app_error", - "translation": "Niet mogelijk om bestand te vinden wanneer een bericht gemigreerd word met FileInfos, post_id=%v, filename=%v, path=%v, err=%v" + "translation": "Niet mogelijk om bestand te vinden wanneer een bericht gemigreerd word met FileInfos, post_id=%v, filename=%v, err=%v" }, { "id": "api.file.migrate_filenames_to_file_infos.migrating_post.debug", - "translation": "Migrating post to use FileInfos, post_id=%v, err=%v" + "translation": "Migreren van bericht naar FileInfos, post_id=%v, err=%v" }, { "id": "api.file.migrate_filenames_to_file_infos.mismatched_filename.warn", @@ -1173,6 +1173,10 @@ "id": "api.general.init.debug", "translation": "Initialisatie van algemene api routes" }, + { + "id": "api.import.import_post.attach_files.error", + "translation": "Error attaching files to post. postId=%v, fileIds=%v, message=%v" + }, { "id": "api.import.import_post.saving.debug", "translation": "Fout bij het opslaan van bericht. user=%v, bericht=%v" @@ -1231,7 +1235,7 @@ }, { "id": "api.license.init.debug", - "translation": "Initialisatie van licentie api routes" + "translation": "Initialisatie van licentie API routes" }, { "id": "api.license.remove_license.remove.app_error", @@ -1383,7 +1387,7 @@ }, { "id": "api.post.create_post.attach_files.error", - "translation": "Encountered error attaching files to post, post_id=%s, user_id=%s, file_ids=%v, err=%v" + "translation": "Een fout trad op bij het bijvoegen van de bestanden bij bericht, post_id=%s, user_id=%s, file_ids=%v, err=%v" }, { "id": "api.post.create_post.bad_filename.error", @@ -1423,7 +1427,7 @@ }, { "id": "api.post.delete_post_files.app_error.warn", - "translation": "Encountered error when deleting files for post, post_id=%v, err=%v" + "translation": "Er gebeurde een fout bij het verwijderen van de bestanden van het bericht, post_id=%v, err=%v" }, { "id": "api.post.disabled_all", @@ -1446,7 +1450,7 @@ }, { "id": "api.post.get_message_for_notification.get_files.error", - "translation": "Encountered error when getting files for notification message, post_id=%v, err=%v" + "translation": "Een fout trad op bij het ophalen van de bestanden voor het notificatiebericht, post_id=%v, err=%v" }, { "id": "api.post.get_message_for_notification.images_sent", @@ -1497,7 +1501,7 @@ }, { "id": "api.post.init.debug", - "translation": "Initialisatie van de berichten api" + "translation": "Initialisatie van de berichten API routes" }, { "id": "api.post.make_direct_channel_visible.get_2_members.error", @@ -1533,7 +1537,7 @@ }, { "id": "api.post.send_notifications_and_forget.files.error", - "translation": "Failed to get files for post notification post_id=%v, err=%v" + "translation": "Bestanden voor de berichtmelding post_id=%v, err=%v konden niet worden opgehaald " }, { "id": "api.post.send_notifications_and_forget.get_teams.error", @@ -1629,7 +1633,7 @@ }, { "id": "api.preference.init.debug", - "translation": "Initialisatie van de voorkeurs api" + "translation": "Initialisatie van de voorkeurs API routes" }, { "id": "api.preference.save_preferences.decode.app_error", @@ -1649,7 +1653,7 @@ }, { "id": "api.reaction.init.debug", - "translation": "Initialisatie van de admin-api-routes" + "translation": "Initialisatie van de reactie API routes" }, { "id": "api.reaction.list_reactions.mismatched_channel_id.app_error", @@ -1685,11 +1689,11 @@ }, { "id": "api.server.start_server.rate_limiting_memory_store", - "translation": "Unable to initialize rate limiting memory store. Check MemoryStoreSize config setting." + "translation": "Kon de geheugenopslag limitatie niet laden. Controleer uw MemoryStoreSize configuratie instellingen. " }, { "id": "api.server.start_server.rate_limiting_rate_limiter", - "translation": "Unable to initialize rate limiting." + "translation": "Kan de snelheidsregeling niet laden" }, { "id": "api.server.start_server.starting.critical", @@ -1733,7 +1737,7 @@ }, { "id": "api.slackimport.slack_add_channels.import_failed.warn", - "translation": "Slack Importer: Failed to import channel: %s" + "translation": "Slack importeerder: Kon het kanaal niet inladen: %s" }, { "id": "api.slackimport.slack_add_channels.merge", @@ -1741,7 +1745,7 @@ }, { "id": "api.slackimport.slack_add_posts.attach_files.error", - "translation": "Encountered error attaching files to post, post_id=%s, file_ids=%v, err=%v" + "translation": "Een error trad op bij het attachen van de bestanden bij post, post_id=%s, file_ids=%v, err=%v" }, { "id": "api.slackimport.slack_add_posts.bot.warn", @@ -1749,11 +1753,11 @@ }, { "id": "api.slackimport.slack_add_posts.bot_user_no_exists.warn", - "translation": "Slack Importer: Not importing bot message as the bot-importing user does not exist." + "translation": "Slack Importeerder: Bot berichten worden niet ingeladen aangezien de bot-importerende gebruiker niet bestaat. " }, { "id": "api.slackimport.slack_add_posts.msg_no_comment.debug", - "translation": "File comment undefined" + "translation": "Bestandsomschrijving werd niet opgegeven" }, { "id": "api.slackimport.slack_add_posts.msg_no_usr.debug", diff --git a/i18n/pt-BR.json b/i18n/pt-BR.json index 4946d58fc5..7c222e9789 100644 --- a/i18n/pt-BR.json +++ b/i18n/pt-BR.json @@ -1173,6 +1173,10 @@ "id": "api.general.init.debug", "translation": "Inicializando as rotas de API general" }, + { + "id": "api.import.import_post.attach_files.error", + "translation": "Error ao anexar arquivos para postar. postId=%v, fileIds=%v, message=%v" + }, { "id": "api.import.import_post.saving.debug", "translation": "Erro ao salvar o post. usuário=%v, mensagem=%v" diff --git a/i18n/ru.json b/i18n/ru.json index e9a72525a7..4a8a74b2c3 100644 --- a/i18n/ru.json +++ b/i18n/ru.json @@ -73,7 +73,7 @@ }, { "id": "api.admin.init.debug", - "translation": "Инициализация административных маршрутов api" + "translation": "Инициализация административных маршрутов API" }, { "id": "api.admin.recycle_db_end.warn", @@ -197,7 +197,7 @@ }, { "id": "api.channel.create_channel.direct_channel.app_error", - "translation": "Нужно использовать createDirectChannel сервис API для создания канала личных сообщений" + "translation": "Нужно использовать createDirectChannel из API для создания канала личных сообщений" }, { "id": "api.channel.create_channel.invalid_character.app_error", @@ -217,7 +217,7 @@ }, { "id": "api.channel.create_direct_channel.invalid_user.app_error", - "translation": "Недопустимый идентификатор другого пользователя " + "translation": "Неверный идентификатор другого пользователя " }, { "id": "api.channel.delete_channel.archived", @@ -273,7 +273,7 @@ }, { "id": "api.channel.init.debug", - "translation": "Инициализация канала маршрутов api" + "translation": "Инициализация API каналов" }, { "id": "api.channel.join_channel.permissions.app_error", @@ -381,7 +381,7 @@ }, { "id": "api.command.delete.app_error", - "translation": "Несоответствующие права для команды удаления" + "translation": "Отсутствуют права на команду удаления" }, { "id": "api.command.disabled.app_error", @@ -421,7 +421,7 @@ }, { "id": "api.command.init.debug", - "translation": "Инициализация маршрутов api комманд" + "translation": "Инициализация API команд" }, { "id": "api.command.invite_people.desc", @@ -485,7 +485,7 @@ }, { "id": "api.command_collapse.success", - "translation": "Image links now collapse by default" + "translation": "Теперь ссылки на изображения сокращаются" }, { "id": "api.command_echo.create.app_error", @@ -509,7 +509,7 @@ }, { "id": "api.command_echo.message.app_error", - "translation": "A message must be provided with the /echo command." + "translation": "Перед сообщение должна быть команда /echo." }, { "id": "api.command_echo.name", @@ -525,11 +525,11 @@ }, { "id": "api.command_expand.success", - "translation": "Image links now expand by default" + "translation": "Теперь ссылки на изображения показываются полностью" }, { "id": "api.command_expand_collapse.fail.app_error", - "translation": "Произошла ошибка при расширении предварительного просмотра" + "translation": "Произошла ошибка при открытии превью" }, { "id": "api.command_join.desc", @@ -589,11 +589,11 @@ }, { "id": "api.command_msg.dm_fail.app_error", - "translation": "При создании персонального сообщения произошла ошибка." + "translation": "При создании канала личных сообщений произошла ошибка." }, { "id": "api.command_msg.fail.app_error", - "translation": "Ошибка при передачи сообщения пользователю." + "translation": "Произошла ошибка при передаче сообщения пользователю." }, { "id": "api.command_msg.hint", @@ -601,7 +601,7 @@ }, { "id": "api.command_msg.list.app_error", - "translation": "При перечислении пользователей произошла ошибка." + "translation": "Произошла ошибка при перечислении пользователей." }, { "id": "api.command_msg.missing.app_error", @@ -641,11 +641,11 @@ }, { "id": "api.command_shortcuts.browser.channel_next", - "translation": "{{.ChannelNextCmd}}: Next channel in your history\n" + "translation": "{{.ChannelNextCmd}}: Следующий канал в вашей истории\n" }, { "id": "api.command_shortcuts.browser.channel_next.cmd", - "translation": "ALT+RIGHT" + "translation": "ALT+ВПРАВО" }, { "id": "api.command_shortcuts.browser.channel_next.cmd_mac", @@ -653,11 +653,11 @@ }, { "id": "api.command_shortcuts.browser.channel_prev", - "translation": "{{.ChannelPrevCmd}}: Previous channel in your history\n" + "translation": "{{.ChannelPrevCmd}}: Предыдущий канал в вашей истории\n" }, { "id": "api.command_shortcuts.browser.channel_prev.cmd", - "translation": "ALT+LEFT" + "translation": "ALT+ВЛЕВО" }, { "id": "api.command_shortcuts.browser.channel_prev.cmd_mac", @@ -665,27 +665,27 @@ }, { "id": "api.command_shortcuts.browser.font_decrease", - "translation": "{{.CmdOrCtrl}}+MINUS: Decrease font size (zoom out)\n" + "translation": "{{.CmdOrCtrl}}+МИНУС: Уменьшить размер шрифта (отдалить)\n" }, { "id": "api.command_shortcuts.browser.font_increase", - "translation": "{{.CmdOrCtrl}}+PLUS: Increase font size (zoom in)\n" + "translation": "{{.CmdOrCtrl}}+ПЛЮС: Увеличить размер шрифта (приблизить)\n" }, { "id": "api.command_shortcuts.browser.header", - "translation": "#### Built-in Browser Commands\n\n" + "translation": "#### Встроенные команды\n\n" }, { "id": "api.command_shortcuts.browser.highlight_next", - "translation": "SHIFT+DOWN (in input field): Highlight text to the next line\n" + "translation": "SHIFT+ВНИЗ (в поле ввода): Выделить текст до следующей строки\n" }, { "id": "api.command_shortcuts.browser.highlight_prev", - "translation": "SHIFT+UP (in input field): Highlight text to the previous line\n" + "translation": "SHIFT+ВВЕРХ (в поле ввода): Выделить текст до предыдущей строки\n" }, { "id": "api.command_shortcuts.browser.newline", - "translation": "SHIFT+ENTER (in input field): Create a new line\n" + "translation": "SHIFT+ВВОД (в поле ввода): Создать новую строку\n" }, { "id": "api.command_shortcuts.cmd", @@ -705,7 +705,7 @@ }, { "id": "api.command_shortcuts.files.upload", - "translation": "{{.CmdOrCtrl}}+U: Upload file(s)\n\n" + "translation": "{{.CmdOrCtrl}}+U: Загрузить файл(ы)\n\n" }, { "id": "api.command_shortcuts.header", @@ -713,19 +713,19 @@ }, { "id": "api.command_shortcuts.msgs.comp_channel", - "translation": "~[character]+TAB: Autocomplete channel beginning with [character]\n" + "translation": "~[character]+TAB: Автодополнение названия канала, начинающегося с символа [character]\n" }, { "id": "api.command_shortcuts.msgs.comp_emoji", - "translation": ":[character]+TAB: Autocomplete emoji beginning with [character]\n\n" + "translation": ":[character]+TAB: Автодополнение эмодзи, начинающегося с символа [character]\n\n" }, { "id": "api.command_shortcuts.msgs.comp_username", - "translation": "@[character]+TAB: Autocomplete @username beginning with [character]\n" + "translation": "@[character]+TAB: Автодополнение @имени пользователя, начинающегося с символа [character]\n" }, { "id": "api.command_shortcuts.msgs.edit", - "translation": "UP (in empty input field): Edit your last message in the current channel\n" + "translation": "ВВЕРХ (в пустом поле ввода): Редактировать ваше последнее сообщение в этом канале\n" }, { "id": "api.command_shortcuts.msgs.header", @@ -733,15 +733,15 @@ }, { "id": "api.command_shortcuts.msgs.mark_as_read", - "translation": "ESC: Mark all messages in the current channel as read\n" + "translation": "ESC: Пометить все сообщения в текущем канале как прочитанные\n" }, { "id": "api.command_shortcuts.msgs.reprint_next", - "translation": "{{.CmdOrCtrl}}+DOWN (in empty input field): Reprint the next message or slash command you entered\n" + "translation": "{{.CmdOrCtrl}}+ВНИЗ (в пустом поле ввода): Ввести следующее сообщение или команду\n" }, { "id": "api.command_shortcuts.msgs.reprint_prev", - "translation": "{{.CmdOrCtrl}}+UP (in empty input field): Reprint the previous message or slash command you entered\n" + "translation": "{{.CmdOrCtrl}}+ВВЕРХ (в пустом поле ввода): Ввести предыдущее сообщение или команду\n" }, { "id": "api.command_shortcuts.name", @@ -753,31 +753,31 @@ }, { "id": "api.command_shortcuts.nav.next", - "translation": "ALT+DOWN: Next channel or direct message in left hand sidebar\n" + "translation": "ALT+ВНИЗ: Следующий канал или диалог в левом боковом меню\n" }, { "id": "api.command_shortcuts.nav.prev", - "translation": "ALT+UP: Previous channel or direct message in left hand sidebar\n" + "translation": "ALT+ВВЕРХ: Предыдущий канал или диалог в левом боковом меню\n" }, { "id": "api.command_shortcuts.nav.recent_mentions", - "translation": "{{.CmdOrCtrl}}+SHIFT+M: Open recent mentions\n\n" + "translation": "{{.CmdOrCtrl}}+SHIFT+M: Открыть недавние упоминания\n\n" }, { "id": "api.command_shortcuts.nav.settings", - "translation": "{{.CmdOrCtrl}}+SHIFT+A: Open account settings\n" + "translation": "{{.CmdOrCtrl}}+SHIFT+A: Открыть настройки аккаунта\n" }, { "id": "api.command_shortcuts.nav.switcher", - "translation": "{{.CmdOrCtrl}}+K: Open a quick channel switcher dialog\n" + "translation": "{{.CmdOrCtrl}}+K: Открыть диалог переключения между каналами\n" }, { "id": "api.command_shortcuts.nav.unread_next", - "translation": "ALT+SHIFT+DOWN: Next channel or direct message in left hand sidebar with unread messages\n" + "translation": "ALT+SHIFT+ВВЕРХ: Следующий канал или диалог в левом боковом меню с непрочитанными сообщениями\n" }, { "id": "api.command_shortcuts.nav.unread_prev", - "translation": "ALT+SHIFT+UP: Previous channel or direct message in left hand sidebar with unread messages\n" + "translation": "ALT+SHIFT+ВВЕРХ: Предыдущий канал или диалог в левом боковом меню с непрочитанными сообщениями\n" }, { "id": "api.command_shrug.desc", @@ -801,7 +801,7 @@ }, { "id": "api.context.invalid_team_url.debug", - "translation": "URL сайта команды доступен, но не действителен. URL сайта команды не должны использоваться в функциях API." + "translation": "Адрес команды доступен, но не корректен. Он не должен использоваться в API или в тех функциях, что независимы от неё." }, { "id": "api.context.invalid_token.error", @@ -923,7 +923,7 @@ }, { "id": "api.emoji.create.permissions.app_error", - "translation": "Несоответствующие права для создания смайлика." + "translation": "Отсутствуют права на создание эмодзи." }, { "id": "api.emoji.create.too_large.app_error", @@ -931,11 +931,11 @@ }, { "id": "api.emoji.delete.delete_reactions.app_error", - "translation": "Unable to delete reactions when deleting emoji with emoji name %v" + "translation": "Не удалось удалить реакции при удалении эмодзи с именем %v" }, { "id": "api.emoji.delete.permissions.app_error", - "translation": "Несоответствующие права для удаления смайлика." + "translation": "Отсутствуют права на удаление эмодзи." }, { "id": "api.emoji.disabled.app_error", @@ -951,7 +951,7 @@ }, { "id": "api.emoji.init.debug", - "translation": "Инициализация маршрутов api смайликов" + "translation": "Инициализация API эмодзи" }, { "id": "api.emoji.storage.app_error", @@ -1039,7 +1039,7 @@ }, { "id": "api.file.init.debug", - "translation": "Инициализация маршрутов файлового api" + "translation": "Инициализация API файлов" }, { "id": "api.file.migrate_filenames_to_file_infos.channel.app_error", @@ -1171,7 +1171,11 @@ }, { "id": "api.general.init.debug", - "translation": "Инициализация основных маршрутов api" + "translation": "Инициализация API основных маршрутов" + }, + { + "id": "api.import.import_post.attach_files.error", + "translation": "Ошибка добавления вложения к сообщению. postId=%v, fileIds=%v, message=%v" }, { "id": "api.import.import_post.saving.debug", @@ -1343,7 +1347,7 @@ }, { "id": "api.oauth.regenerate_secret.app_error", - "translation": "Несоответствующие права для восстановления секрета приложения OAuth2" + "translation": "Несоответствующие права для создания новой секретной строки приложения OAuth2" }, { "id": "api.oauth.register_oauth_app.turn_off.app_error", @@ -1629,7 +1633,7 @@ }, { "id": "api.preference.init.debug", - "translation": "Инициализация API" + "translation": "Инициализация API настроек" }, { "id": "api.preference.save_preferences.decode.app_error", @@ -1645,23 +1649,23 @@ }, { "id": "api.reaction.delete_reaction.mismatched_channel_id.app_error", - "translation": "Failed to delete reaction because channel ID does not match post ID in the URL" + "translation": "Не удалось удалить реакцию, так как в адресе идентификатор канала не совпал с идентификатором сообщения" }, { "id": "api.reaction.init.debug", - "translation": "Инициализация административных маршрутов api" + "translation": "Инициализация API реакций" }, { "id": "api.reaction.list_reactions.mismatched_channel_id.app_error", - "translation": "Failed to get reactions because channel ID does not match post ID in the URL" + "translation": "Не удалось получить реакции, так как в адресе идентификатор канала не совпал с идентификатором сообщения" }, { "id": "api.reaction.save_reaction.mismatched_channel_id.app_error", - "translation": "Failed to save reaction because channel ID does not match post ID in the URL" + "translation": "Не удалось сохранить реакцию, так как в адресе идентификатор канала не совпал с идентификатором сообщения" }, { "id": "api.reaction.send_reaction_event.post.app_error", - "translation": "Failed to get post when sending websocket event for reaction" + "translation": "Не удалось получить сообщение при отправке websocket-события реакции" }, { "id": "api.saml.save_certificate.app_error", @@ -1805,7 +1809,7 @@ }, { "id": "api.slackimport.slack_add_users.merge_existing_failed", - "translation": "Tried to merge user with existing account: {{.Email}}, {{.Username}}, but failed to add the user to this team.\r\n" + "translation": "При слиянии с существующим аккаунтом: {{.Email}}, {{.Username}}, возникла ошибка добавления пользователя в команду.\r\n" }, { "id": "api.slackimport.slack_add_users.unable_import", @@ -1885,7 +1889,7 @@ }, { "id": "api.status.init.debug", - "translation": "Инициализация API" + "translation": "Инициализация API статусов" }, { "id": "api.status.last_activity.error", @@ -1949,11 +1953,11 @@ }, { "id": "api.team.import_team.unavailable.app_error", - "translation": "Malformed request: filesize field is not present." + "translation": "Неправильный запрос: отсутствует поле \"filesize\"." }, { "id": "api.team.init.debug", - "translation": "Инициализация API" + "translation": "Инициализация API команд" }, { "id": "api.team.invite_members.admin", @@ -2105,23 +2109,23 @@ }, { "id": "api.templates.mfa_activated_body.info", - "translation": "Multi-factor authentication has been added to your account on {{ .SiteURL }}.
If this change wasn't initiated by you, please contact your system administrator." + "translation": "Многофакторная проверка подлинности была активирована для вашего аккаунта на {{ .SiteURL }}.
Если данное изменение сделано не вами, пожалуйста, обратитесь к администратору системы." }, { "id": "api.templates.mfa_activated_body.title", - "translation": "Multi-factor authentication was added" + "translation": "Многофакторная проверка подлинности активирована" }, { "id": "api.templates.mfa_change_subject", - "translation": "Your MFA has been updated on {{ .SiteName }}" + "translation": "Ваша МПП обновлена на {{ .SiteName }}" }, { "id": "api.templates.mfa_deactivated_body.info", - "translation": "Multi-factor authentication has been removed from your account on {{ .SiteURL }}.
If this change wasn't initiated by you, please contact your system administrator." + "translation": "Многофакторная проверка подлинности отключена для вашего аккаунта на {{ .SiteURL }}.
Если данное изменение сделано не вами, пожалуйста, обратитесь к администратору системы." }, { "id": "api.templates.mfa_deactivated_body.title", - "translation": "Multi-factor authentication was removed" + "translation": "Многофакторная проверка подлинности отключена" }, { "id": "api.templates.password_change_body.info", @@ -2441,7 +2445,7 @@ }, { "id": "api.user.login.not_provided.app_error", - "translation": "Must provide either user ID, or team name and user email" + "translation": "Необходимо указать либо идентификатор пользователя, либо имя команды и электронную почту пользователя" }, { "id": "api.user.login.not_verified.app_error", @@ -2677,7 +2681,7 @@ }, { "id": "api.web_socket.init.debug", - "translation": "Инициализация API сокетов" + "translation": "Инициализация API веб-сокетов" }, { "id": "api.web_socket_handler.log.error", @@ -2749,7 +2753,7 @@ }, { "id": "api.webhook.init.debug", - "translation": "Инициализация API webhook" + "translation": "Инициализация API вебхуков" }, { "id": "api.webhook.regen_outgoing_token.disabled.app_error", @@ -2757,7 +2761,7 @@ }, { "id": "api.webhook.regen_outgoing_token.permissions.app_error", - "translation": "Несоответствующие права для генерации нового токена для исходящего вебхука" + "translation": "Несоответствующие права для генерации нового токена исходящего вебхука" }, { "id": "api.webrtc.disabled.app_error", @@ -2765,7 +2769,7 @@ }, { "id": "api.webrtc.init.debug", - "translation": "Инициализация API WebRTC" + "translation": "Инициализация WebRTC API" }, { "id": "api.webrtc.register_token.app_error", @@ -2949,11 +2953,11 @@ }, { "id": "ent.metrics.starting.info", - "translation": "Metrics and profiling server is listening on %v" + "translation": "Сервер метрик и профилирования запускается на %v" }, { "id": "ent.metrics.stopping.info", - "translation": "Metrics and profiling server is stopping on %v" + "translation": "Сервер метрик и профилирования останавливается на %v" }, { "id": "ent.mfa.activate.authenticate.app_error", @@ -3113,7 +3117,7 @@ }, { "id": "manaultesting.get_channel_id.no_found.debug", - "translation": "Невозможно найти канал %v, %v возможностей просмотрено" + "translation": "Невозможно найти канал: %v, найдено похожих %v " }, { "id": "manaultesting.get_channel_id.unable.debug", @@ -3133,7 +3137,7 @@ }, { "id": "manaultesting.manual_test.uid.debug", - "translation": "Нет uid в url" + "translation": "Отсутствует uid в URL" }, { "id": "manaultesting.test_autolink.info", @@ -3161,7 +3165,7 @@ }, { "id": "mattermost.load_license.find.warn", - "translation": "License key from https://mattermost.com required to unlock enterprise features." + "translation": "Требуется лицензионный ключ от https://mattermost.com для доступа к возможностям корпоративной редакции." }, { "id": "mattermost.security_bulletin.error", @@ -3361,7 +3365,7 @@ }, { "id": "model.command.is_valid.url.app_error", - "translation": "Invalid URL" + "translation": "Неверный URL" }, { "id": "model.command.is_valid.url_http.app_error", @@ -3757,7 +3761,7 @@ }, { "id": "model.outgoing_hook.is_valid.callback.app_error", - "translation": "Некорректный адрес обратного вызова" + "translation": "Неверный адрес колбэка" }, { "id": "model.outgoing_hook.is_valid.channel_id.app_error", @@ -3853,7 +3857,7 @@ }, { "id": "model.post.is_valid.root_parent.app_error", - "translation": "Вы не имеете требуемого допуска" + "translation": "Должен быть установлен неверный корневой идентификатор, если установлен родительский" }, { "id": "model.post.is_valid.type.app_error", @@ -4001,7 +4005,7 @@ }, { "id": "model.user.is_valid.position.app_error", - "translation": "Invalid position: must not be longer than 35 characters." + "translation": "Неверная позиция: должно быть не более 35 символов." }, { "id": "model.user.is_valid.pwd.app_error", @@ -4161,11 +4165,11 @@ }, { "id": "store.sql.open_conn.critical", - "translation": "Не удалось открыть sql-соединение с err:%v" + "translation": "Не удалось открыть SQL соединение с err:%v" }, { "id": "store.sql.open_conn.panic", - "translation": "Не удалось открыть sql-соединение %v" + "translation": "Не удалось открыть SQL соединение %v" }, { "id": "store.sql.ping.critical", @@ -4309,7 +4313,7 @@ }, { "id": "store.sql_channel.get_member.missing.app_error", - "translation": "Ни одного участника канала не было найдено для данных идентификаторов пользователя и канала" + "translation": "Не найдено ни одного участника канала по данному идентификатору пользователя и канала" }, { "id": "store.sql_channel.get_member_count.app_error", @@ -4325,7 +4329,7 @@ }, { "id": "store.sql_channel.get_members_by_ids.app_error", - "translation": "Не удалось получить участников канала" + "translation": "Не удалось получить список участников канала" }, { "id": "store.sql_channel.get_more_channels.get.app_error", @@ -4785,43 +4789,43 @@ }, { "id": "store.sql_reaction.delete.begin.app_error", - "translation": "Unable to open transaction while deleting reaction" + "translation": "Не удалось открыть транзакцию при удалении реакции" }, { "id": "store.sql_reaction.delete.commit.app_error", - "translation": "Unable to commit transaction while deleting reaction" + "translation": "Не удалось совершить транзакцию при удалении реакции" }, { "id": "store.sql_reaction.delete.save.app_error", - "translation": "Unable to delete reaction" + "translation": "Не удалось удалить реакцию" }, { "id": "store.sql_reaction.delete_all_with_emoj_name.delete_reactions.app_error", - "translation": "Unable to delete reactions with the given emoji name" + "translation": "Не удалось удалить реакцию с данным именем эмодзи" }, { "id": "store.sql_reaction.delete_all_with_emoj_name.get_reactions.app_error", - "translation": "Unable to get reactions with the given emoji name" + "translation": "Не удалось получить реакцию с данным именем эмодзи" }, { "id": "store.sql_reaction.delete_all_with_emoji_name.update_post.warn", - "translation": "Unable to update Post.HasReactions while removing reactions post_id=%v, error=%v" + "translation": "Не удалось обновить Post.HasReactions во время удаления реакции post_id=%v, error=%v" }, { "id": "store.sql_reaction.get_for_post.app_error", - "translation": "Unable to get reactions for post" + "translation": "Не удалось получить реакции для данного сообщения" }, { "id": "store.sql_reaction.save.begin.app_error", - "translation": "Unable to open transaction while saving reaction" + "translation": "Не удалось открыть транзакцию при сохранении реакции" }, { "id": "store.sql_reaction.save.commit.app_error", - "translation": "Unable to commit transaction while saving reaction" + "translation": "Не удалось совершить транзакцию при сохранении реакции" }, { "id": "store.sql_reaction.save.save.app_error", - "translation": "Unable to save reaction" + "translation": "Не удалось сохранить реакцию" }, { "id": "store.sql_session.analytics_session_count.app_error", @@ -4973,7 +4977,7 @@ }, { "id": "store.sql_team.get_member.missing.app_error", - "translation": "Ни одного участника канала не было найдено для данных идентификаторов пользователя и команды" + "translation": "Не найдено ни одного участника команды по данному идентификатору пользователя и канала" }, { "id": "store.sql_team.get_member_count.app_error", @@ -4993,7 +4997,7 @@ }, { "id": "store.sql_team.get_unread.app_error", - "translation": "We couldn't get the teams unread messages" + "translation": "Не удалось получить список непрочтённых сообщений для команды" }, { "id": "store.sql_team.permanent_delete.app_error", @@ -5405,7 +5409,7 @@ }, { "id": "web.check_browser_compatibility.app_error", - "translation": "Ваш текущий браузер не поддерживается, пожалуйста, используйте один из следующих браузеров: Google Chrome 21 или новее, Internet Explorer 11 или новее, FireFox 14 или новее, Safari 9 или более новый" + "translation": "Ваш текущий браузер не поддерживается, пожалуйста, используйте один из следующих браузеров: Google Chrome 21 или новее, Internet Explorer 11 или новее, Firefox 14 или новее, Safari 9 или более новый" }, { "id": "web.claim_account.team.error", @@ -5449,7 +5453,7 @@ }, { "id": "web.incoming_webhook.attachment.app_error", - "translation": "Maximum attachments length is {{.Max}} characters, received size is {{.Actual}}" + "translation": "Максимальный размер вложения {{.Max}} символов, полученный размер {{.Actual}}" }, { "id": "web.incoming_webhook.channel.app_error", @@ -5477,7 +5481,7 @@ }, { "id": "web.incoming_webhook.text.length.app_error", - "translation": "Maximum text length is {{.Max}} characters, received size is {{.Actual}}" + "translation": "Максимальная длина текста {{.Max}} символов, получено {{.Actual}}" }, { "id": "web.incoming_webhook.user.app_error", diff --git a/i18n/zh_CN.json b/i18n/zh_CN.json index 7223cdabf3..ef51d7ad73 100644 --- a/i18n/zh_CN.json +++ b/i18n/zh_CN.json @@ -73,7 +73,7 @@ }, { "id": "api.admin.init.debug", - "translation": "初始化管理员API路由" + "translation": "正在初始化管理 API 路由" }, { "id": "api.admin.recycle_db_end.warn", @@ -197,7 +197,7 @@ }, { "id": "api.channel.create_channel.direct_channel.app_error", - "translation": "创建私信频道必须使用createDirectChannel接口服务" + "translation": "必须使用 createDirectChannel API 创建私信频道" }, { "id": "api.channel.create_channel.invalid_character.app_error", @@ -217,7 +217,7 @@ }, { "id": "api.channel.create_direct_channel.invalid_user.app_error", - "translation": "无效的其他用户ID" + "translation": "无效的其他用户 ID " }, { "id": "api.channel.delete_channel.archived", @@ -273,7 +273,7 @@ }, { "id": "api.channel.init.debug", - "translation": "初始化频道API路由" + "translation": "正在初始化频道 API 路由" }, { "id": "api.channel.join_channel.permissions.app_error", @@ -301,15 +301,15 @@ }, { "id": "api.channel.post_update_channel_displayname_message_and_forget.create_post.error", - "translation": "Failed to post displayname update message %v" + "translation": "发送显示名更新信息 %v 时失败" }, { "id": "api.channel.post_update_channel_displayname_message_and_forget.retrieve_user.error", - "translation": "尝试保存更新的频道标题消息 %v 时获取用户信息失败" + "translation": "尝试保存更新的频道标题消息 %v 时获取用户失败" }, { "id": "api.channel.post_update_channel_displayname_message_and_forget.updated_from", - "translation": "%s 将频道标题从 %s 更新为 %s" + "translation": "%s 将频道显示名从 %s 更新为 %s" }, { "id": "api.channel.post_update_channel_header_message_and_forget.join_leave.error", @@ -381,7 +381,7 @@ }, { "id": "api.command.delete.app_error", - "translation": "无删除权限" + "translation": "无效删除命令权限" }, { "id": "api.command.disabled.app_error", @@ -421,7 +421,7 @@ }, { "id": "api.command.init.debug", - "translation": "初始化控制API路由" + "translation": "正在初始化命令 API 路由" }, { "id": "api.command.invite_people.desc", @@ -453,7 +453,7 @@ }, { "id": "api.command.regen.app_error", - "translation": "没有重新生成命令令牌的权限" + "translation": "无效重新生成命令令牌权限" }, { "id": "api.command.team_mismatch.app_error", @@ -529,7 +529,7 @@ }, { "id": "api.command_expand_collapse.fail.app_error", - "translation": "放大预览时发生了错误" + "translation": "展开预览时发生了错误" }, { "id": "api.command_join.desc", @@ -537,7 +537,7 @@ }, { "id": "api.command_join.fail.app_error", - "translation": "加入频道时出错。" + "translation": "加入频道时发生错误。" }, { "id": "api.command_join.hint", @@ -545,7 +545,7 @@ }, { "id": "api.command_join.list.app_error", - "translation": "列出频道时出错。" + "translation": "列出频道时发生错误。" }, { "id": "api.command_join.missing.app_error", @@ -641,7 +641,7 @@ }, { "id": "api.command_shortcuts.browser.channel_next", - "translation": "{{.ChannelNextCmd}}: Next channel in your history\n" + "translation": "{{.ChannelNextCmd}}:您的历史记录里的下一个频道\n" }, { "id": "api.command_shortcuts.browser.channel_next.cmd", @@ -653,7 +653,7 @@ }, { "id": "api.command_shortcuts.browser.channel_prev", - "translation": "{{.ChannelPrevCmd}}: Previous channel in your history\n" + "translation": "{{.ChannelPrevCmd}}:您的历史记录里的上一个频道\n" }, { "id": "api.command_shortcuts.browser.channel_prev.cmd", @@ -665,27 +665,27 @@ }, { "id": "api.command_shortcuts.browser.font_decrease", - "translation": "{{.CmdOrCtrl}}+MINUS: Decrease font size (zoom out)\n" + "translation": "{{.CmdOrCtrl}}+减号:减少字体大小 (缩小)\n" }, { "id": "api.command_shortcuts.browser.font_increase", - "translation": "{{.CmdOrCtrl}}+PLUS: Increase font size (zoom in)\n" + "translation": "{{.CmdOrCtrl}}+加号:增加字体大小 (放大)\n" }, { "id": "api.command_shortcuts.browser.header", - "translation": "#### Built-in Browser Commands\n\n" + "translation": "#### 内置浏览器命令\n\n" }, { "id": "api.command_shortcuts.browser.highlight_next", - "translation": "SHIFT+DOWN (in input field): Highlight text to the next line\n" + "translation": "SHIFT+DOWN (在输入栏):高亮到下一行之间的文字\n" }, { "id": "api.command_shortcuts.browser.highlight_prev", - "translation": "SHIFT+UP (in input field): Highlight text to the previous line\n" + "translation": "SHIFT+UP (在输入栏):高亮到上一行之间的文字\n" }, { "id": "api.command_shortcuts.browser.newline", - "translation": "SHIFT+ENTER (in input field): Create a new line\n" + "translation": "SHIFT+ENTER (在输入栏):新增行\n" }, { "id": "api.command_shortcuts.cmd", @@ -701,47 +701,47 @@ }, { "id": "api.command_shortcuts.files.header", - "translation": "#### Files\n\n" + "translation": "#### 文件\n\n" }, { "id": "api.command_shortcuts.files.upload", - "translation": "{{.CmdOrCtrl}}+U: Upload file(s)\n\n" + "translation": "{{.CmdOrCtrl}}+U:上传文件\n\n" }, { "id": "api.command_shortcuts.header", - "translation": "### Keyboard Shortcuts\n\n" + "translation": "### 键盘快捷键\n\n" }, { "id": "api.command_shortcuts.msgs.comp_channel", - "translation": "~[character]+TAB: Autocomplete channel beginning with [character]\n" + "translation": "~[字符]+TAB:自动完成以[字符]开头的频道\n" }, { "id": "api.command_shortcuts.msgs.comp_emoji", - "translation": ":[character]+TAB: Autocomplete emoji beginning with [character]\n\n" + "translation": ":[字符]+TAB:自动完成以[字符]开头的表情符\n\n" }, { "id": "api.command_shortcuts.msgs.comp_username", - "translation": "@[character]+TAB: Autocomplete @username beginning with [character]\n" + "translation": "@[字符]+TAB:自动完成以[字符]开头的 @用户名\n" }, { "id": "api.command_shortcuts.msgs.edit", - "translation": "UP (in empty input field): Edit your last message in the current channel\n" + "translation": "向上键 (在空白输入栏):修改您在本频道的上一条消息\n" }, { "id": "api.command_shortcuts.msgs.header", - "translation": "#### Messages\n\n" + "translation": "#### 消息\n\n" }, { "id": "api.command_shortcuts.msgs.mark_as_read", - "translation": "ESC: Mark all messages in the current channel as read\n" + "translation": "ESC:将当前频道所有消息标为已读\n" }, { "id": "api.command_shortcuts.msgs.reprint_next", - "translation": "{{.CmdOrCtrl}}+DOWN (in empty input field): Reprint the next message or slash command you entered\n" + "translation": "{{.CmdOrCtrl}}+向下键 (在空白输入栏):重显示您输入的下一条消息或斜杠命令\n" }, { "id": "api.command_shortcuts.msgs.reprint_prev", - "translation": "{{.CmdOrCtrl}}+UP (in empty input field): Reprint the previous message or slash command you entered\n" + "translation": "{{.CmdOrCtrl}}+向上键 (在空白输入栏):重显示您输入的上一条消息或斜杠命令\n" }, { "id": "api.command_shortcuts.name", @@ -749,35 +749,35 @@ }, { "id": "api.command_shortcuts.nav.header", - "translation": "#### Navigation\n\n" + "translation": "#### 导航\n\n" }, { "id": "api.command_shortcuts.nav.next", - "translation": "ALT+DOWN: Next channel or direct message in left hand sidebar\n" + "translation": "ALT+向下键:左侧栏中的下一个频道或私信\n" }, { "id": "api.command_shortcuts.nav.prev", - "translation": "ALT+UP: Previous channel or direct message in left hand sidebar\n" + "translation": "ALT+向上键:左侧栏中的上一个频道或私信\n" }, { "id": "api.command_shortcuts.nav.recent_mentions", - "translation": "{{.CmdOrCtrl}}+SHIFT+M: Open recent mentions\n\n" + "translation": "{{.CmdOrCtrl}}+SHIFT+M:打开最近提及\n\n" }, { "id": "api.command_shortcuts.nav.settings", - "translation": "{{.CmdOrCtrl}}+SHIFT+A: Open account settings\n" + "translation": "{{.CmdOrCtrl}}+SHIFT+A:打开帐号设置\n" }, { "id": "api.command_shortcuts.nav.switcher", - "translation": "{{.CmdOrCtrl}}+K: Open a quick channel switcher dialog\n" + "translation": "{{.CmdOrCtrl}}+K:打开频道快速切换对话框\n" }, { "id": "api.command_shortcuts.nav.unread_next", - "translation": "ALT+SHIFT+DOWN: Next channel or direct message in left hand sidebar with unread messages\n" + "translation": "ALT+SHIFT+向下键:左侧栏中的下一个有未读消息的频道或私信\n" }, { "id": "api.command_shortcuts.nav.unread_prev", - "translation": "ALT+SHIFT+UP: Previous channel or direct message in left hand sidebar with unread messages\n" + "translation": "ALT+SHIFT+向上键:左侧栏中的上一个有未读消息的频道或私信\n" }, { "id": "api.command_shrug.desc", @@ -801,7 +801,7 @@ }, { "id": "api.context.invalid_team_url.debug", - "translation": "团队URL访问无效。团队URL不能在api函数或者和不相干的团队中使用" + "translation": "团队URL访问无效。团队URL不能在API函数或者和不相干的团队中使用" }, { "id": "api.context.invalid_token.error", @@ -923,7 +923,7 @@ }, { "id": "api.emoji.create.permissions.app_error", - "translation": "无创建表情符权限。" + "translation": "无效创建表情符权限。" }, { "id": "api.emoji.create.too_large.app_error", @@ -935,7 +935,7 @@ }, { "id": "api.emoji.delete.permissions.app_error", - "translation": "无删除表情符权限。" + "translation": "无效删除表情符权限。" }, { "id": "api.emoji.disabled.app_error", @@ -951,7 +951,7 @@ }, { "id": "api.emoji.init.debug", - "translation": "正在初始化表情符api路径" + "translation": "正在初始化表情符 API 路由" }, { "id": "api.emoji.storage.app_error", @@ -1039,7 +1039,7 @@ }, { "id": "api.file.init.debug", - "translation": "初始化文件API路由" + "translation": "正在初始化文件 API 路由" }, { "id": "api.file.migrate_filenames_to_file_infos.channel.app_error", @@ -1171,7 +1171,11 @@ }, { "id": "api.general.init.debug", - "translation": "正在初始化通用api路由" + "translation": "正在初始化常规 API 路由" + }, + { + "id": "api.import.import_post.attach_files.error", + "translation": "给消息添加附件时失败。postId=%v, fileIds=%v, message=%v" }, { "id": "api.import.import_post.saving.debug", @@ -1231,7 +1235,7 @@ }, { "id": "api.license.init.debug", - "translation": "初始化许可证API路由" + "translation": "正在初始化许可证 API 路由" }, { "id": "api.license.remove_license.remove.app_error", @@ -1275,7 +1279,7 @@ }, { "id": "api.oauth.delete.permissions.app_error", - "translation": "没有权限删除 OAuth2 应用" + "translation": "无效删除 OAuth2 应用权限" }, { "id": "api.oauth.get_access_token.bad_client_id.app_error", @@ -1339,11 +1343,11 @@ }, { "id": "api.oauth.init.debug", - "translation": "初始化认证API路由" + "translation": "正在初始化 OAuth API 路由" }, { "id": "api.oauth.regenerate_secret.app_error", - "translation": "没有权限重新生成 OAuth2 应用秘钥" + "translation": "无效重新生成 OAuth2 应用秘钥权限" }, { "id": "api.oauth.register_oauth_app.turn_off.app_error", @@ -1497,7 +1501,7 @@ }, { "id": "api.post.init.debug", - "translation": "初始化post api路由" + "translation": "正在初始化发文 API 路由" }, { "id": "api.post.make_direct_channel_visible.get_2_members.error", @@ -1629,7 +1633,7 @@ }, { "id": "api.preference.init.debug", - "translation": "初始化优先级api路由" + "translation": "正在初始化偏好 API 路由" }, { "id": "api.preference.save_preferences.decode.app_error", @@ -1645,19 +1649,19 @@ }, { "id": "api.reaction.delete_reaction.mismatched_channel_id.app_error", - "translation": "Failed to delete reaction because channel ID does not match post ID in the URL" + "translation": "因网址中频道 ID 与消息 ID不符而删除反应失败" }, { "id": "api.reaction.init.debug", - "translation": "初始化管理员API路由" + "translation": "正在初始化反应 API 路由" }, { "id": "api.reaction.list_reactions.mismatched_channel_id.app_error", - "translation": "Failed to get reactions because channel ID does not match post ID in the URL" + "translation": "因网址中频道 ID 与消息 ID不符而获取反应失败" }, { "id": "api.reaction.save_reaction.mismatched_channel_id.app_error", - "translation": "Failed to save reaction because channel ID does not match post ID in the URL" + "translation": "因网址中频道 ID 与消息 ID不符而保存反应失败" }, { "id": "api.reaction.send_reaction_event.post.app_error", @@ -1885,7 +1889,7 @@ }, { "id": "api.status.init.debug", - "translation": "初始化状态 API 路由" + "translation": "正在初始化状态 API 路由" }, { "id": "api.status.last_activity.error", @@ -1949,11 +1953,11 @@ }, { "id": "api.team.import_team.unavailable.app_error", - "translation": "Malformed request: filesize field is not present." + "translation": "错误请求:缺少 filesize 字段。" }, { "id": "api.team.init.debug", - "translation": "初始化团队api路由" + "translation": "正在初始化团队 API 路由" }, { "id": "api.team.invite_members.admin", @@ -2417,7 +2421,7 @@ }, { "id": "api.user.init.debug", - "translation": "初始化用户api路由" + "translation": "正在初始化用户 API 路由" }, { "id": "api.user.ldap_to_email.not_available.app_error", @@ -2441,7 +2445,7 @@ }, { "id": "api.user.login.not_provided.app_error", - "translation": "Must provide either user ID, or team name and user email" + "translation": "必须提供用户 ID 或团队名和用户邮箱地址" }, { "id": "api.user.login.not_verified.app_error", @@ -2677,7 +2681,7 @@ }, { "id": "api.web_socket.init.debug", - "translation": "初始化Web Socket API路由" + "translation": "正在初始化 Web Socket API 路由" }, { "id": "api.web_socket_handler.log.error", @@ -2709,7 +2713,7 @@ }, { "id": "api.webhook.create_outgoing.permissions.app_error", - "translation": "没有权限创建对外webhook。" + "translation": "无效的创建传出的 webhook 权限。" }, { "id": "api.webhook.create_outgoing.triggers.app_error", @@ -2721,7 +2725,7 @@ }, { "id": "api.webhook.delete_incoming.permissions.app_errror", - "translation": "没有权限删除传入的webhook" + "translation": "无效的删除传入的 webhook 权限" }, { "id": "api.webhook.delete_outgoing.disabled.app_error", @@ -2729,7 +2733,7 @@ }, { "id": "api.webhook.delete_outgoing.permissions.app_error", - "translation": "没有权限删除对外webhook" + "translation": "无效的删除传出的 webhook 权限" }, { "id": "api.webhook.get_incoming.disabled.app_error", @@ -2749,7 +2753,7 @@ }, { "id": "api.webhook.init.debug", - "translation": "初始化webhook api路由" + "translation": "正在初始化 webhook API 路由" }, { "id": "api.webhook.regen_outgoing_token.disabled.app_error", @@ -2757,7 +2761,7 @@ }, { "id": "api.webhook.regen_outgoing_token.permissions.app_error", - "translation": "没有权限重新生成传出webhook令牌" + "translation": "无效的重新生成传出的 webhook 令牌权限" }, { "id": "api.webrtc.disabled.app_error", @@ -2765,7 +2769,7 @@ }, { "id": "api.webrtc.init.debug", - "translation": "初始化 WebRTC api 路由中" + "translation": "正在初始化 WebRTC API 路由" }, { "id": "api.webrtc.register_token.app_error", @@ -3077,7 +3081,7 @@ }, { "id": "error.generic.message", - "translation": "出现一个错误。" + "translation": "发生一个错误。" }, { "id": "error.generic.title", @@ -3133,7 +3137,7 @@ }, { "id": "manaultesting.manual_test.uid.debug", - "translation": "URL 中没有 UID" + "translation": "网址中没有 uid" }, { "id": "manaultesting.test_autolink.info", @@ -3345,7 +3349,7 @@ }, { "id": "model.command.is_valid.team_id.app_error", - "translation": "无效团队id" + "translation": "无效的团队 ID" }, { "id": "model.command.is_valid.token.app_error", @@ -3361,7 +3365,7 @@ }, { "id": "model.command.is_valid.url.app_error", - "translation": "Invalid URL" + "translation": "无效的 URL" }, { "id": "model.command.is_valid.url_http.app_error", @@ -3633,11 +3637,11 @@ }, { "id": "model.config.is_valid.webrtc_gateway_ws_url.app_error", - "translation": "WebRTC 网关 Websocket 网址必须时有效的网址并且以 ws:// 或 wss:// 开头。" + "translation": "WebRTC 网关 Websocket 网址必须是有效的网址并且以 ws:// 或 wss:// 开头。" }, { "id": "model.config.is_valid.webrtc_stun_uri.app_error", - "translation": "WebRTC STUN URI 必须为有效的 URI 并且以 stun: 开头" + "translation": "WebRTC STUN URI 必须为有效的 URL 并且以 stun: 开头" }, { "id": "model.config.is_valid.webrtc_turn_shared_key.app_error", @@ -3705,7 +3709,7 @@ }, { "id": "model.incoming_hook.team_id.app_error", - "translation": "无效团队id" + "translation": "无效的团队 ID" }, { "id": "model.incoming_hook.update_at.app_error", @@ -3757,7 +3761,7 @@ }, { "id": "model.outgoing_hook.is_valid.callback.app_error", - "translation": "无效回调网址" + "translation": "无效的回调网址" }, { "id": "model.outgoing_hook.is_valid.channel_id.app_error", @@ -3781,7 +3785,7 @@ }, { "id": "model.outgoing_hook.is_valid.team_id.app_error", - "translation": "无效团队id" + "translation": "无效的团队 ID" }, { "id": "model.outgoing_hook.is_valid.token.app_error", @@ -3853,7 +3857,7 @@ }, { "id": "model.post.is_valid.root_parent.app_error", - "translation": "如果父id设置必须设置根id,无效的根id" + "translation": "如果父 ID 已设置则必须设置无效根 ID" }, { "id": "model.post.is_valid.type.app_error", @@ -3957,7 +3961,7 @@ }, { "id": "model.team_member.is_valid.team_id.app_error", - "translation": "无效团队id" + "translation": "无效的团队 ID" }, { "id": "model.team_member.is_valid.user_id.app_error", @@ -4069,7 +4073,7 @@ }, { "id": "model.user.is_valid.team_id.app_error", - "translation": "无效团队id" + "translation": "无效的团队 ID" }, { "id": "model.user.is_valid.update_at.app_error", @@ -4169,7 +4173,7 @@ }, { "id": "store.sql.ping.critical", - "translation": "ping数据库失败 err:%v" + "translation": "ping 数据库失败 err:%v" }, { "id": "store.sql.pinging.info", @@ -4325,7 +4329,7 @@ }, { "id": "store.sql_channel.get_members_by_ids.app_error", - "translation": "我们无法获得该频道成员" + "translation": "我们无法获得频道成员" }, { "id": "store.sql_channel.get_more_channels.get.app_error", @@ -4365,7 +4369,7 @@ }, { "id": "store.sql_channel.save_channel.existing.app_error", - "translation": "必须对现有的频道更新" + "translation": "必须对现有的频道执行更新" }, { "id": "store.sql_channel.save_channel.exists.app_error", @@ -4405,7 +4409,7 @@ }, { "id": "store.sql_channel.save_member.exists.app_error", - "translation": "该频道成员 id 已存在" + "translation": "该频道已存在拥有此 ID 的成员" }, { "id": "store.sql_channel.save_member.open_transaction.app_error", @@ -4617,7 +4621,7 @@ }, { "id": "store.sql_oauth.save_app.existing.app_error", - "translation": "必须更新现有的app" + "translation": "必须对现有的应用执行更新" }, { "id": "store.sql_oauth.save_app.save.app_error", @@ -5017,7 +5021,7 @@ }, { "id": "store.sql_team.save_member.exists.app_error", - "translation": "拥有此id的团队成员已存在" + "translation": "拥有此ID的团队成员已存在" }, { "id": "store.sql_team.save_member.save.app_error", @@ -5129,7 +5133,7 @@ }, { "id": "store.sql_user.save.existing.app_error", - "translation": "必须对现有的用户更新" + "translation": "必须对现有的用户执行更新" }, { "id": "store.sql_user.save.max_accounts.app_error", @@ -5377,7 +5381,7 @@ }, { "id": "utils.mail.send_mail.msg_data.app_error", - "translation": "无法添加电子邮件信息数据" + "translation": "添加电子邮件信息数据失败" }, { "id": "utils.mail.send_mail.sending.debug", @@ -5405,7 +5409,7 @@ }, { "id": "web.check_browser_compatibility.app_error", - "translation": "你当前的浏览器不支持, 请升级到下列浏览器之一: Chrome 21及以上, Internet Explorer 11及以上, FireFox 14及以上, Safari 9及以上" + "translation": "您当前的浏览器不支持,请升级到下列浏览器之一:Chrome 21 或以上、Internet Explorer 11 或以上、火狐 14 或以上、Safari 9 或以上" }, { "id": "web.claim_account.team.error", @@ -5449,7 +5453,7 @@ }, { "id": "web.incoming_webhook.attachment.app_error", - "translation": "Maximum attachments length is {{.Max}} characters, received size is {{.Actual}}" + "translation": "最大附件长度为 {{.Max}} 字,已收到大小为 {{.Actual}}" }, { "id": "web.incoming_webhook.channel.app_error", @@ -5477,7 +5481,7 @@ }, { "id": "web.incoming_webhook.text.length.app_error", - "translation": "Maximum text length is {{.Max}} characters, received size is {{.Actual}}" + "translation": "最大文字长度位 {{.Max}} 字,已收到大小为 {{.Actual}}" }, { "id": "web.incoming_webhook.user.app_error", diff --git a/i18n/zh_TW.json b/i18n/zh_TW.json index a3f8c5fae0..1299f2d2be 100644 --- a/i18n/zh_TW.json +++ b/i18n/zh_TW.json @@ -1173,6 +1173,10 @@ "id": "api.general.init.debug", "translation": "正在初始化一般 API 路徑" }, + { + "id": "api.import.import_post.attach_files.error", + "translation": "附加檔案於文章時錯誤:postId=%v, fileIds=%v, message=%v" + }, { "id": "api.import.import_post.saving.debug", "translation": "儲存訊息時遇到錯誤。user=%v, message=%v" diff --git a/model/status.go b/model/status.go index 8637f60a39..fec3a5f708 100644 --- a/model/status.go +++ b/model/status.go @@ -44,3 +44,14 @@ func StatusFromJson(data io.Reader) *Status { return nil } } + +func StatusMapToInterfaceMap(statusMap map[string]*Status) map[string]interface{} { + interfaceMap := map[string]interface{}{} + for _, s := range statusMap { + // Omitted statues mean offline + if s.Status != STATUS_OFFLINE { + interfaceMap[s.UserId] = s.Status + } + } + return interfaceMap +} diff --git a/utils/license.go b/utils/license.go index 456a731a17..2c43db6dd4 100644 --- a/utils/license.go +++ b/utils/license.go @@ -168,7 +168,6 @@ func GetSanitizedClientLicense() map[string]string { if IsLicensed { delete(sanitizedLicense, "Name") delete(sanitizedLicense, "Email") - delete(sanitizedLicense, "Company") delete(sanitizedLicense, "PhoneNumber") delete(sanitizedLicense, "IssuedAt") delete(sanitizedLicense, "StartsAt") diff --git a/webapp/actions/global_actions.jsx b/webapp/actions/global_actions.jsx index c6b7969832..ea077d6eb9 100644 --- a/webapp/actions/global_actions.jsx +++ b/webapp/actions/global_actions.jsx @@ -55,6 +55,10 @@ export function emitChannelClickEvent(channel) { trackPage(); }); + // Mark previous and next channel as read + ChannelStore.resetCounts(ChannelStore.getCurrentId()); + ChannelStore.resetCounts(chan.id); + BrowserStore.setGlobalItem(chan.team_id, chan.id); AppDispatcher.handleViewAction({ @@ -487,10 +491,9 @@ export function clientLogout(redirectTo = '/') { UserStore.clear(); TeamStore.clear(); ChannelStore.clear(); - newLocalizationSelected(global.window.mm_config.DefaultClientLocale); stopPeriodicStatusUpdates(); WebsocketActions.close(); - browserHistory.push(redirectTo); + window.location.href = redirectTo; } export function emitSearchMentionsEvent(user) { diff --git a/webapp/client/web_client.jsx b/webapp/client/web_client.jsx index 53e199e668..99f30da374 100644 --- a/webapp/client/web_client.jsx +++ b/webapp/client/web_client.jsx @@ -13,6 +13,11 @@ import request from 'superagent'; const HTTP_UNAUTHORIZED = 401; +const mfaPaths = [ + '/mfa/setup', + '/mfa/confirm' +]; + class WebClientClass extends Client { constructor() { super(); @@ -39,7 +44,9 @@ class WebClientClass extends Client { handleError(err, res) { if (res && res.body && res.body.id === 'api.context.mfa_required.app_error') { - window.location.reload(); + if (mfaPaths.indexOf(window.location.pathname) === -1) { + window.location.reload(); + } return; } diff --git a/webapp/components/admin_console/admin_team_members_dropdown.jsx b/webapp/components/admin_console/admin_team_members_dropdown.jsx index 0019dfbc00..ee9e53f6c3 100644 --- a/webapp/components/admin_console/admin_team_members_dropdown.jsx +++ b/webapp/components/admin_console/admin_team_members_dropdown.jsx @@ -432,10 +432,6 @@ export default class AdminTeamMembersDropdown extends React.Component { ); } - if (global.window.mm_config.EnableSignInWithEmail !== 'true') { - passwordReset = null; - } - let makeDemoteModal = null; if (this.props.user.id === me.id) { const title = ( diff --git a/webapp/components/admin_console/policy_settings.jsx b/webapp/components/admin_console/policy_settings.jsx index 50b9d40336..0e224af731 100644 --- a/webapp/components/admin_console/policy_settings.jsx +++ b/webapp/components/admin_console/policy_settings.jsx @@ -146,7 +146,11 @@ export default class PolicySettings extends AdminSettings { defaultMessage='Set policy on who can delete public channels. Deleted channels can be recovered from the database using a {commandLineToolLink}.' values={{ commandLineToolLink: ( - + +
-
diff --git a/webapp/components/analytics/system_analytics.jsx b/webapp/components/analytics/system_analytics.jsx index 244e1ff072..dd7b902605 100644 --- a/webapp/components/analytics/system_analytics.jsx +++ b/webapp/components/analytics/system_analytics.jsx @@ -80,68 +80,140 @@ class SystemAnalytics extends React.Component { render() { const stats = this.state.stats; + const isLicensed = global.window.mm_license.IsLicensed === 'true'; + const skippedIntensiveQueries = stats[StatTypes.TOTAL_POSTS] === -1; + const postCountsDay = formatPostsPerDayData(stats[StatTypes.POST_PER_DAY]); + const userCountsWithPostsDay = formatUsersWithPostsPerDayData(stats[StatTypes.USERS_WITH_POSTS_PER_DAY]); let banner; - if (stats[StatTypes.TOTAL_POSTS] === -1) { + let postCount; + let postTotalGraph; + let activeUserGraph; + if (skippedIntensiveQueries) { banner = ( - +
+
+ + ); + } else { + postCount = ( + } + icon='fa-comment' + count={stats[StatTypes.TOTAL_POSTS]} /> ); + + postTotalGraph = ( +
+ + } + data={postCountsDay} + options={{ + legend: { + display: false + } + }} + width='740' + height='225' + /> +
+ ); + + activeUserGraph = ( +
+ + } + data={userCountsWithPostsDay} + options={{ + legend: { + display: false + } + }} + width='740' + height='225' + /> +
+ ); } - let advancedCounts; let advancedStats; let advancedGraphs; + let sessionCount; + let commandCount; + let incomingCount; + let outgoingCount; if (global.window.mm_license.IsLicensed === 'true') { - advancedCounts = ( -
- - } - icon='fa-signal' - count={stats[StatTypes.TOTAL_SESSIONS]} - /> - - } - icon='fa-terminal' - count={stats[StatTypes.TOTAL_COMMANDS]} - /> - - } - icon='fa-arrow-down' - count={stats[StatTypes.TOTAL_IHOOKS]} - /> - - } - icon='fa-arrow-up' - count={stats[StatTypes.TOTAL_OHOOKS]} - /> -
+ sessionCount = ( + + } + icon='fa-signal' + count={stats[StatTypes.TOTAL_SESSIONS]} + /> + ); + + commandCount = ( + + } + icon='fa-terminal' + count={stats[StatTypes.TOTAL_COMMANDS]} + /> + ); + + incomingCount = ( + + } + icon='fa-arrow-down' + count={stats[StatTypes.TOTAL_IHOOKS]} + /> + ); + + outgoingCount = ( + + } + icon='fa-arrow-up' + count={stats[StatTypes.TOTAL_OHOOKS]} + /> ); advancedStats = ( @@ -247,65 +319,89 @@ class SystemAnalytics extends React.Component { } } - const postCountsDay = formatPostsPerDayData(stats[StatTypes.POST_PER_DAY]); - const userCountsWithPostsDay = formatUsersWithPostsPerDayData(stats[StatTypes.USERS_WITH_POSTS_PER_DAY]); - - let totalPostsCount; - let postTotalGraph; - let activeUserGraph; - if (stats[StatTypes.TOTAL_POSTS] !== -1) { - totalPostsCount = ( - - } - icon='fa-comment' - count={stats[StatTypes.TOTAL_POSTS]} - /> - ); - - postTotalGraph = ( -
- - } - data={postCountsDay} - options={{ - legend: { - display: false - } - }} - width='740' - height='225' + const userCount = ( + + } + icon='fa-user' + count={stats[StatTypes.TOTAL_USERS]} + /> + ); + + const teamCount = ( + + } + icon='fa-users' + count={stats[StatTypes.TOTAL_TEAMS]} + /> + ); + + const channelCount = ( + + } + icon='fa-globe' + count={stats[StatTypes.TOTAL_PUBLIC_CHANNELS] + stats[StatTypes.TOTAL_PRIVATE_GROUPS]} + /> + ); + + let firstRow; + let secondRow; + if (isLicensed && skippedIntensiveQueries) { + firstRow = ( +
+ {userCount} + {teamCount} + {channelCount} + {sessionCount}
); - activeUserGraph = ( + secondRow = (
- - } - data={userCountsWithPostsDay} - options={{ - legend: { - display: false - } - }} - width='740' - height='225' - /> + {commandCount} + {incomingCount} + {outgoingCount} +
+ ); + } else if (isLicensed && !skippedIntensiveQueries) { + firstRow = ( +
+ {userCount} + {teamCount} + {channelCount} + {postCount} +
+ ); + + secondRow = ( +
+ {sessionCount} + {commandCount} + {incomingCount} + {outgoingCount} +
+ ); + } else if (!isLicensed) { + firstRow = ( +
+ {userCount} + {teamCount} + {channelCount} + {postCount}
); } @@ -319,40 +415,8 @@ class SystemAnalytics extends React.Component { /> {banner} -
- - } - icon='fa-user' - count={stats[StatTypes.TOTAL_USERS]} - /> - - } - icon='fa-users' - count={stats[StatTypes.TOTAL_TEAMS]} - /> - {totalPostsCount} - - } - icon='fa-globe' - count={stats[StatTypes.TOTAL_PUBLIC_CHANNELS] + stats[StatTypes.TOTAL_PRIVATE_GROUPS]} - /> -
- {advancedCounts} + {firstRow} + {secondRow} {advancedStats} {advancedGraphs} {postTotalGraph} diff --git a/webapp/components/channel_members_modal.jsx b/webapp/components/channel_members_modal.jsx index 9f6a2a2eb4..351efed967 100644 --- a/webapp/components/channel_members_modal.jsx +++ b/webapp/components/channel_members_modal.jsx @@ -168,7 +168,7 @@ export default class ChannelMembersModal extends React.Component { return (