diff --git a/app/models/translation_override.rb b/app/models/translation_override.rb index 32e45186d11..41334c3c24a 100644 --- a/app/models/translation_override.rb +++ b/app/models/translation_override.rb @@ -138,7 +138,8 @@ class TranslationOverride < ActiveRecord::Base :base, I18n.t( "activerecord.errors.models.translation_overrides.attributes.value.invalid_interpolation_keys", - keys: invalid_keys.join(", "), + keys: invalid_keys.join(I18n.t("word_connector.comma")), + count: invalid_keys.size, ), ) diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 2e3fdd52cd2..d855d9c87aa 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -161,6 +161,9 @@ en: email: "Send via email" url: "Copy and share URL" + word_connector: + comma: ", " + action_codes: public_topic: "Made this topic public %{when}" open_topic: "Converted this to a topic %{when}" diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml index 3669228720b..120551cb510 100644 --- a/config/locales/server.en.yml +++ b/config/locales/server.en.yml @@ -641,7 +641,9 @@ en: translation_overrides: attributes: value: - invalid_interpolation_keys: 'The following interpolation key(s) are invalid: "%{keys}"' + invalid_interpolation_keys: + one: 'The following interpolation key is invalid: %{keys}' + other: 'The following interpolation keys are invalid: %{keys}' watched_word: attributes: word: diff --git a/plugins/chat/app/models/chat_channel.rb b/plugins/chat/app/models/chat_channel.rb index beb38e15a8f..35f427a2049 100644 --- a/plugins/chat/app/models/chat_channel.rb +++ b/plugins/chat/app/models/chat_channel.rb @@ -75,10 +75,6 @@ class ChatChannel < ActiveRecord::Base Chat::ChatChannelMembershipManager.new(self).unfollow(user) end - def status_name - I18n.t("chat.channel.statuses.#{self.status}") - end - def url "#{Discourse.base_url}/chat/c/#{self.slug || "-"}/#{self.id}" end diff --git a/plugins/chat/app/models/chat_message.rb b/plugins/chat/app/models/chat_message.rb index 677c14aa222..6b485036a31 100644 --- a/plugins/chat/app/models/chat_message.rb +++ b/plugins/chat/app/models/chat_message.rb @@ -52,7 +52,7 @@ class ChatMessage < ActiveRecord::Base :base, I18n.t( "chat.errors.minimum_length_not_met", - minimum: SiteSetting.chat_minimum_message_length, + count: SiteSetting.chat_minimum_message_length, ), ) end @@ -60,7 +60,7 @@ class ChatMessage < ActiveRecord::Base if message_too_long? self.errors.add( :base, - I18n.t("chat.errors.message_too_long", maximum: SiteSetting.chat_maximum_message_length), + I18n.t("chat.errors.message_too_long", count: SiteSetting.chat_maximum_message_length), ) end end diff --git a/plugins/chat/app/models/direct_message.rb b/plugins/chat/app/models/direct_message.rb index 40ad99c4723..58427608f15 100644 --- a/plugins/chat/app/models/direct_message.rb +++ b/plugins/chat/app/models/direct_message.rb @@ -25,7 +25,7 @@ class DirectMessage < ActiveRecord::Base # direct message to self if users.empty? - return I18n.t("chat.channel.dm_title.single_user", user: "@#{acting_user.username}") + return I18n.t("chat.channel.dm_title.single_user", username: "@#{acting_user.username}") end # all users deleted @@ -36,13 +36,16 @@ class DirectMessage < ActiveRecord::Base return( I18n.t( "chat.channel.dm_title.multi_user_truncated", - users: usernames_formatted[0..4].join(", "), - leftover: usernames_formatted.length - 5, + comma_separated_usernames: usernames_formatted[0..4].join(I18n.t("word_connector.comma")), + count: usernames_formatted.length - 5, ) ) end - I18n.t("chat.channel.dm_title.multi_user", users: usernames_formatted.join(", ")) + I18n.t( + "chat.channel.dm_title.multi_user", + comma_separated_usernames: usernames_formatted.join(I18n.t("word_connector.comma")), + ) end end diff --git a/plugins/chat/app/serializers/chat_message_serializer.rb b/plugins/chat/app/serializers/chat_message_serializer.rb index 66e96535402..9f6dc19a23e 100644 --- a/plugins/chat/app/serializers/chat_message_serializer.rb +++ b/plugins/chat/app/serializers/chat_message_serializer.rb @@ -40,7 +40,7 @@ class ChatMessageSerializer < ApplicationSerializer .reactions .group_by(&:emoji) .each do |emoji, reactions| - users = reactions[0..6].map(&:user).filter { |user| user.id != scope&.user&.id }[0..5] + users = reactions[0..5].map(&:user).filter { |user| user.id != scope&.user&.id }[0..4] next unless Emoji.exists?(emoji) diff --git a/plugins/chat/assets/javascripts/discourse/components/chat-channel-status.js b/plugins/chat/assets/javascripts/discourse/components/chat-channel-status.js index f6048b21b9d..cfbd949cdac 100644 --- a/plugins/chat/assets/javascripts/discourse/components/chat-channel-status.js +++ b/plugins/chat/assets/javascripts/discourse/components/chat-channel-status.js @@ -4,7 +4,6 @@ import Component from "@ember/component"; import { CHANNEL_STATUSES, channelStatusIcon, - channelStatusName, } from "discourse/plugins/chat/discourse/models/chat-channel"; export default Component.extend({ @@ -38,20 +37,28 @@ export default Component.extend({ }, _shortStatusMessage(channelStatus) { - return channelStatusName(channelStatus); + switch (channelStatus) { + case CHANNEL_STATUSES.archived: + return I18n.t("chat.channel_status.archived"); + case CHANNEL_STATUSES.closed: + return I18n.t("chat.channel_status.closed"); + case CHANNEL_STATUSES.open: + return I18n.t("chat.channel_status.open"); + case CHANNEL_STATUSES.readOnly: + return I18n.t("chat.channel_status.read_only"); + } }, _longStatusMessage(channelStatus) { switch (channelStatus) { - case CHANNEL_STATUSES.closed: - return I18n.t("chat.channel_status.closed_header"); - break; - case CHANNEL_STATUSES.readOnly: - return I18n.t("chat.channel_status.read_only_header"); - break; case CHANNEL_STATUSES.archived: return I18n.t("chat.channel_status.archived_header"); - break; + case CHANNEL_STATUSES.closed: + return I18n.t("chat.channel_status.closed_header"); + case CHANNEL_STATUSES.open: + return I18n.t("chat.channel_status.open_header"); + case CHANNEL_STATUSES.readOnly: + return I18n.t("chat.channel_status.read_only_header"); } }, }); diff --git a/plugins/chat/assets/javascripts/discourse/components/chat-composer.js b/plugins/chat/assets/javascripts/discourse/components/chat-composer.js index 567df1590cc..315083f6fe2 100644 --- a/plugins/chat/assets/javascripts/discourse/components/chat-composer.js +++ b/plugins/chat/assets/javascripts/discourse/components/chat-composer.js @@ -19,7 +19,6 @@ import { readOnly, reads } from "@ember/object/computed"; import { SKIP } from "discourse/lib/autocomplete"; import { Promise } from "rsvp"; import { translations } from "pretty-text/emoji/data"; -import { channelStatusName } from "discourse/plugins/chat/discourse/models/chat-channel"; import { setupHashtagAutocomplete } from "discourse/lib/hashtag-autocomplete"; import { chatComposerButtons, @@ -566,17 +565,21 @@ export default Component.extend(TextareaTextManipulation, { @discourseComputed("userSilenced", "chatChannel.{chatable.users.[],id}") placeholder(userSilenced, chatChannel) { if (!chatChannel.canModifyMessages(this.currentUser)) { - return I18n.t("chat.placeholder_new_message_disallowed", { - status: channelStatusName(chatChannel.status).toLowerCase(), - }); + return I18n.t( + `chat.placeholder_new_message_disallowed.${chatChannel.status}` + ); } if (chatChannel.isDraft) { - return I18n.t("chat.placeholder_start_conversation", { - usernames: chatChannel?.chatable?.users?.length - ? chatChannel.chatable.users.mapBy("username").join(", ") - : "...", - }); + if (chatChannel?.chatable?.users?.length) { + return I18n.t("chat.placeholder_start_conversation_users", { + usernames: chatChannel.chatable.users + .mapBy("username") + .join(I18n.t("word_connector.comma")), + }); + } else { + return I18n.t("chat.placeholder_start_conversation"); + } } if (userSilenced) { @@ -596,14 +599,14 @@ export default Component.extend(TextareaTextManipulation, { return I18n.t("chat.placeholder_self"); } - return I18n.t("chat.placeholder_others", { - messageRecipient: directMessageRecipients + return I18n.t("chat.placeholder_users", { + commaSeparatedNames: directMessageRecipients .map((u) => u.name || `@${u.username}`) - .join(", "), + .join(I18n.t("word_connector.comma")), }); } else { - return I18n.t("chat.placeholder_others", { - messageRecipient: `#${chatChannel.title}`, + return I18n.t("chat.placeholder_channel", { + channelName: `#${chatChannel.title}`, }); } }, diff --git a/plugins/chat/assets/javascripts/discourse/components/chat-mention-warnings.js b/plugins/chat/assets/javascripts/discourse/components/chat-mention-warnings.js index 8ea0880fab2..24592fec121 100644 --- a/plugins/chat/assets/javascripts/discourse/components/chat-mention-warnings.js +++ b/plugins/chat/assets/javascripts/discourse/components/chat-mention-warnings.js @@ -2,6 +2,7 @@ import Component from "@glimmer/component"; import I18n from "I18n"; import { htmlSafe } from "@ember/template"; import { inject as service } from "@ember/service"; +import getURL from "discourse-common/lib/get-url"; export default class ChatMentionWarnings extends Component { @service siteSettings; @@ -79,31 +80,22 @@ export default class ChatMentionWarnings extends Component { return; } - let notificationLimit = I18n.t( - "chat.mention_warning.groups.notification_limit" - ); - - if (this.currentUser.staff) { - notificationLimit = htmlSafe( - ` - ${notificationLimit} - ` + if (this.currentUser.admin) { + return htmlSafe( + I18n.t("chat.mention_warning.too_many_mentions_admin", { + count: this.siteSettings.max_mentions_per_chat_message, + siteSettingUrl: getURL( + "/admin/site_settings/category/plugins?filter=max_mentions_per_chat_message" + ), + }) + ); + } else { + return htmlSafe( + I18n.t("chat.mention_warning.too_many_mentions", { + count: this.siteSettings.max_mentions_per_chat_message, + }) ); } - - const settingLimit = I18n.t("chat.mention_warning.mentions_limit", { - count: this.siteSettings.max_mentions_per_chat_message, - }); - - return htmlSafe( - I18n.t("chat.mention_warning.too_many_mentions", { - notification_limit: notificationLimit, - limit: settingLimit, - }) - ); } get unreachableBody() { @@ -111,17 +103,21 @@ export default class ChatMentionWarnings extends Component { return; } - if (this.unreachableGroupMentionsCount <= 2) { - return I18n.t("chat.mention_warning.groups.unreachable", { - group: this.unreachableGroupMentions[0], - group_2: this.unreachableGroupMentions[1], - count: this.unreachableGroupMentionsCount, - }); - } else { - return I18n.t("chat.mention_warning.groups.unreachable_multiple", { - group: this.unreachableGroupMentions[0], - count: this.unreachableGroupMentionsCount - 1, //N others - }); + switch (this.unreachableGroupMentionsCount) { + case 1: + return I18n.t("chat.mention_warning.groups.unreachable_1", { + group: this.unreachableGroupMentions[0], + }); + case 2: + return I18n.t("chat.mention_warning.groups.unreachable_2", { + group1: this.unreachableGroupMentions[0], + group2: this.unreachableGroupMentions[1], + }); + default: + return I18n.t("chat.mention_warning.groups.unreachable_multiple", { + group: this.unreachableGroupMentions[0], + count: this.unreachableGroupMentionsCount - 1, + }); } } @@ -130,44 +126,18 @@ export default class ChatMentionWarnings extends Component { return; } - let notificationLimit = I18n.t( - "chat.mention_warning.groups.notification_limit" + return htmlSafe( + I18n.messageFormat("chat.mention_warning.groups.too_many_members_MF", { + groupCount: this.overMembersLimitMentionsCount, + isAdmin: this.currentUser.admin, + siteSettingUrl: getURL( + "/admin/site_settings/category/plugins?filter=max_users_notified_per_group_mention" + ), + notificationLimit: + this.siteSettings.max_users_notified_per_group_mention, + group1: this.overMembersLimitGroupMentions[0], + group2: this.overMembersLimitGroupMentions[1], + }) ); - - if (this.currentUser.staff) { - notificationLimit = htmlSafe( - ` - ${notificationLimit} - ` - ); - } - - const settingLimit = I18n.t("chat.mention_warning.groups.users_limit", { - count: this.siteSettings.max_users_notified_per_group_mention, - }); - - if (this.hasOverMembersLimitGroupMentions <= 2) { - return htmlSafe( - I18n.t("chat.mention_warning.groups.too_many_members", { - group: this.overMembersLimitGroupMentions[0], - group_2: this.overMembersLimitGroupMentions[1], - count: this.overMembersLimitMentionsCount, - notification_limit: notificationLimit, - limit: settingLimit, - }) - ); - } else { - return htmlSafe( - I18n.t("chat.mention_warning.groups.too_many_members_multiple", { - group: this.overMembersLimitGroupMentions[0], - count: this.overMembersLimitMentionsCount - 1, //N others - notification_limit: notificationLimit, - limit: settingLimit, - }) - ); - } } } diff --git a/plugins/chat/assets/javascripts/discourse/components/chat-message-reaction.js b/plugins/chat/assets/javascripts/discourse/components/chat-message-reaction.js index a15cdc06b73..748143d2ea3 100644 --- a/plugins/chat/assets/javascripts/discourse/components/chat-message-reaction.js +++ b/plugins/chat/assets/javascripts/discourse/components/chat-message-reaction.js @@ -83,37 +83,91 @@ export default class ChatMessageReaction extends Component { @computed("reaction") get popoverContent() { - let usernames = this.reaction.users.mapBy("username").join(", "); - if (this.reaction.reacted) { - if (this.reaction.count === 1) { - return I18n.t("chat.reactions.only_you", { - emoji: this.reaction.emoji, - }); - } else if (this.reaction.count > 1 && this.reaction.count < 6) { - return I18n.t("chat.reactions.and_others", { - usernames, - emoji: this.reaction.emoji, - }); - } else if (this.reaction.count >= 6) { - return I18n.t("chat.reactions.you_others_and_more", { - usernames, - emoji: this.reaction.emoji, - more: this.reaction.count - 5, - }); - } - } else { - if (this.reaction.count > 0 && this.reaction.count < 6) { - return I18n.t("chat.reactions.only_others", { - usernames, - emoji: this.reaction.emoji, - }); - } else if (this.reaction.count >= 6) { - return I18n.t("chat.reactions.others_and_more", { - usernames, - emoji: this.reaction.emoji, - more: this.reaction.count - 5, - }); - } + return this.reaction.reacted + ? this._reactionTextWithSelf() + : this._reactionText(); + } + + _reactionTextWithSelf() { + const reactionCount = this.reaction.count; + + if (reactionCount === 0) { + return; } + + if (reactionCount === 1) { + return I18n.t("chat.reactions.only_you", { + emoji: this.reaction.emoji, + }); + } + + const maxUsernames = 4; + const usernames = this.reaction.users + .slice(0, maxUsernames) + .mapBy("username"); + + if (reactionCount === 2) { + return I18n.t("chat.reactions.you_and_single_user", { + emoji: this.reaction.emoji, + username: usernames.pop(), + }); + } + + // `-1` because the current user ("you") isn't included in `usernames` + const unnamedUserCount = reactionCount - usernames.length - 1; + + if (unnamedUserCount > 0) { + return I18n.t("chat.reactions.you_multiple_users_and_more", { + emoji: this.reaction.emoji, + commaSeparatedUsernames: this._joinUsernames(usernames), + count: unnamedUserCount, + }); + } + + return I18n.t("chat.reactions.you_and_multiple_users", { + emoji: this.reaction.emoji, + username: usernames.pop(), + commaSeparatedUsernames: this._joinUsernames(usernames), + }); + } + + _reactionText() { + const reactionCount = this.reaction.count; + + if (reactionCount === 0) { + return; + } + + const maxUsernames = 5; + const usernames = this.reaction.users + .slice(0, maxUsernames) + .mapBy("username"); + + if (reactionCount === 1) { + return I18n.t("chat.reactions.single_user", { + emoji: this.reaction.emoji, + username: usernames.pop(), + }); + } + + const unnamedUserCount = reactionCount - usernames.length; + + if (unnamedUserCount > 0) { + return I18n.t("chat.reactions.multiple_users_and_more", { + emoji: this.reaction.emoji, + commaSeparatedUsernames: this._joinUsernames(usernames), + count: unnamedUserCount, + }); + } + + return I18n.t("chat.reactions.multiple_users", { + emoji: this.reaction.emoji, + username: usernames.pop(), + commaSeparatedUsernames: this._joinUsernames(usernames), + }); + } + + _joinUsernames(usernames) { + return usernames.join(I18n.t("word_connector.comma")); } } diff --git a/plugins/chat/assets/javascripts/discourse/components/chat-message.js b/plugins/chat/assets/javascripts/discourse/components/chat-message.js index 1931f97db37..a8865c36510 100644 --- a/plugins/chat/assets/javascripts/discourse/components/chat-message.js +++ b/plugins/chat/assets/javascripts/discourse/components/chat-message.js @@ -411,49 +411,53 @@ export default class ChatMessage extends Component { } get mentionedCannotSeeText() { - return I18n.t("chat.mention_warning.cannot_see", { - username: this.mentionWarning?.cannot_see?.[0]?.username, - count: this.mentionWarning?.cannot_see?.length, - others: this._othersTranslation( - this.mentionWarning?.cannot_see?.length - 1 - ), - }); + return this._findTranslatedWarning( + "chat.mention_warning.cannot_see", + "chat.mention_warning.cannot_see_multiple", + { + username: this.mentionWarning?.cannot_see?.[0]?.username, + count: this.mentionWarning?.cannot_see?.length, + } + ); } get mentionedWithoutMembershipText() { - return I18n.t("chat.mention_warning.without_membership", { - username: this.mentionWarning?.without_membership?.[0]?.username, - count: this.mentionWarning?.without_membership?.length, - others: this._othersTranslation( - this.mentionWarning?.without_membership?.length - 1 - ), - }); + return this._findTranslatedWarning( + "chat.mention_warning.without_membership", + "chat.mention_warning.without_membership_multiple", + { + username: this.mentionWarning?.without_membership?.[0]?.username, + count: this.mentionWarning?.without_membership?.length, + } + ); } get groupsWithDisabledMentions() { - return I18n.t("chat.mention_warning.group_mentions_disabled", { - group_name: this.mentionWarning?.group_mentions_disabled?.[0], - count: this.mentionWarning?.group_mentions_disabled?.length, - others: this._othersTranslation( - this.mentionWarning?.group_mentions_disabled?.length - 1 - ), - }); + return this._findTranslatedWarning( + "chat.mention_warning.group_mentions_disabled", + "chat.mention_warning.group_mentions_disabled_multiple", + { + group_name: this.mentionWarning?.group_mentions_disabled?.[0], + count: this.mentionWarning?.group_mentions_disabled?.length, + } + ); } get groupsWithTooManyMembers() { - return I18n.t("chat.mention_warning.too_many_members", { - group_name: this.mentionWarning.groups_with_too_many_members?.[0], - count: this.mentionWarning.groups_with_too_many_members?.length, - others: this._othersTranslation( - this.mentionWarning.groups_with_too_many_members?.length - 1 - ), - }); + return this._findTranslatedWarning( + "chat.mention_warning.too_many_members", + "chat.mention_warning.too_many_members_multiple", + { + group_name: this.mentionWarning.groups_with_too_many_members?.[0], + count: this.mentionWarning.groups_with_too_many_members?.length, + } + ); } - _othersTranslation(othersCount) { - return I18n.t("chat.mention_warning.warning_multiple", { - count: othersCount, - }); + _findTranslatedWarning(oneKey, multipleKey, args) { + const translationKey = args.count === 1 ? oneKey : multipleKey; + args.count--; + return I18n.t(translationKey, args); } @action diff --git a/plugins/chat/assets/javascripts/discourse/components/chat-replying-indicator.js b/plugins/chat/assets/javascripts/discourse/components/chat-replying-indicator.js index 0e0f797e938..6c46c2e9101 100644 --- a/plugins/chat/assets/javascripts/discourse/components/chat-replying-indicator.js +++ b/plugins/chat/assets/javascripts/discourse/components/chat-replying-indicator.js @@ -33,14 +33,18 @@ export default Component.extend({ if (usernames.length < 4) { const lastUsername = usernames.pop(); - const commaSeparatedUsernames = usernames.join(", "); + const commaSeparatedUsernames = usernames.join( + I18n.t("word_connector.comma") + ); return I18n.t("chat.replying_indicator.multiple_users", { commaSeparatedUsernames, lastUsername, }); } - const commaSeparatedUsernames = usernames.slice(0, 2).join(", "); + const commaSeparatedUsernames = usernames + .slice(0, 2) + .join(I18n.t("word_connector.comma")); return I18n.t("chat.replying_indicator.many_users", { commaSeparatedUsernames, count: usernames.length - 2, diff --git a/plugins/chat/assets/javascripts/discourse/controllers/create-channel.js b/plugins/chat/assets/javascripts/discourse/controllers/create-channel.js index 0b6328bd886..0f0079de005 100644 --- a/plugins/chat/assets/javascripts/discourse/controllers/create-channel.js +++ b/plugins/chat/assets/javascripts/discourse/controllers/create-channel.js @@ -103,20 +103,40 @@ export default class CreateChannelController extends Controller.extend( _updateAutoJoinConfirmWarning(category, catPermissions) { const allowedGroups = catPermissions.allowed_groups; + let warning; if (catPermissions.private) { - const warningTranslationKey = - allowedGroups.length < 3 ? "warning_groups" : "warning_multiple_groups"; - - this.set( - "autoJoinWarning", - I18n.t(`chat.create_channel.auto_join_users.${warningTranslationKey}`, { - members_count: catPermissions.members_count, - group: escapeExpression(allowedGroups[0]), - group_2: escapeExpression(allowedGroups[1]), - count: allowedGroups.length, - }) - ); + switch (allowedGroups.length) { + case 1: + warning = I18n.t( + "chat.create_channel.auto_join_users.warning_1_group", + { + count: catPermissions.members_count, + group: escapeExpression(allowedGroups[0]), + } + ); + break; + case 2: + warning = I18n.t( + "chat.create_channel.auto_join_users.warning_2_groups", + { + count: catPermissions.members_count, + group1: escapeExpression(allowedGroups[0]), + group2: escapeExpression(allowedGroups[1]), + } + ); + break; + default: + warning = I18n.messageFormat( + "chat.create_channel.auto_join_users.warning_multiple_groups_MF", + { + groupCount: allowedGroups.length - 1, + userCount: catPermissions.members_count, + groupName: escapeExpression(allowedGroups[0]), + } + ); + break; + } } else { this.set( "autoJoinWarning", @@ -125,6 +145,8 @@ export default class CreateChannelController extends Controller.extend( }) ); } + + this.set("autoJoinWarning", warning); } _updatePermissionsHint(category) { @@ -136,20 +158,42 @@ export default class CreateChannelController extends Controller.extend( .then((catPermissions) => { this._updateAutoJoinConfirmWarning(category, catPermissions); const allowedGroups = catPermissions.allowed_groups; - const translationKey = - allowedGroups.length < 3 ? "hint_groups" : "hint_multiple_groups"; + const settingLink = `/c/${escapeExpression(fullSlug)}/edit/security`; + let hint; - this.set( - "categoryPermissionsHint", - htmlSafe( - I18n.t(`chat.create_channel.choose_category.${translationKey}`, { - link: `/c/${escapeExpression(fullSlug)}/edit/security`, - hint: escapeExpression(allowedGroups[0]), - hint_2: escapeExpression(allowedGroups[1]), - count: allowedGroups.length, - }) - ) - ); + switch (allowedGroups.length) { + case 1: + hint = I18n.t( + "chat.create_channel.choose_category.hint_1_group", + { + settingLink, + group: escapeExpression(allowedGroups[0]), + } + ); + break; + case 2: + hint = I18n.t( + "chat.create_channel.choose_category.hint_2_groups", + { + settingLink, + group1: escapeExpression(allowedGroups[0]), + group2: escapeExpression(allowedGroups[1]), + } + ); + break; + default: + hint = I18n.t( + "chat.create_channel.choose_category.hint_multiple_groups", + { + settingLink, + group: escapeExpression(allowedGroups[0]), + count: allowedGroups.length - 1, + } + ); + break; + } + + this.set("categoryPermissionsHint", htmlSafe(hint)); }); } else { this.set("categoryPermissionsHint", DEFAULT_HINT); diff --git a/plugins/chat/assets/javascripts/discourse/initializers/chat-sidebar.js b/plugins/chat/assets/javascripts/discourse/initializers/chat-sidebar.js index 1cb408dbaba..56fff731a30 100644 --- a/plugins/chat/assets/javascripts/discourse/initializers/chat-sidebar.js +++ b/plugins/chat/assets/javascripts/discourse/initializers/chat-sidebar.js @@ -223,8 +223,8 @@ export default { } get title() { - return I18n.t("chat.placeholder_others", { - messageRecipient: this.channel.escapedTitle, + return I18n.t("chat.placeholder_channel", { + channelName: this.channel.escapedTitle, }); } diff --git a/plugins/chat/assets/javascripts/discourse/models/chat-channel.js b/plugins/chat/assets/javascripts/discourse/models/chat-channel.js index c38b83d5650..c6e75e9edd3 100644 --- a/plugins/chat/assets/javascripts/discourse/models/chat-channel.js +++ b/plugins/chat/assets/javascripts/discourse/models/chat-channel.js @@ -1,5 +1,4 @@ import RestModel from "discourse/models/rest"; -import I18n from "I18n"; import User from "discourse/models/user"; import UserChatChannelMembership from "discourse/plugins/chat/discourse/models/user-chat-channel-membership"; import { ajax } from "discourse/lib/ajax"; @@ -21,19 +20,6 @@ export const CHANNEL_STATUSES = { archived: "archived", }; -export function channelStatusName(channelStatus) { - switch (channelStatus) { - case CHANNEL_STATUSES.open: - return I18n.t("chat.channel_status.open"); - case CHANNEL_STATUSES.readOnly: - return I18n.t("chat.channel_status.read_only"); - case CHANNEL_STATUSES.closed: - return I18n.t("chat.channel_status.closed"); - case CHANNEL_STATUSES.archived: - return I18n.t("chat.channel_status.archived"); - } -} - export function channelStatusIcon(channelStatus) { if (channelStatus === CHANNEL_STATUSES.open) { return null; diff --git a/plugins/chat/config/locales/client.en.yml b/plugins/chat/config/locales/client.en.yml index 87a89e3dd3d..d3d47e6f853 100644 --- a/plugins/chat/config/locales/client.en.yml +++ b/plugins/chat/config/locales/client.en.yml @@ -106,46 +106,96 @@ en: new_messages: "new messages" mention_warning: dismiss: "dismiss" - cannot_see: - one: "%{username} cannot access this channel and was not notified." - other: "%{username} and %{others} cannot access this channel and were not notified." + cannot_see: "%{username} can't access this channel and was not notified." + cannot_see_multiple: + one: "%{username} and %{count} other user cannot access this channel and were not notified." + other: "%{username} and %{count} other users cannot access this channel and were not notified." invitations_sent: one: "Invitation sent" other: "Invitations sent" invite: "Invite to channel" - without_membership: - one: "%{username} has not joined this channel." - other: "%{username} and %{others} have not joined this channel." - group_mentions_disabled: - one: "%{group_name} doesn't allow mentions" - other: "%{group_name} and %{others} doesn't allow mentions" - too_many_members: - one: "%{group_name} has too many members. No one was notified" - other: "%{group_name} and %{others} have too many members. No one was notified" - warning_multiple: - one: "%{count} other" - other: "%{count} others" - + without_membership: "%{username} has not joined this channel." + without_membership_multiple: + one: "%{username} and %{count} other user have not joined this channel." + other: "%{username} and %{count} other users have not joined this channel." + group_mentions_disabled: "%{group_name} doesn't allow mentions." + group_mentions_disabled_multiple: + one: "%{group_name} and %{count} other group don't allow mentions." + other: "%{group_name} and %{count} other groups don't allow mentions." + too_many_members: "%{group_name} has too many members. No one was notified." + too_many_members_multiple: + one: "%{group_name} and %{count} other group have too many members. No one was notified." + other: "%{group_name} and %{count} other groups have too many members. No one was notified." groups: header: some: "Some users won't be notified" all: "Nobody will be notified" - unreachable: - one: "@%{group} doesn't allow mentions" - other: "@%{group} and @%{group_2} doesn't allow mentions" - unreachable_multiple: "@%{group} and %{count} others doesn't allow mentions" - too_many_members: - one: "Mentioning @%{group} exceeds the %{notification_limit} of %{limit}" - other: "Mentioning both @%{group} or @%{group_2} exceeds the %{notification_limit} of %{limit}" - too_many_members_multiple: "These %{count} groups exceed the %{notification_limit} of %{limit}" - users_limit: - one: "%{count} user" - other: "%{count} users" - notification_limit: "notification limit" - too_many_mentions: "This message exceeds the %{notification_limit} of %{limit}" - mentions_limit: - one: "%{count} mention" - other: "%{count} mentions" + unreachable_1: "@%{group} doesn't allow mentions." + unreachable_2: "@%{group1} and @%{group2} don't allow mentions." + unreachable_multiple: + one: "@%{group} and %{count} other group don't allow mentions." + other: "@%{group} and %{count} other groups don't allow mentions." + too_many_members_MF: | + { groupCount, plural, + =1 { + { isAdmin, select, + true { + { notificationLimit, plural, + one {Mentioning @{group1} exceeds the notification limit of # user.} + other {Mentioning @{group1} exceeds the notification limit of # users.} + } + } + false { + { notificationLimit, plural, + one {Mentioning @{group1} exceeds the notification limit of # user.} + other {Mentioning @{group1} exceeds the notification limit of # users.} + } + } + other {} + } + } + =2 { + { isAdmin, select, + true { + { notificationLimit, plural, + one {Mentioning @{group1} and @{group2} exceeds the notification limit of # user.} + other {Mentioning @{group1} and @{group2} exceeds the notification limit of # users.} + } + } + false { + { notificationLimit, plural, + one {Mentioning @{group1} and @{group2} exceeds the notification limit of # user.} + other {Mentioning @{group1} and @{group2} exceeds the notification limit of # users.} + } + } + other {} + } + } + other { + { isAdmin, select, + true { + { notificationLimit, plural, + one {Mentioning these {groupCount} groups exceeds the notification limit of # user.} + other {Mentioning these {groupCount} groups exceeds the notification limit of # users.} + } + } + false { + { notificationLimit, plural, + one {Mentioning these {groupCount} groups exceeds the notification limit of # user.} + other {Mentioning these {groupCount} groups exceeds the notification limit of # users.} + } + } + other {} + } + } + } + too_many_mentions: + one: "This message exceeds the notification limit of %{count} mention." + other: "This message exceeds the notification limit of %{count} mentions." + too_many_mentions_admin: + one: 'This message exceeds the notification limit of %{count} mention.' + other: 'This message exceeds the notification limit of %{count} mentions.' + aria_roles: header: "Chat header" composer: "Chat composer" @@ -163,10 +213,15 @@ en: close_full_page: "Close full-screen chat" open_message: "Open message in chat" placeholder_self: "Jot something down" - placeholder_others: "Chat with %{messageRecipient}" - placeholder_new_message_disallowed: "Channel is %{status}, you cannot send new messages right now." + placeholder_channel: "Chat with %{channelName}" + placeholder_users: "Chat with %{commaSeparatedNames}" + placeholder_new_message_disallowed: + archived: "Channel is archived, you cannot send new messages right now." + closed: "Channel is closed, you cannot send new messages right now." + read_only: "Channel is read only, you cannot send new messages right now." placeholder_silenced: "You cannot send messages at this time." - placeholder_start_conversation: Start a conversation with %{usernames} + placeholder_start_conversation: "Start a conversation with ..." + placeholder_start_conversation_users: "Start a conversation with %{commaSeparatedUsernames}" remove_upload: "Remove file" react: "React with emoji" reply: "Reply" @@ -276,18 +331,36 @@ en: create_channel: auto_join_users: public_category_warning: "%{category} is a public category. Automatically add all recently active users to this channel?" - warning_groups: - one: Automatically add %{members_count} users from %{group}? - other: Automatically add %{members_count} users from %{group} and %{group_2}? - warning_multiple_groups: Automatically add %{members_count} users from %{group_1} and %{count} others? + warning_1_group: + one: "Automatically add %{count} user from %{group}?" + other: "Automatically add %{count} users from %{group}?" + warning_2_groups: + one: "Automatically add %{count} user from %{group1} and %{group2}?" + other: "Automatically add %{count} users from %{group1} and %{group2}?" + warning_multiple_groups_MF: | + { groupCount, plural, + one { + { userCount, plural, + one {Automatically add {userCount} user from {groupName} and {groupCount} other group?} + other {Automatically add {userCount} users from {groupName} and {groupCount} other group?} + } + } + other { + { userCount, plural, + one {Automatically add {userCount} user from {groupName} and {groupCount} other groups?} + other {Automatically add {userCount} users from {groupName} and {groupCount} other groups?} + } + } + } choose_category: label: "Choose a category" none: "select one..." default_hint: Manage access by visiting %{category} security settings - hint_groups: - one: Users in %{hint} will have access to this channel per the security settings - other: Users in %{hint} and %{hint_2} will have access to this channel per the security settings - hint_multiple_groups: Users in %{hint_1} and %{count} other groups will have access to this channel per the security settings + hint_1_group: 'Users in %{group} will have access to this channel per the security settings' + hint_2_groups: 'Users in %{group1} and %{group2} will have access to this channel per the security settings' + hint_multiple_groups: + one: 'Users in %{group} and %{count} other group will have access to this channel per the security settings' + other: 'Users in %{group} and %{count} other groups will have access to this channel per the security settings' create: "Create channel" description: "Description (optional)" name: "Channel name" @@ -303,10 +376,16 @@ en: reactions: only_you: "You reacted with :%{emoji}:" - and_others: "You, %{usernames} reacted with :%{emoji}:" - only_others: "%{usernames} reacted with :%{emoji}:" - others_and_more: "%{usernames} and %{more} others reacted with :%{emoji}:" - you_others_and_more: "You, %{usernames} and %{more} others reacted with :%{emoji}:" + you_and_single_user: "You and %{username} reacted with :%{emoji}:" + you_and_multiple_users: "You, %{commaSeparatedUsernames} and %{username} reacted with :%{emoji}:" + you_multiple_users_and_more: + one: "You, %{commaSeparatedUsernames} and %{count} other reacted with :%{emoji}:" + other: "You, %{commaSeparatedUsernames} and %{count} others reacted with :%{emoji}:" + single_user: "%{username} reacted with :%{emoji}:" + multiple_users: "%{commaSeparatedUsernames} and %{username} reacted with :%{emoji}:" + multiple_users_and_more: + one: "%{commaSeparatedUsernames} and %{count} other reacted with :%{emoji}:" + other: "%{commaSeparatedUsernames} and %{count} others reacted with :%{emoji}:" composer: toggle_toolbar: "Toggle toolbar" @@ -465,11 +544,13 @@ en: direct: 'mentioned you in "%{channel}"' direct_html: '%{username} mentioned you in "%{channel}"' other_plain: 'mentioned %{identifier} in "%{channel}"' + # %{identifier} is either @here or @all other_html: '%{username} mentioned %{identifier} in "%{channel}"' direct_message_chat_mention: direct: "mentioned you in personal chat" direct_html: "%{username} mentioned you in personal chat" other_plain: "mentioned %{identifier} in personal chat" + # %{identifier} is either @here or @all other_html: "%{username} mentioned %{identifier} in personal chat" chat_message: "New chat message" chat_quoted: "%{username} quoted your chat message" diff --git a/plugins/chat/config/locales/server.en.yml b/plugins/chat/config/locales/server.en.yml index 89142083fbf..b6b312d6c53 100644 --- a/plugins/chat/config/locales/server.en.yml +++ b/plugins/chat/config/locales/server.en.yml @@ -49,16 +49,26 @@ en: deleted_chat_username: deleted errors: channel_exists_for_category: "A channel already exists for this category and name" - channel_new_message_disallowed: "The channel is %{status}, no new messages can be sent" - channel_modify_message_disallowed: "The channel is %{status}, no messages can be edited or deleted" + channel_new_message_disallowed: + archived: "The channel is archived, no new messages can be sent" + closed: "The channel is closed, no new messages can be sent" + read_only: "The channel is read only, no new messages can be sent" + channel_modify_message_disallowed: + archived: "The channel is archived, no messages can be edited or deleted" + closed: "The channel is closed, no messages can be edited or deleted" + read_only: "The channel is read only, no messages can be edited or deleted" user_cannot_send_message: "You cannot send messages at this time." rate_limit_exceeded: "Exceeded the limit of chat messages that can be sent within 30 seconds" auto_silence_from_flags: "Chat message flagged with score high enough to silence user." channel_cannot_be_archived: "The channel cannot be archived at this time, it must be either closed or open to archive." duplicate_message: "You posted an identical message too recently." delete_channel_failed: "Delete channel failed, please try again." - minimum_length_not_met: "Message is too short, must have a minimum of %{minimum} characters." - message_too_long: "Message is too long, messages must be a maximum of %{maximum} characters." + minimum_length_not_met: + one: "Message is too short, must have a minimum of %{count} character." + other: "Message is too short, must have a minimum of %{count} characters." + message_too_long: + one: "Message is too long, messages must be a maximum of %{count} characters." + other: "Message is too long, messages must be a maximum of %{count} characters." draft_too_long: "Draft is too long." max_reactions_limit_reached: "New reactions are not allowed on this message." message_move_invalid_channel: "The source and destination channel must be public channels." @@ -70,8 +80,9 @@ en: actor_disallowed_dms: "You have chosen to prevent users from sending you private and direct messages, so you cannot create new direct messages." actor_preventing_target_user_from_dm: "You have chosen to prevent %{username} from sending you private and direct messages, so you cannot create new direct messages to them." user_cannot_send_direct_messages: "Sorry, you cannot send direct messages." + over_chat_max_direct_message_users_allow_self: "You can only create a direct message with yourself." over_chat_max_direct_message_users: - one: "You can only create a direct message with yourself." + one: "You can't create a direct message with more than %{count} other user." other: "You can't create a direct message with more than %{count} other users." original_message_not_found: "The ancestor of the message you are replying cannot be found or has been deleted." reviewables: @@ -110,20 +121,17 @@ en: transcript_title: "Transcript of previous messages in %{channel_name}" transcript_body: "To give you more context, we included a transcript of the previous messages in this conversation (up to ten):\n\n%{transcript}" channel: - statuses: - read_only: "Read Only" - archived: "Archived" - closed: "Closed" - open: "Open" archive: first_post_raw: "This topic is an archive of the [%{channel_name}](%{channel_url}) chat channel." messages_moved: one: "@%{acting_username} moved a message to the [%{channel_name}](%{first_moved_message_url}) channel." other: "@%{acting_username} moved %{count} messages to the [%{channel_name}](%{first_moved_message_url}) channel." dm_title: - single_user: "%{user}" - multi_user: "%{users}" - multi_user_truncated: "%{users} and %{leftover} others" + single_user: "%{username}" + multi_user: "%{comma_separated_usernames}" + multi_user_truncated: + one: "%{comma_separated_usernames} and %{count} other" + other: "%{comma_separated_usernames} and %{count} others" category_channel: errors: diff --git a/plugins/chat/lib/chat_message_creator.rb b/plugins/chat/lib/chat_message_creator.rb index 08b5a711a08..6cd55f2fedb 100644 --- a/plugins/chat/lib/chat_message_creator.rb +++ b/plugins/chat/lib/chat_message_creator.rb @@ -82,10 +82,7 @@ class Chat::ChatMessageCreator raise StandardError.new(I18n.t("chat.errors.user_cannot_send_direct_messages")) else raise StandardError.new( - I18n.t( - "chat.errors.channel_new_message_disallowed", - status: @chat_channel.status_name, - ), + I18n.t("chat.errors.channel_new_message_disallowed.#{@chat_channel.status}"), ) end end diff --git a/plugins/chat/lib/chat_message_reactor.rb b/plugins/chat/lib/chat_message_reactor.rb index 9e7260f7979..8815fa135e3 100644 --- a/plugins/chat/lib/chat_message_reactor.rb +++ b/plugins/chat/lib/chat_message_reactor.rb @@ -53,10 +53,7 @@ class Chat::ChatMessageReactor raise Discourse::InvalidAccess.new( nil, nil, - custom_message: "chat.errors.channel_modify_message_disallowed", - custom_message_params: { - status: @chat_channel.status_name, - }, + custom_message: "chat.errors.channel_modify_message_disallowed.#{@chat_channel.status}", ) end diff --git a/plugins/chat/lib/chat_message_updater.rb b/plugins/chat/lib/chat_message_updater.rb index 79ecfed4e2c..43bb028c40d 100644 --- a/plugins/chat/lib/chat_message_updater.rb +++ b/plugins/chat/lib/chat_message_updater.rb @@ -51,10 +51,7 @@ class Chat::ChatMessageUpdater def validate_channel_status! return if @guardian.can_modify_channel_message?(@chat_channel) raise StandardError.new( - I18n.t( - "chat.errors.channel_modify_message_disallowed", - status: @chat_channel.status_name, - ), + I18n.t("chat.errors.channel_modify_message_disallowed.#{@chat_channel.status}"), ) end diff --git a/plugins/chat/lib/direct_message_channel_creator.rb b/plugins/chat/lib/direct_message_channel_creator.rb index 63342e3cfb7..505801d42fe 100644 --- a/plugins/chat/lib/direct_message_channel_creator.rb +++ b/plugins/chat/lib/direct_message_channel_creator.rb @@ -30,12 +30,16 @@ module Chat::DirectMessageChannelCreator target_users = target_users.reject { |user| user.id == acting_user.id } if !acting_user.staff? && target_users.size > SiteSetting.chat_max_direct_message_users - raise NotAllowed.new( - I18n.t( - "chat.errors.over_chat_max_direct_message_users", - count: SiteSetting.chat_max_direct_message_users + 1, # +1 for the acting_user - ), - ) + if SiteSetting.chat_max_direct_message_users == 0 + raise NotAllowed.new(I18n.t("chat.errors.over_chat_max_direct_message_users_allow_self")) + else + raise NotAllowed.new( + I18n.t( + "chat.errors.over_chat_max_direct_message_users", + count: SiteSetting.chat_max_direct_message_users + 1, # +1 for the acting_user + ), + ) + end end end diff --git a/plugins/chat/spec/components/chat_message_creator_spec.rb b/plugins/chat/spec/components/chat_message_creator_spec.rb index de4cf37173a..798149ece86 100644 --- a/plugins/chat/spec/components/chat_message_creator_spec.rb +++ b/plugins/chat/spec/components/chat_message_creator_spec.rb @@ -64,7 +64,7 @@ describe Chat::ChatMessageCreator do expect(creator.error.message).to match( I18n.t( "chat.errors.minimum_length_not_met", - { minimum: SiteSetting.chat_minimum_message_length }, + { count: SiteSetting.chat_minimum_message_length }, ), ) end @@ -79,10 +79,7 @@ describe Chat::ChatMessageCreator do ) expect(creator.failed?).to eq(true) expect(creator.error.message).to match( - I18n.t( - "chat.errors.message_too_long", - { maximum: SiteSetting.chat_maximum_message_length }, - ), + I18n.t("chat.errors.message_too_long", { count: SiteSetting.chat_maximum_message_length }), ) end @@ -866,10 +863,7 @@ describe Chat::ChatMessageCreator do creator = create_message(user1) expect(creator.failed?).to eq(true) expect(creator.error.message).to eq( - I18n.t( - "chat.errors.channel_new_message_disallowed", - status: public_chat_channel.status_name, - ), + I18n.t("chat.errors.channel_new_message_disallowed.closed"), ) end @@ -885,18 +879,12 @@ describe Chat::ChatMessageCreator do creator = create_message(user1) expect(creator.failed?).to eq(true) expect(creator.error.message).to eq( - I18n.t( - "chat.errors.channel_new_message_disallowed", - status: public_chat_channel.status_name, - ), + I18n.t("chat.errors.channel_new_message_disallowed.read_only"), ) creator = create_message(admin1) expect(creator.failed?).to eq(true) expect(creator.error.message).to eq( - I18n.t( - "chat.errors.channel_new_message_disallowed", - status: public_chat_channel.status_name, - ), + I18n.t("chat.errors.channel_new_message_disallowed.read_only"), ) end end @@ -908,18 +896,12 @@ describe Chat::ChatMessageCreator do creator = create_message(user1) expect(creator.failed?).to eq(true) expect(creator.error.message).to eq( - I18n.t( - "chat.errors.channel_new_message_disallowed", - status: public_chat_channel.status_name, - ), + I18n.t("chat.errors.channel_new_message_disallowed.archived"), ) creator = create_message(admin1) expect(creator.failed?).to eq(true) expect(creator.error.message).to eq( - I18n.t( - "chat.errors.channel_new_message_disallowed", - status: public_chat_channel.status_name, - ), + I18n.t("chat.errors.channel_new_message_disallowed.archived"), ) end end diff --git a/plugins/chat/spec/components/chat_message_updater_spec.rb b/plugins/chat/spec/components/chat_message_updater_spec.rb index 39c00726bc6..62de1bd9e3f 100644 --- a/plugins/chat/spec/components/chat_message_updater_spec.rb +++ b/plugins/chat/spec/components/chat_message_updater_spec.rb @@ -62,7 +62,7 @@ describe Chat::ChatMessageUpdater do expect(updater.error.message).to match( I18n.t( "chat.errors.minimum_length_not_met", - { minimum: SiteSetting.chat_minimum_message_length }, + { count: SiteSetting.chat_minimum_message_length }, ), ) expect(chat_message.reload.message).to eq(og_message) @@ -82,7 +82,7 @@ describe Chat::ChatMessageUpdater do ) expect(updater.failed?).to eq(true) expect(updater.error.message).to match( - I18n.t("chat.errors.message_too_long", { maximum: SiteSetting.chat_maximum_message_length }), + I18n.t("chat.errors.message_too_long", { count: SiteSetting.chat_maximum_message_length }), ) expect(chat_message.reload.message).to eq(og_message) end @@ -528,10 +528,7 @@ describe Chat::ChatMessageUpdater do updater = update_message(user1) expect(updater.failed?).to eq(true) expect(updater.error.message).to eq( - I18n.t( - "chat.errors.channel_modify_message_disallowed", - status: public_chat_channel.status_name, - ), + I18n.t("chat.errors.channel_modify_message_disallowed.closed"), ) end @@ -548,18 +545,12 @@ describe Chat::ChatMessageUpdater do updater = update_message(user1) expect(updater.failed?).to eq(true) expect(updater.error.message).to eq( - I18n.t( - "chat.errors.channel_modify_message_disallowed", - status: public_chat_channel.status_name, - ), + I18n.t("chat.errors.channel_modify_message_disallowed.read_only"), ) updater = update_message(admin1) expect(updater.failed?).to eq(true) expect(updater.error.message).to eq( - I18n.t( - "chat.errors.channel_modify_message_disallowed", - status: public_chat_channel.status_name, - ), + I18n.t("chat.errors.channel_modify_message_disallowed.read_only"), ) end end @@ -571,18 +562,12 @@ describe Chat::ChatMessageUpdater do updater = update_message(user1) expect(updater.failed?).to eq(true) expect(updater.error.message).to eq( - I18n.t( - "chat.errors.channel_modify_message_disallowed", - status: public_chat_channel.status_name, - ), + I18n.t("chat.errors.channel_modify_message_disallowed.archived"), ) updater = update_message(admin1) expect(updater.failed?).to eq(true) expect(updater.error.message).to eq( - I18n.t( - "chat.errors.channel_modify_message_disallowed", - status: public_chat_channel.status_name, - ), + I18n.t("chat.errors.channel_modify_message_disallowed.archived"), ) end end diff --git a/plugins/chat/spec/lib/direct_message_channel_creator_spec.rb b/plugins/chat/spec/lib/direct_message_channel_creator_spec.rb index ff3863ca3a7..0ae71e0c462 100644 --- a/plugins/chat/spec/lib/direct_message_channel_creator_spec.rb +++ b/plugins/chat/spec/lib/direct_message_channel_creator_spec.rb @@ -212,7 +212,7 @@ describe Chat::DirectMessageChannelCreator do subject.create!(acting_user: user_1, target_users: [user_1, user_2]) }.to raise_error( Chat::DirectMessageChannelCreator::NotAllowed, - I18n.t("chat.errors.over_chat_max_direct_message_users", count: 1), + I18n.t("chat.errors.over_chat_max_direct_message_users_allow_self"), ) end end diff --git a/plugins/chat/spec/models/direct_message_spec.rb b/plugins/chat/spec/models/direct_message_spec.rb index 9e44e51cd5d..8e8443cf90d 100644 --- a/plugins/chat/spec/models/direct_message_spec.rb +++ b/plugins/chat/spec/models/direct_message_spec.rb @@ -20,7 +20,8 @@ describe DirectMessage do expect(direct_message.chat_channel_title_for_user(chat_channel, user1)).to eq( I18n.t( "chat.channel.dm_title.multi_user", - users: [user3, user2].map { |u| "@#{u.username}" }.join(", "), + comma_separated_usernames: + [user3, user2].map { |u| "@#{u.username}" }.join(I18n.t("word_connector.comma")), ), ) end @@ -36,8 +37,12 @@ describe DirectMessage do expect(direct_message.chat_channel_title_for_user(chat_channel, user1)).to eq( I18n.t( "chat.channel.dm_title.multi_user_truncated", - users: users[1..5].sort_by(&:username).map { |u| "@#{u.username}" }.join(", "), - leftover: 2, + comma_separated_usernames: + users[1..5] + .sort_by(&:username) + .map { |u| "@#{u.username}" } + .join(I18n.t("word_connector.comma")), + count: 2, ), ) end @@ -46,7 +51,7 @@ describe DirectMessage do direct_message = Fabricate(:direct_message, users: [user1, user2]) expect(direct_message.chat_channel_title_for_user(chat_channel, user1)).to eq( - I18n.t("chat.channel.dm_title.single_user", user: "@#{user2.username}"), + I18n.t("chat.channel.dm_title.single_user", username: "@#{user2.username}"), ) end @@ -54,7 +59,7 @@ describe DirectMessage do direct_message = Fabricate(:direct_message, users: [user1]) expect(direct_message.chat_channel_title_for_user(chat_channel, user1)).to eq( - I18n.t("chat.channel.dm_title.single_user", user: "@#{user1.username}"), + I18n.t("chat.channel.dm_title.single_user", username: "@#{user1.username}"), ) end diff --git a/plugins/chat/spec/requests/chat_controller_spec.rb b/plugins/chat/spec/requests/chat_controller_spec.rb index 9f1729837d0..d0fcbfd19ab 100644 --- a/plugins/chat/spec/requests/chat_controller_spec.rb +++ b/plugins/chat/spec/requests/chat_controller_spec.rb @@ -320,7 +320,7 @@ RSpec.describe Chat::ChatController do post "/chat/#{chat_channel.id}.json", params: { message: message } expect(response.status).to eq(422) expect(response.parsed_body["errors"]).to include( - I18n.t("chat.errors.channel_new_message_disallowed", status: chat_channel.status_name), + I18n.t("chat.errors.channel_new_message_disallowed.closed"), ) end @@ -336,7 +336,7 @@ RSpec.describe Chat::ChatController do post "/chat/#{chat_channel.id}.json", params: { message: message } expect(response.status).to eq(422) expect(response.parsed_body["errors"]).to include( - I18n.t("chat.errors.channel_new_message_disallowed", status: chat_channel.status_name), + I18n.t("chat.errors.channel_new_message_disallowed.read_only"), ) end @@ -903,7 +903,7 @@ RSpec.describe Chat::ChatController do }.not_to change { chat_message.reactions.where(user: user, emoji: emoji).count } expect(response.status).to eq(403) expect(response.parsed_body["errors"]).to include( - I18n.t("chat.errors.channel_modify_message_disallowed", status: chat_channel.status_name), + I18n.t("chat.errors.channel_modify_message_disallowed.#{chat_channel.status}"), ) end diff --git a/plugins/chat/spec/requests/incoming_chat_webhooks_controller_spec.rb b/plugins/chat/spec/requests/incoming_chat_webhooks_controller_spec.rb index a8a54334718..6c049a1f050 100644 --- a/plugins/chat/spec/requests/incoming_chat_webhooks_controller_spec.rb +++ b/plugins/chat/spec/requests/incoming_chat_webhooks_controller_spec.rb @@ -55,7 +55,7 @@ RSpec.describe Chat::IncomingChatWebhooksController do }.not_to change { ChatMessage.where(chat_channel: chat_channel).count } expect(response.status).to eq(422) expect(response.parsed_body["errors"]).to include( - I18n.t("chat.errors.channel_new_message_disallowed", status: chat_channel.status_name), + I18n.t("chat.errors.channel_new_message_disallowed.read_only"), ) end diff --git a/plugins/chat/spec/system/closed_channel_spec.rb b/plugins/chat/spec/system/closed_channel_spec.rb index 7237db225fe..5c19e7564c6 100644 --- a/plugins/chat/spec/system/closed_channel_spec.rb +++ b/plugins/chat/spec/system/closed_channel_spec.rb @@ -30,11 +30,7 @@ RSpec.describe "Closed channel", type: :system, js: true do chat.visit_channel(channel_1) expect(page).to have_field( - placeholder: - I18n.t( - "js.chat.placeholder_new_message_disallowed", - status: I18n.t("js.chat.channel_status.closed").downcase, - ), + placeholder: I18n.t("js.chat.placeholder_new_message_disallowed.closed"), disabled: true, ) end @@ -54,7 +50,7 @@ RSpec.describe "Closed channel", type: :system, js: true do chat.visit_channel(channel_1) expect(page).to have_no_field( - placeholder: I18n.t("js.chat.placeholder_new_message_disallowed"), + placeholder: I18n.t("js.chat.placeholder_new_message_disallowed.closed"), disabled: true, ) end diff --git a/plugins/chat/spec/system/create_channel_spec.rb b/plugins/chat/spec/system/create_channel_spec.rb index 294683dec1c..27a0de52dc5 100644 --- a/plugins/chat/spec/system/create_channel_spec.rb +++ b/plugins/chat/spec/system/create_channel_spec.rb @@ -69,7 +69,7 @@ RSpec.describe "Create channel", type: :system, js: true do end end - context "when category has a malicous group name" do + context "when category has a malicious group name" do fab!(:group_1) do group = Group.new(name: "") group.save(validate: false) diff --git a/plugins/chat/spec/system/jit_messages_spec.rb b/plugins/chat/spec/system/jit_messages_spec.rb index d5e0a2e7df4..0f0628b1ac9 100644 --- a/plugins/chat/spec/system/jit_messages_spec.rb +++ b/plugins/chat/spec/system/jit_messages_spec.rb @@ -22,7 +22,7 @@ RSpec.describe "JIT messages", type: :system, js: true do channel.send_message("hi @#{other_user.username}") expect(page).to have_content( - I18n.t("js.chat.mention_warning.without_membership.one", username: other_user.username), + I18n.t("js.chat.mention_warning.without_membership", username: other_user.username), wait: 5, ) end @@ -44,7 +44,7 @@ RSpec.describe "JIT messages", type: :system, js: true do channel.send_message("hi @#{other_user.username}") expect(page).to have_content( - I18n.t("js.chat.mention_warning.cannot_see.one", username: other_user.username), + I18n.t("js.chat.mention_warning.cannot_see", username: other_user.username), wait: 5, ) end @@ -61,7 +61,7 @@ RSpec.describe "JIT messages", type: :system, js: true do channel.send_message("hi @#{group_1.name}") expect(page).to have_content( - I18n.t("js.chat.mention_warning.group_mentions_disabled.one", group_name: group_1.name), + I18n.t("js.chat.mention_warning.group_mentions_disabled", group_name: group_1.name), wait: 5, ) end diff --git a/plugins/chat/spec/system/read_only_spec.rb b/plugins/chat/spec/system/read_only_spec.rb index 3610e55020e..ffadc0dce03 100644 --- a/plugins/chat/spec/system/read_only_spec.rb +++ b/plugins/chat/spec/system/read_only_spec.rb @@ -30,7 +30,7 @@ RSpec.describe "Read only", type: :system, js: true do chat.visit_channel(channel_1) expect(page).to have_field( - placeholder: I18n.t("js.chat.placeholder_new_message_disallowed", status: "read only"), + placeholder: I18n.t("js.chat.placeholder_new_message_disallowed.read_only"), disabled: true, ) end @@ -50,7 +50,7 @@ RSpec.describe "Read only", type: :system, js: true do chat.visit_channel(channel_1) expect(page).to have_field( - placeholder: I18n.t("js.chat.placeholder_new_message_disallowed", status: "read only"), + placeholder: I18n.t("js.chat.placeholder_new_message_disallowed.read_only"), disabled: true, ) end diff --git a/script/i18n_lint.rb b/script/i18n_lint.rb index f3f96abf87d..794b07b34ae 100755 --- a/script/i18n_lint.rb +++ b/script/i18n_lint.rb @@ -37,8 +37,6 @@ class LocaleFileValidator "Pluralized strings must have only the sub-keys 'one' and 'other'.\nThe following keys have missing or additional keys:", invalid_one_keys: "The following keys contain the number 1 instead of the interpolation key %{count}:", - invalid_message_format_one_key: - "The following keys use 'one {1 foo}' instead of the generic 'one {# foo}':", } PLURALIZATION_KEYS = %w[zero one two few many other] @@ -88,7 +86,6 @@ class LocaleFileValidator @errors[:invalid_relative_links] = [] @errors[:invalid_relative_image_sources] = [] @errors[:invalid_interpolation_key_format] = [] - @errors[:invalid_message_format_one_key] = [] each_translation(yaml) do |key, value| @errors[:invalid_relative_links] << key if value.match?(%r{href\s*=\s*["']/[^/]|\]\(/[^/]}i) @@ -98,10 +95,6 @@ class LocaleFileValidator if value.match?(/{{.+?}}/) && !key.end_with?("_MF") @errors[:invalid_interpolation_key_format] << key end - - if key.end_with?("_MF") && value.match?(/one {.*?1.*?}/) - @errors[:invalid_message_format_one_key] << key - end end end diff --git a/spec/models/translation_override_spec.rb b/spec/models/translation_override_spec.rb index 20f3200b430..d8c8a5c3971 100644 --- a/spec/models/translation_override_spec.rb +++ b/spec/models/translation_override_spec.rb @@ -27,6 +27,7 @@ RSpec.describe TranslationOverride do I18n.t( "activerecord.errors.models.translation_overrides.attributes.value.invalid_interpolation_keys", keys: "key, omg", + count: 2, ), ) end @@ -61,6 +62,7 @@ RSpec.describe TranslationOverride do I18n.t( "activerecord.errors.models.translation_overrides.attributes.value.invalid_interpolation_keys", keys: "something", + count: 1, ), ) end @@ -78,6 +80,7 @@ RSpec.describe TranslationOverride do I18n.t( "activerecord.errors.models.translation_overrides.attributes.value.invalid_interpolation_keys", keys: "topic_title_url_encoded", + count: 1, ), ) end @@ -132,6 +135,7 @@ RSpec.describe TranslationOverride do I18n.t( "activerecord.errors.models.translation_overrides.attributes.value.invalid_interpolation_keys", keys: "key3, key4", + count: 2, ), ) end diff --git a/spec/requests/admin/email_templates_controller_spec.rb b/spec/requests/admin/email_templates_controller_spec.rb index e9e15341bfb..4fb80b48daf 100644 --- a/spec/requests/admin/email_templates_controller_spec.rb +++ b/spec/requests/admin/email_templates_controller_spec.rb @@ -165,6 +165,7 @@ RSpec.describe Admin::EmailTemplatesController do I18n.t( "activerecord.errors.models.translation_overrides.attributes.value.invalid_interpolation_keys", keys: "email_wrongfix", + count: 1, ) }", ] @@ -183,6 +184,7 @@ RSpec.describe Admin::EmailTemplatesController do I18n.t( "activerecord.errors.models.translation_overrides.attributes.value.invalid_interpolation_keys", keys: "invalid", + count: 1, ) }", ] @@ -201,12 +203,14 @@ RSpec.describe Admin::EmailTemplatesController do I18n.t( "activerecord.errors.models.translation_overrides.attributes.value.invalid_interpolation_keys", keys: "invalid", + count: 1, ) }", "Body: #{ I18n.t( "activerecord.errors.models.translation_overrides.attributes.value.invalid_interpolation_keys", keys: "invalid", + count: 1, ) }", ] diff --git a/spec/requests/admin/site_texts_controller_spec.rb b/spec/requests/admin/site_texts_controller_spec.rb index 0bdace38ede..14b3f2455c3 100644 --- a/spec/requests/admin/site_texts_controller_spec.rb +++ b/spec/requests/admin/site_texts_controller_spec.rb @@ -580,6 +580,7 @@ RSpec.describe Admin::SiteTextsController do I18n.t( "activerecord.errors.models.translation_overrides.attributes.value.invalid_interpolation_keys", keys: "key, omg", + count: 2, ), ) end