mirror of
https://github.com/discourse/discourse.git
synced 2024-11-25 18:30:26 -06:00
DEV: Add endpoint for dismissing outdated translations (#22509)
Recently we started giving admins a notice in the advice panel when their translations have become outdated due to changes in core. However, we didn't include any additional information. This PR adds more information about the outdated translation inside the site text edit page, together with an option to dismiss the warning.
This commit is contained in:
parent
3820fae041
commit
341acacba8
@ -16,6 +16,11 @@ export default Controller.extend(bufferedProperty("siteText"), {
|
|||||||
return this.siteText.value === value;
|
return this.siteText.value === value;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@discourseComputed("siteText.status")
|
||||||
|
isOutdated(status) {
|
||||||
|
return status === "outdated";
|
||||||
|
},
|
||||||
|
|
||||||
@action
|
@action
|
||||||
saveChanges() {
|
saveChanges() {
|
||||||
const attrs = this.buffered.getProperties("value");
|
const attrs = this.buffered.getProperties("value");
|
||||||
@ -49,6 +54,16 @@ export default Controller.extend(bufferedProperty("siteText"), {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@action
|
||||||
|
dismissOutdated() {
|
||||||
|
this.siteText
|
||||||
|
.dismissOutdated(this.locale)
|
||||||
|
.then(() => {
|
||||||
|
this.siteText.set("status", "up_to_date");
|
||||||
|
})
|
||||||
|
.catch(popupAjaxError);
|
||||||
|
},
|
||||||
|
|
||||||
get interpolationKeys() {
|
get interpolationKeys() {
|
||||||
return this.siteText.interpolation_keys.join(", ");
|
return this.siteText.interpolation_keys.join(", ");
|
||||||
},
|
},
|
||||||
|
@ -8,4 +8,13 @@ export default class SiteText extends RestModel {
|
|||||||
type: "DELETE",
|
type: "DELETE",
|
||||||
}).then((result) => getProperties(result.site_text, "value", "can_revert"));
|
}).then((result) => getProperties(result.site_text, "value", "can_revert"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dismissOutdated(locale) {
|
||||||
|
return ajax(
|
||||||
|
`/admin/customize/site_texts/${this.id}/dismiss_outdated?locale=${locale}`,
|
||||||
|
{
|
||||||
|
type: "PUT",
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,22 @@
|
|||||||
<h4>{{i18n "admin.site_text.locale"}} {{this.localeFullName}}</h4>
|
<h4>{{i18n "admin.site_text.locale"}} {{this.localeFullName}}</h4>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{{#if this.isOutdated}}
|
||||||
|
<div class="outdated">
|
||||||
|
<h4>{{i18n "admin.site_text.outdated.title"}}</h4>
|
||||||
|
<p>{{i18n "admin.site_text.outdated.description"}}</p>
|
||||||
|
<h5>{{i18n "admin.site_text.outdated.old_default"}}</h5>
|
||||||
|
<p>{{this.siteText.old_default}}</p>
|
||||||
|
<h5>{{i18n "admin.site_text.outdated.new_default"}}</h5>
|
||||||
|
<p>{{this.siteText.new_default}}</p>
|
||||||
|
<DButton
|
||||||
|
@class="btn-default"
|
||||||
|
@action={{action "dismissOutdated"}}
|
||||||
|
@label="admin.site_text.outdated.dismiss"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
<ExpandingTextArea
|
<ExpandingTextArea
|
||||||
@value={{this.buffered.value}}
|
@value={{this.buffered.value}}
|
||||||
@rows="1"
|
@rows="1"
|
||||||
|
@ -295,6 +295,18 @@ $mobile-breakpoint: 700px;
|
|||||||
line-height: var(--line-height-large);
|
line-height: var(--line-height-large);
|
||||||
color: var(--primary-medium);
|
color: var(--primary-medium);
|
||||||
}
|
}
|
||||||
|
.outdated {
|
||||||
|
border: 1px solid var(--primary-low);
|
||||||
|
box-sizing: border-box;
|
||||||
|
color: var(--primary);
|
||||||
|
margin-bottom: 1em;
|
||||||
|
max-width: 800px;
|
||||||
|
padding: 1em;
|
||||||
|
|
||||||
|
p {
|
||||||
|
color: var(--primary-high);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
p.warning {
|
p.warning {
|
||||||
color: var(--danger);
|
color: var(--danger);
|
||||||
|
@ -128,6 +128,26 @@ class Admin::SiteTextsController < Admin::AdminController
|
|||||||
render_serialized(site_text, SiteTextSerializer, root: "site_text", rest_serializer: true)
|
render_serialized(site_text, SiteTextSerializer, root: "site_text", rest_serializer: true)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def dismiss_outdated
|
||||||
|
locale = fetch_locale(params[:locale])
|
||||||
|
override = TranslationOverride.find_by(locale: locale, translation_key: params[:id])
|
||||||
|
|
||||||
|
raise Discourse::NotFound if override.blank?
|
||||||
|
|
||||||
|
if override.outdated?
|
||||||
|
override.update!(
|
||||||
|
status: "up_to_date",
|
||||||
|
original_translation:
|
||||||
|
I18n.overrides_disabled do
|
||||||
|
I18n.t(TranslationOverride.transform_pluralized_key(params[:id]), locale: :en)
|
||||||
|
end,
|
||||||
|
)
|
||||||
|
render json: success_json
|
||||||
|
else
|
||||||
|
render json: failed_json.merge(message: "Can only dismiss outdated translations"), status: 422
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def get_reseed_options
|
def get_reseed_options
|
||||||
render_json_dump(
|
render_json_dump(
|
||||||
categories: SeedData::Categories.with_default_locale.reseed_options,
|
categories: SeedData::Categories.with_default_locale.reseed_options,
|
||||||
|
@ -138,19 +138,13 @@ class TranslationOverride < ActiveRecord::Base
|
|||||||
def original_translation_updated?
|
def original_translation_updated?
|
||||||
return false if original_translation.blank?
|
return false if original_translation.blank?
|
||||||
|
|
||||||
transformed_key = self.class.transform_pluralized_key(translation_key)
|
original_translation != current_default
|
||||||
|
|
||||||
original_translation != I18n.overrides_disabled { I18n.t(transformed_key, locale: :en) }
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def invalid_interpolation_keys
|
def invalid_interpolation_keys
|
||||||
transformed_key = self.class.transform_pluralized_key(translation_key)
|
return [] if current_default.blank?
|
||||||
|
|
||||||
original_text = I18n.overrides_disabled { I18n.t(transformed_key, locale: :en) }
|
original_interpolation_keys = I18nInterpolationKeysFinder.find(current_default)
|
||||||
|
|
||||||
return [] if original_text.blank?
|
|
||||||
|
|
||||||
original_interpolation_keys = I18nInterpolationKeysFinder.find(original_text)
|
|
||||||
new_interpolation_keys = I18nInterpolationKeysFinder.find(value)
|
new_interpolation_keys = I18nInterpolationKeysFinder.find(value)
|
||||||
custom_interpolation_keys = []
|
custom_interpolation_keys = []
|
||||||
|
|
||||||
@ -162,6 +156,10 @@ class TranslationOverride < ActiveRecord::Base
|
|||||||
custom_interpolation_keys
|
custom_interpolation_keys
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def current_default
|
||||||
|
I18n.overrides_disabled { I18n.t(transformed_key, locale: :en) }
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def transformed_key
|
def transformed_key
|
||||||
|
@ -1,7 +1,15 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class SiteTextSerializer < ApplicationSerializer
|
class SiteTextSerializer < ApplicationSerializer
|
||||||
attributes :id, :value, :interpolation_keys, :has_interpolation_keys?, :overridden?, :can_revert?
|
attributes :id,
|
||||||
|
:value,
|
||||||
|
:status,
|
||||||
|
:old_default,
|
||||||
|
:new_default,
|
||||||
|
:interpolation_keys,
|
||||||
|
:has_interpolation_keys?,
|
||||||
|
:overridden?,
|
||||||
|
:can_revert?
|
||||||
|
|
||||||
def id
|
def id
|
||||||
object[:id]
|
object[:id]
|
||||||
@ -11,6 +19,22 @@ class SiteTextSerializer < ApplicationSerializer
|
|||||||
object[:value]
|
object[:value]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def status
|
||||||
|
if override.present?
|
||||||
|
override.status
|
||||||
|
else
|
||||||
|
"up_to_date"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def old_default
|
||||||
|
override.original_translation if override.present?
|
||||||
|
end
|
||||||
|
|
||||||
|
def new_default
|
||||||
|
override.current_default if override.present?
|
||||||
|
end
|
||||||
|
|
||||||
def interpolation_keys
|
def interpolation_keys
|
||||||
object[:interpolation_keys]
|
object[:interpolation_keys]
|
||||||
end
|
end
|
||||||
@ -23,9 +47,15 @@ class SiteTextSerializer < ApplicationSerializer
|
|||||||
if options[:overridden_keys]
|
if options[:overridden_keys]
|
||||||
options[:overridden_keys].include?(object[:id])
|
options[:overridden_keys].include?(object[:id])
|
||||||
else
|
else
|
||||||
TranslationOverride.exists?(locale: object[:locale], translation_key: object[:id])
|
override.present?
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
alias_method :can_revert?, :overridden?
|
alias_method :can_revert?, :overridden?
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def override
|
||||||
|
TranslationOverride.find_by(locale: object[:locale], translation_key: object[:id])
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
@ -6098,6 +6098,12 @@ en:
|
|||||||
locale: "Language:"
|
locale: "Language:"
|
||||||
more_than_50_results: "There are more than 50 results. Please refine your search."
|
more_than_50_results: "There are more than 50 results. Please refine your search."
|
||||||
interpolation_keys: "Available interpolation keys:"
|
interpolation_keys: "Available interpolation keys:"
|
||||||
|
outdated:
|
||||||
|
title: "This translation is outdated"
|
||||||
|
description: "The default translation for this key has changed since this override was created. Please check below that your translation matches any changes that have been made to the original intent."
|
||||||
|
old_default: "Old default"
|
||||||
|
new_default: "New default"
|
||||||
|
dismiss: "Dismiss"
|
||||||
|
|
||||||
settings: # used by theme and site settings
|
settings: # used by theme and site settings
|
||||||
show_overriden: "Only show overridden"
|
show_overriden: "Only show overridden"
|
||||||
|
@ -257,6 +257,14 @@ Discourse::Application.routes.draw do
|
|||||||
id: /[\w.\-\+\%\&]+/i,
|
id: /[\w.\-\+\%\&]+/i,
|
||||||
}
|
}
|
||||||
delete "site_texts/:id" => "site_texts#revert", :constraints => { id: /[\w.\-\+\%\&]+/i }
|
delete "site_texts/:id" => "site_texts#revert", :constraints => { id: /[\w.\-\+\%\&]+/i }
|
||||||
|
put "site_texts/:id/dismiss_outdated" => "site_texts#dismiss_outdated",
|
||||||
|
:constraints => {
|
||||||
|
id: /[\w.\-\+\%\&]+/i,
|
||||||
|
}
|
||||||
|
put "site_texts/:id/dismiss_outdated.json" => "site_texts#dismiss_outdated",
|
||||||
|
:constraints => {
|
||||||
|
id: /[\w.\-\+\%\&]+/i,
|
||||||
|
}
|
||||||
|
|
||||||
get "reseed" => "site_texts#get_reseed_options"
|
get "reseed" => "site_texts#get_reseed_options"
|
||||||
post "reseed" => "site_texts#reseed"
|
post "reseed" => "site_texts#reseed"
|
||||||
|
@ -224,6 +224,9 @@ RSpec.describe Admin::SiteTextsController do
|
|||||||
{
|
{
|
||||||
id: "colour.#{key}",
|
id: "colour.#{key}",
|
||||||
value: value,
|
value: value,
|
||||||
|
status: "up_to_date",
|
||||||
|
old_default: nil,
|
||||||
|
new_default: nil,
|
||||||
can_revert: overridden,
|
can_revert: overridden,
|
||||||
overridden: overridden,
|
overridden: overridden,
|
||||||
interpolation_keys: interpolation_keys,
|
interpolation_keys: interpolation_keys,
|
||||||
@ -815,6 +818,70 @@ RSpec.describe Admin::SiteTextsController do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "#dismiss_outdated" do
|
||||||
|
before { sign_in(admin) }
|
||||||
|
|
||||||
|
context "when using a key which isn't overridden" do
|
||||||
|
it "returns a not found error" do
|
||||||
|
put "/admin/customize/site_texts/title/dismiss_outdated.json",
|
||||||
|
params: {
|
||||||
|
locale: default_locale,
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(response.status).to eq(404)
|
||||||
|
|
||||||
|
json = response.parsed_body
|
||||||
|
expect(json["error_type"]).to eq("not_found")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when the override isn't outdated" do
|
||||||
|
before do
|
||||||
|
Fabricate(
|
||||||
|
:translation_override,
|
||||||
|
locale: default_locale,
|
||||||
|
translation_key: "title",
|
||||||
|
value: "My Forum",
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns an unprocessable entity error" do
|
||||||
|
put "/admin/customize/site_texts/title/dismiss_outdated.json",
|
||||||
|
params: {
|
||||||
|
locale: default_locale,
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(response.status).to eq(422)
|
||||||
|
|
||||||
|
json = response.parsed_body
|
||||||
|
expect(json["failed"]).to eq("FAILED")
|
||||||
|
expect(json["message"]).to eq("Can only dismiss outdated translations")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when the override is outdated" do
|
||||||
|
before do
|
||||||
|
Fabricate(
|
||||||
|
:translation_override,
|
||||||
|
locale: default_locale,
|
||||||
|
translation_key: "title",
|
||||||
|
value: "My Forum",
|
||||||
|
status: "outdated",
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns success" do
|
||||||
|
put "/admin/customize/site_texts/title/dismiss_outdated.json",
|
||||||
|
params: {
|
||||||
|
locale: default_locale,
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(response.status).to eq(200)
|
||||||
|
expect(response.parsed_body["success"]).to eq("OK")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
context "when reseeding" do
|
context "when reseeding" do
|
||||||
before do
|
before do
|
||||||
staff_category = Fabricate(:category, name: "Staff EN", user: Discourse.system_user)
|
staff_category = Fabricate(:category, name: "Staff EN", user: Discourse.system_user)
|
||||||
|
Loading…
Reference in New Issue
Block a user