FIX: prevents i18n helper to return a SafeString (#9191)
For convenience the i18n helper has been made returning a SafeString, but when used with other helpers, a String is expected and will cause unexpected behaviors.
This is the root cause of the initial bug fixed in d2bb127e2c
This commit is kept as it's a better security in case of unexpected behavior.
This commit is contained in:
parent
59578dfc5b
commit
6102c287f7
|
@ -15,7 +15,7 @@
|
|||
|
||||
{{#if backupStats.last_backup_taken_at}}
|
||||
<br>
|
||||
{{i18n "admin.dashboard.lastest_backup" date=(format-date backupStats.last_backup_taken_at leaveAgo="true")}}
|
||||
{{html-safe (i18n "admin.dashboard.lastest_backup" date=(format-date backupStats.last_backup_taken_at leaveAgo="true"))}}
|
||||
{{/if}}
|
||||
</p>
|
||||
</div>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<div class='penalty-post-controls'>
|
||||
<label>
|
||||
<div class='penalty-post-label'>
|
||||
{{i18n 'admin.user.penalty_post_actions'}}
|
||||
{{html-safe (i18n 'admin.user.penalty_post_actions')}}
|
||||
</div>
|
||||
</label>
|
||||
{{combo-box
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<div class='reason-controls'>
|
||||
<label>
|
||||
<div class='silence-reason-label'>
|
||||
{{i18n 'admin.user.silence_reason_label'}}
|
||||
{{html-safe (i18n 'admin.user.silence_reason_label')}}
|
||||
</div>
|
||||
</label>
|
||||
{{text-field
|
||||
|
|
|
@ -2,9 +2,9 @@
|
|||
<label>
|
||||
<div class='suspend-reason-label'>
|
||||
{{#if siteSettings.hide_suspension_reasons}}
|
||||
{{i18n 'admin.user.suspend_reason_hidden_label'}}
|
||||
{{html-safe (i18n 'admin.user.suspend_reason_hidden_label')}}
|
||||
{{else}}
|
||||
{{i18n 'admin.user.suspend_reason_label'}}
|
||||
{{html-safe (i18n 'admin.user.suspend_reason_label')}}
|
||||
{{/if}}
|
||||
</div>
|
||||
</label>
|
||||
|
|
|
@ -142,7 +142,7 @@
|
|||
filters=trendingSearchFilters
|
||||
isEnabled=logSearchQueriesEnabled
|
||||
disabledLabel=trendingSearchDisabledLabel}}
|
||||
{{i18n "admin.dashboard.reports.trending_search.more" basePath=basePath}}
|
||||
{{html-safe (i18n "admin.dashboard.reports.trending_search.more" basePath=basePath)}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
|
||||
{{#if showSecondary}}
|
||||
<div class='embedding-secondary'>
|
||||
<p>{{i18n "admin.embedding.sample"}}</p>
|
||||
<p>{{html-safe (i18n "admin.embedding.sample")}}</p>
|
||||
{{highlighted-code code=embeddingCode lang="html"}}
|
||||
</div>
|
||||
|
||||
|
|
|
@ -17,9 +17,9 @@
|
|||
{{else}}
|
||||
<p class="grant-count">
|
||||
{{#if count}}
|
||||
{{i18n "admin.badges.preview.grant_count" count=count}}
|
||||
{{html-safe (i18n "admin.badges.preview.grant_count" count=count)}}
|
||||
{{else}}
|
||||
{{i18n "admin.badges.preview.no_grant_count"}}
|
||||
{{html-safe (i18n "admin.badges.preview.no_grant_count")}}
|
||||
{{/if}}
|
||||
</p>
|
||||
|
||||
|
|
|
@ -132,7 +132,7 @@
|
|||
<div class="field">{{i18n "user.avatar.title"}}</div>
|
||||
<div class="value">{{avatar model imageSize="large"}}</div>
|
||||
<div class="controls">
|
||||
{{i18n "admin.user.visit_profile" url=preferencesPath}}
|
||||
{{html-safe (i18n "admin.user.visit_profile" url=preferencesPath)}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import { registerUnbound } from "discourse-common/lib/helpers";
|
||||
import { htmlSafe } from "@ember/template";
|
||||
|
||||
registerUnbound("i18n", (key, params) => htmlSafe(I18n.t(key, params)));
|
||||
registerUnbound("i18n", (key, params) => I18n.t(key, params));
|
||||
registerUnbound("i18n-yes-no", (value, params) =>
|
||||
I18n.t(value ? "yes_value" : "no_value", params)
|
||||
);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { registerUnbound } from "discourse-common/lib/helpers";
|
||||
import { emojiUnescape } from "discourse/lib/text";
|
||||
import { htmlSafe } from "@ember/template";
|
||||
|
||||
registerUnbound(
|
||||
"replace-emoji",
|
||||
text => new Handlebars.SafeString(emojiUnescape(text))
|
||||
);
|
||||
registerUnbound("replace-emoji", text => {
|
||||
return htmlSafe(emojiUnescape(text));
|
||||
});
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<div class='ac-message'>
|
||||
{{#if email}}
|
||||
{{i18n 'login.sent_activation_email_again' currentEmail=email}}
|
||||
{{html-safe (i18n 'login.sent_activation_email_again' currentEmail=email)}}
|
||||
{{else}}
|
||||
{{i18n 'login.sent_activation_email_again_generic'}}
|
||||
{{/if}}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<div id="banner-content">
|
||||
{{html-safe content}}
|
||||
{{#if currentUser.staff}}
|
||||
<p><a href={{banner.url}}>{{i18n "banner.edit"}}</a></p>
|
||||
<p><a href={{banner.url}}>{{html-safe (i18n "banner.edit")}}</a></p>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{{#if category.isUncategorizedCategory}}
|
||||
<p class="warning">
|
||||
{{d-icon "exclamation-triangle"}}
|
||||
{{i18n 'category.uncategorized_general_warning' settingLink=uncategorizedSiteSettingLink customizeLink=customizeTextContentLink}}
|
||||
{{html-safe (i18n 'category.uncategorized_general_warning' settingLink=uncategorizedSiteSettingLink customizeLink=customizeTextContentLink)}}
|
||||
</p>
|
||||
{{/if}}
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
{{#each category.permissions as |p|}}
|
||||
<li>
|
||||
<span class="name"><span class="badge-group">{{p.group_name}}</span></span>
|
||||
{{i18n "category.can"}}
|
||||
{{html-safe (i18n "category.can")}}
|
||||
<span class="permission">{{p.permission.description}}</span>
|
||||
{{#if editingPermissions}}
|
||||
<a class="remove-permission" href {{action "removePermission" p}}>{{d-icon "times-circle"}}</a>
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
{{d-button action=(action "copy") class="pull-right no-text" icon="copy"}}
|
||||
{{/if}}
|
||||
<h4>{{i18n "ip_lookup.title"}}</h4>
|
||||
<p class='powered-by'>{{i18n "ip_lookup.powered_by"}}</p>
|
||||
<p class='powered-by'>{{html-safe (i18n "ip_lookup.powered_by")}}</p>
|
||||
<dl>
|
||||
{{#if location}}
|
||||
{{#if location.hostname}}
|
||||
|
|
|
@ -10,5 +10,5 @@
|
|||
</div>
|
||||
|
||||
{{#if targetUser}}
|
||||
<h3 class="see-all-pms-message">{{i18n "related_messages.see_all" path=searchLink username=targetUser.username}}</h3>
|
||||
<h3 class="see-all-pms-message">{{html-safe (i18n "related_messages.see_all" path=searchLink username=targetUser.username)}}</h3>
|
||||
{{/if}}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
{{#if publishing}}
|
||||
{{i18n "shared_drafts.publishing"}}
|
||||
{{else}}
|
||||
{{i18n "shared_drafts.notice" category=topic.category.name}}
|
||||
{{html-safe (i18n "shared_drafts.notice" category=topic.category.name)}}
|
||||
|
||||
<div class='publish-field'>
|
||||
<label>{{i18n "shared_drafts.destination_category"}}</label>
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
{{#if tagInfo.synonyms}}
|
||||
<div class="synonyms-list">
|
||||
<h3>{{i18n "tagging.synonyms"}}</h3>
|
||||
<div>{{i18n "tagging.synonyms_description" base_tag_name=tagInfo.name}}</div>
|
||||
<div>{{html-safe (i18n "tagging.synonyms_description" base_tag_name=tagInfo.name)}}</div>
|
||||
<div class="tag-list">
|
||||
{{#each tagInfo.synonyms as |tag|}}
|
||||
<div class='tag-box'>
|
||||
|
|
|
@ -9,5 +9,5 @@
|
|||
</span>
|
||||
<span class='label'>
|
||||
{{#if icon}}{{d-icon icon}}{{/if}}
|
||||
{{i18n label count=value}}
|
||||
{{html-safe (i18n label count=value)}}
|
||||
</span>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{{#d-modal-body}}
|
||||
{{i18n 'login.sent_activation_email_again' currentEmail=currentEmail}}
|
||||
{{html-safe (i18n 'login.sent_activation_email_again' currentEmail=currentEmail)}}
|
||||
{{/d-modal-body}}
|
||||
|
||||
{{modal-footer-close closeModal=(route-action "closeModal")}}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{{#d-modal-body title="user.auth_tokens.was_this_you"}}
|
||||
<div>
|
||||
<p>{{i18n 'user.auth_tokens.was_this_you_description'}}</p>
|
||||
<p>{{i18n 'user.second_factor.extended_description'}}</p>
|
||||
<p>{{html-safe (i18n 'user.second_factor.extended_description')}}</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
|
|
|
@ -10,11 +10,11 @@
|
|||
{{else}}
|
||||
<div class="avatar-choice">
|
||||
{{radio-button id="system-avatar" name="avatar" value="system" selection=selected}}
|
||||
<label class="radio" for="system-avatar">{{bound-avatar-template user.system_avatar_template "large"}} {{i18n 'user.change_avatar.letter_based'}}</label>
|
||||
<label class="radio" for="system-avatar">{{bound-avatar-template user.system_avatar_template "large"}} {{html-safe (i18n 'user.change_avatar.letter_based')}}</label>
|
||||
</div>
|
||||
<div class="avatar-choice">
|
||||
{{radio-button id="gravatar" name="avatar" value="gravatar" selection=selected}}
|
||||
<label class="radio" for="gravatar">{{bound-avatar-template user.gravatar_avatar_template "large"}} <span>{{i18n 'user.change_avatar.gravatar' gravatarName=gravatarName gravatarBaseUrl=gravatarBaseUrl gravatarLoginUrl=gravatarLoginUrl }} {{user.email}}</span></label>
|
||||
<label class="radio" for="gravatar">{{bound-avatar-template user.gravatar_avatar_template "large"}} <span>{{html-safe (i18n 'user.change_avatar.gravatar' gravatarName=gravatarName gravatarBaseUrl=gravatarBaseUrl gravatarLoginUrl=gravatarLoginUrl)}} {{user.email}}</span></label>
|
||||
|
||||
{{d-button action=(action "refreshGravatar")
|
||||
translatedTitle=(i18n "user.change_avatar.refresh_gravatar_title" gravatarName=gravatarName)
|
||||
|
|
|
@ -50,7 +50,7 @@
|
|||
{{/if}}
|
||||
|
||||
{{else}}
|
||||
<div class="alert alert-info">{{i18n "bookmarks.no_timezone" basePath=basePath }}</div>
|
||||
<div class="alert alert-info">{{html-safe (i18n "bookmarks.no_timezone" basePath=basePath)}}</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/if}}
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
{{#d-modal-body class='change-ownership'}}
|
||||
<span>
|
||||
{{i18n (if selectedPostsUsername 'topic.change_owner.instructions' 'topic.change_owner.instructions_without_old_user')
|
||||
count=selectedPostsCount
|
||||
old_user=selectedPostsUsername}}
|
||||
{{html-safe (i18n (if selectedPostsUsername 'topic.change_owner.instructions' 'topic.change_owner.instructions_without_old_user')
|
||||
count=selectedPostsCount
|
||||
old_user=selectedPostsUsername
|
||||
)
|
||||
}}
|
||||
</span>
|
||||
|
||||
<form>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{{#d-modal-body}}
|
||||
<p>{{i18n "post.controls.delete_topic_disallowed_modal"}}</p>
|
||||
<p>{{html-safe (i18n "post.controls.delete_topic_disallowed_modal")}}</p>
|
||||
{{/d-modal-body}}
|
||||
<div class="modal-footer">
|
||||
{{d-button action=(route-action "closeModal") class="btn-primary" label="close"}}
|
||||
|
|
|
@ -6,9 +6,9 @@
|
|||
<p>
|
||||
{{#conditional-loading-spinner size="small" condition=loading}}
|
||||
{{#if pinnedGloballyCount}}
|
||||
{{i18n "topic.feature_topic.already_pinned_globally" count=pinnedGloballyCount}}
|
||||
{{html-safe (i18n "topic.feature_topic.already_pinned_globally" count=pinnedGloballyCount)}}
|
||||
{{else}}
|
||||
{{i18n "topic.feature_topic.not_pinned_globally"}}
|
||||
{{html-safe (i18n "topic.feature_topic.not_pinned_globally")}}
|
||||
{{/if}}
|
||||
{{/conditional-loading-spinner}}
|
||||
</p>
|
||||
|
@ -74,9 +74,9 @@
|
|||
<p>
|
||||
{{#conditional-loading-spinner size="small" condition=loading}}
|
||||
{{#if pinnedGloballyCount}}
|
||||
{{i18n "topic.feature_topic.already_pinned_globally" count=pinnedGloballyCount}}
|
||||
{{html-safe (i18n "topic.feature_topic.already_pinned_globally" count=pinnedGloballyCount)}}
|
||||
{{else}}
|
||||
{{i18n "topic.feature_topic.not_pinned_globally"}}
|
||||
{{html-safe (i18n "topic.feature_topic.not_pinned_globally")}}
|
||||
{{/if}}
|
||||
{{/conditional-loading-spinner}}
|
||||
</p>
|
||||
|
@ -123,9 +123,9 @@
|
|||
<p>
|
||||
{{#conditional-loading-spinner size="small" condition=loading}}
|
||||
{{#if bannerCount}}
|
||||
{{i18n "topic.feature_topic.banner_exists"}}
|
||||
{{html-safe (i18n "topic.feature_topic.banner_exists")}}
|
||||
{{else}}
|
||||
{{i18n "topic.feature_topic.no_banner_exists"}}
|
||||
{{html-safe (i18n "topic.feature_topic.no_banner_exists")}}
|
||||
{{/if}}
|
||||
{{/conditional-loading-spinner}}
|
||||
</p>
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
{{#if canSplitTopic}}
|
||||
{{#if newMessage}}
|
||||
<p>{{i18n 'topic.move_to_new_message.instructions' count=selectedPostsCount}}</p>
|
||||
<p>{{html-safe (i18n 'topic.move_to_new_message.instructions' count=selectedPostsCount)}}</p>
|
||||
<form>
|
||||
<label>{{i18n 'topic.move_to_new_message.message_title'}}</label>
|
||||
{{text-field value=topicName placeholderKey="composer.title_placeholder" elementId='split-topic-name'}}
|
||||
|
@ -31,7 +31,7 @@
|
|||
{{/if}}
|
||||
|
||||
{{#if existingMessage}}
|
||||
<p>{{i18n 'topic.move_to_existing_message.instructions' count=selectedPostsCount}}</p>
|
||||
<p>{{html-safe (i18n 'topic.move_to_existing_message.instructions' count=selectedPostsCount)}}</p>
|
||||
<form>
|
||||
{{choose-message currentTopicId=model.id selectedTopicId=selectedTopicId}}
|
||||
|
||||
|
@ -64,7 +64,7 @@
|
|||
</div>
|
||||
|
||||
{{#if existingTopic}}
|
||||
<p>{{i18n 'topic.merge_topic.instructions' count=selectedPostsCount}}</p>
|
||||
<p>{{html-safe (i18n 'topic.merge_topic.instructions' count=selectedPostsCount)}}</p>
|
||||
<form>
|
||||
{{choose-topic currentTopicId=model.id selectedTopicId=selectedTopicId}}
|
||||
</form>
|
||||
|
@ -72,7 +72,7 @@
|
|||
|
||||
{{#if canSplitTopic}}
|
||||
{{#if newTopic}}
|
||||
<p>{{i18n 'topic.split_topic.instructions' count=selectedPostsCount}}</p>
|
||||
<p>{{html-safe (i18n 'topic.split_topic.instructions' count=selectedPostsCount)}}</p>
|
||||
<form>
|
||||
<label>{{i18n 'topic.split_topic.topic_name'}}</label>
|
||||
{{text-field value=topicName placeholderKey="composer.title_placeholder" elementId='split-topic-name'}}
|
||||
|
@ -93,7 +93,7 @@
|
|||
|
||||
{{#if canSplitTopic}}
|
||||
{{#if newMessage}}
|
||||
<p>{{i18n 'topic.move_to_new_message.instructions' count=selectedPostsCount}}</p>
|
||||
<p>{{html-safe (i18n 'topic.move_to_new_message.instructions' count=selectedPostsCount)}}</p>
|
||||
<form>
|
||||
<label>{{i18n 'topic.move_to_new_message.message_title'}}</label>
|
||||
{{text-field value=topicName placeholderKey="composer.title_placeholder" elementId='split-topic-name'}}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{{#d-modal-body}}
|
||||
{{i18n 'login.not_activated' sentTo=sentTo}}
|
||||
{{html-safe (i18n 'login.not_activated' sentTo=sentTo)}}
|
||||
{{/d-modal-body}}
|
||||
|
||||
<div class="modal-footer">
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{{#d-modal-body}}
|
||||
<p>{{i18n "review.approval.description"}}</p>
|
||||
|
||||
<p>{{i18n "review.approval.pending_posts" count=model.pending_count}}</p>
|
||||
<p>{{html-safe (i18n "review.approval.pending_posts" count=model.pending_count)}}</p>
|
||||
{{/d-modal-body}}
|
||||
<div class="modal-footer">
|
||||
{{d-button action=(route-action "closeModal") class="btn-primary" label="review.approval.ok"}}
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
<div class="control-group">
|
||||
<div class="controls">
|
||||
{{i18n 'user.second_factor.enable_security_key_description'}}
|
||||
{{html-safe (i18n 'user.second_factor.enable_security_key_description')}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
<div class="control-group">
|
||||
<div class="controls">
|
||||
{{i18n 'user.second_factor.enable_description'}}
|
||||
{{html-safe (i18n 'user.second_factor.enable_description')}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
{{/if}}
|
||||
|
||||
{{#if backupEnabled}}
|
||||
{{i18n "user.second_factor_backup.remaining_codes" count=remainingCodes}}
|
||||
{{html-safe (i18n "user.second_factor_backup.remaining_codes" count=remainingCodes)}}
|
||||
{{/if}}
|
||||
|
||||
<div class="actions">
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
{{#d-modal-body}}
|
||||
<p>{{i18n 'topics.bulk.selected' count=model.topics.length}}</p>
|
||||
<p>{{html-safe (i18n 'topics.bulk.selected' count=model.topics.length)}}</p>
|
||||
{{outlet "bulkOutlet"}}
|
||||
{{/d-modal-body}}
|
||||
|
|
|
@ -86,7 +86,7 @@
|
|||
<h2>{{i18n "user.second_factor_backup.title"}}</h2>
|
||||
{{#if model.second_factor_enabled}}
|
||||
{{#if model.second_factor_backup_enabled}}
|
||||
{{i18n 'user.second_factor_backup.manage' count=model.second_factor_remaining_backup_codes}}
|
||||
{{html-safe (i18n 'user.second_factor_backup.manage' count=model.second_factor_remaining_backup_codes)}}
|
||||
{{else}}
|
||||
{{i18n 'user.second_factor_backup.enable_long'}}
|
||||
{{/if}}
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
</div>
|
||||
{{#if siteSettings.enable_mentions}}
|
||||
<div class='instructions'>
|
||||
{{i18n 'user.username.short_instructions' username=model.username}}
|
||||
{{html-safe (i18n 'user.username.short_instructions' username=model.username)}}
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
|
|
|
@ -73,7 +73,7 @@
|
|||
<div class='control-group pref-mailing-list-mode'>
|
||||
<label class="control-label">{{i18n 'user.mailing_list_mode.label'}}</label>
|
||||
{{preference-checkbox labelKey="user.mailing_list_mode.enabled" checked=model.user_option.mailing_list_mode}}
|
||||
<div class='instructions'>{{i18n 'user.mailing_list_mode.instructions'}}</div>
|
||||
<div class='instructions'>{{html-safe (i18n 'user.mailing_list_mode.instructions')}}</div>
|
||||
{{#if model.user_option.mailing_list_mode}}
|
||||
<div class='controls controls-dropdown'>
|
||||
{{combo-box
|
||||
|
|
|
@ -277,7 +277,7 @@
|
|||
{{#if model.queued_posts_count}}
|
||||
<div class="has-pending-posts">
|
||||
<div>
|
||||
{{i18n "review.topic_has_pending" count=model.queued_posts_count}}
|
||||
{{html-safe (i18n "review.topic_has_pending" count=model.queued_posts_count)}}
|
||||
</div>
|
||||
|
||||
{{#link-to 'review' (query-params topic_id=model.id type="ReviewableQueuedPost" status="pending")}}
|
||||
|
|
|
@ -109,7 +109,7 @@
|
|||
{{else}}
|
||||
<div class="user-invite-none">
|
||||
{{#if canBulkInvite}}
|
||||
{{i18n 'user.invited.bulk_invite.none'}}
|
||||
{{html-safe (i18n 'user.invited.bulk_invite.none')}}
|
||||
{{else}}
|
||||
{{i18n 'user.invited.none'}}
|
||||
{{/if}}
|
||||
|
|
|
@ -85,7 +85,7 @@
|
|||
<label class="control-label">
|
||||
{{i18n "discourse_local_dates.create.form.recurring_title"}}
|
||||
</label>
|
||||
<p>{{i18n "discourse_local_dates.create.form.recurring_description"}}</p>
|
||||
<p>{{html-safe (i18n "discourse_local_dates.create.form.recurring_description")}}</p>
|
||||
<div class="controls">
|
||||
{{combo-box
|
||||
content=recurringOptions
|
||||
|
|
Loading…
Reference in New Issue