mirror of
https://github.com/discourse/discourse.git
synced 2024-11-22 08:57:10 -06:00
FEATURE: add Untranslated filter to admin text customization (#27555)
Adds a checkbox to filter untranslated text strings in the admin UI, behind a hidden and default `false` site setting `admin_allow_filter_untranslated_text`.
This commit is contained in:
parent
ce00f83173
commit
55da8a7701
@ -19,13 +19,14 @@ export default class AdminSiteTextIndexController extends Controller {
|
|||||||
@tracked q;
|
@tracked q;
|
||||||
@tracked overridden;
|
@tracked overridden;
|
||||||
@tracked outdated;
|
@tracked outdated;
|
||||||
|
@tracked untranslated;
|
||||||
|
|
||||||
@tracked model;
|
@tracked model;
|
||||||
|
|
||||||
@tracked searching = false;
|
@tracked searching = false;
|
||||||
@tracked preferred = false;
|
@tracked preferred = false;
|
||||||
|
|
||||||
queryParams = ["q", "overridden", "outdated", "locale"];
|
queryParams = ["q", "overridden", "outdated", "locale", "untranslated"];
|
||||||
|
|
||||||
get resolvedOverridden() {
|
get resolvedOverridden() {
|
||||||
return [true, "true"].includes(this.overridden) ?? false;
|
return [true, "true"].includes(this.overridden) ?? false;
|
||||||
@ -35,10 +36,21 @@ export default class AdminSiteTextIndexController extends Controller {
|
|||||||
return [true, "true"].includes(this.outdated) ?? false;
|
return [true, "true"].includes(this.outdated) ?? false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get resolvedUntranslated() {
|
||||||
|
return [true, "true"].includes(this.untranslated) ?? false;
|
||||||
|
}
|
||||||
|
|
||||||
get resolvedLocale() {
|
get resolvedLocale() {
|
||||||
return this.locale ?? this.siteSettings.default_locale;
|
return this.locale ?? this.siteSettings.default_locale;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get showUntranslated() {
|
||||||
|
return (
|
||||||
|
this.siteSettings.admin_allow_filter_untranslated_text &&
|
||||||
|
this.resolvedLocale !== "en"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
async _performSearch() {
|
async _performSearch() {
|
||||||
try {
|
try {
|
||||||
this.model = await this.store.find("site-text", {
|
this.model = await this.store.find("site-text", {
|
||||||
@ -46,6 +58,7 @@ export default class AdminSiteTextIndexController extends Controller {
|
|||||||
overridden: this.resolvedOverridden,
|
overridden: this.resolvedOverridden,
|
||||||
outdated: this.resolvedOutdated,
|
outdated: this.resolvedOutdated,
|
||||||
locale: this.resolvedLocale,
|
locale: this.resolvedLocale,
|
||||||
|
untranslated: this.resolvedUntranslated,
|
||||||
});
|
});
|
||||||
} finally {
|
} finally {
|
||||||
this.searching = false;
|
this.searching = false;
|
||||||
@ -95,6 +108,17 @@ export default class AdminSiteTextIndexController extends Controller {
|
|||||||
discourseDebounce(this, this._performSearch, 400);
|
discourseDebounce(this, this._performSearch, 400);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
toggleUntranslated() {
|
||||||
|
if (this.resolvedUntranslated) {
|
||||||
|
this.untranslated = null;
|
||||||
|
} else {
|
||||||
|
this.untranslated = true;
|
||||||
|
}
|
||||||
|
this.searching = true;
|
||||||
|
discourseDebounce(this, this._performSearch, 400);
|
||||||
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
search() {
|
search() {
|
||||||
const q = this.q;
|
const q = this.q;
|
||||||
|
@ -11,6 +11,7 @@ export default class AdminSiteTextIndexRoute extends Route {
|
|||||||
q: { replace: true },
|
q: { replace: true },
|
||||||
overridden: { replace: true },
|
overridden: { replace: true },
|
||||||
outdated: { replace: true },
|
outdated: { replace: true },
|
||||||
|
untranslated: { replace: true },
|
||||||
locale: { replace: true },
|
locale: { replace: true },
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -19,6 +20,7 @@ export default class AdminSiteTextIndexRoute extends Route {
|
|||||||
q: params.q,
|
q: params.q,
|
||||||
overridden: params.overridden ?? false,
|
overridden: params.overridden ?? false,
|
||||||
outdated: params.outdated ?? false,
|
outdated: params.outdated ?? false,
|
||||||
|
untranslated: params.untranslated ?? false,
|
||||||
locale: params.locale ?? this.siteSettings.default_locale,
|
locale: params.locale ?? this.siteSettings.default_locale,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -51,6 +51,18 @@
|
|||||||
/>
|
/>
|
||||||
{{i18n "admin.site_text.show_outdated"}}
|
{{i18n "admin.site_text.show_outdated"}}
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
|
{{#if this.showUntranslated}}
|
||||||
|
<label class="checkbox-label">
|
||||||
|
<input
|
||||||
|
id="toggle-untranslated"
|
||||||
|
type="checkbox"
|
||||||
|
checked={{this.resolvedUntranslated}}
|
||||||
|
{{on "click" this.toggleUntranslated}}
|
||||||
|
/>
|
||||||
|
{{i18n "admin.site_text.show_untranslated"}}
|
||||||
|
</label>
|
||||||
|
{{/if}}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -21,17 +21,18 @@ class Admin::SiteTextsController < Admin::AdminController
|
|||||||
def index
|
def index
|
||||||
overridden = params[:overridden] == "true"
|
overridden = params[:overridden] == "true"
|
||||||
outdated = params[:outdated] == "true"
|
outdated = params[:outdated] == "true"
|
||||||
|
untranslated = params[:untranslated] == "true"
|
||||||
extras = {}
|
extras = {}
|
||||||
|
|
||||||
query = params[:q] || ""
|
query = params[:q] || ""
|
||||||
|
|
||||||
locale = fetch_locale(params[:locale])
|
locale = fetch_locale(params[:locale])
|
||||||
|
|
||||||
if query.blank? && !overridden && !outdated
|
if query.blank? && !overridden && !outdated && !untranslated
|
||||||
extras[:recommended] = true
|
extras[:recommended] = true
|
||||||
results = self.class.preferred_keys.map { |k| record_for(key: k, locale: locale) }
|
results = self.class.preferred_keys.map { |k| record_for(key: k, locale: locale) }
|
||||||
else
|
else
|
||||||
results = find_translations(query, overridden, outdated, locale)
|
results = find_translations(query, overridden, outdated, locale, untranslated)
|
||||||
|
|
||||||
if results.any?
|
if results.any?
|
||||||
extras[:regex] = I18n::Backend::DiscourseI18n.create_search_regexp(query, as_string: true)
|
extras[:regex] = I18n::Backend::DiscourseI18n.create_search_regexp(query, as_string: true)
|
||||||
@ -209,9 +210,12 @@ class Admin::SiteTextsController < Admin::AdminController
|
|||||||
raise Discourse::NotFound
|
raise Discourse::NotFound
|
||||||
end
|
end
|
||||||
|
|
||||||
def find_translations(query, overridden, outdated, locale)
|
def find_translations(query, overridden, outdated, locale, untranslated)
|
||||||
translations = Hash.new { |hash, key| hash[key] = {} }
|
translations = Hash.new { |hash, key| hash[key] = {} }
|
||||||
search_results = I18n.with_locale(locale) { I18n.search(query, only_overridden: overridden) }
|
search_results =
|
||||||
|
I18n.with_locale(locale) do
|
||||||
|
I18n.search(query, only_overridden: overridden, only_untranslated: untranslated)
|
||||||
|
end
|
||||||
|
|
||||||
if outdated
|
if outdated
|
||||||
outdated_keys =
|
outdated_keys =
|
||||||
|
@ -6706,6 +6706,7 @@ en:
|
|||||||
recommended: "We recommend customizing the following text to suit your needs:"
|
recommended: "We recommend customizing the following text to suit your needs:"
|
||||||
show_overriden: "Only show overridden"
|
show_overriden: "Only show overridden"
|
||||||
show_outdated: "Only show outdated/invalid"
|
show_outdated: "Only show outdated/invalid"
|
||||||
|
show_untranslated: "Only show untranslated"
|
||||||
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."
|
||||||
no_results: "No matching site texts found"
|
no_results: "No matching site texts found"
|
||||||
|
@ -3225,3 +3225,7 @@ dashboard:
|
|||||||
hot_topics_recent_days:
|
hot_topics_recent_days:
|
||||||
hidden: true
|
hidden: true
|
||||||
default: 7
|
default: 7
|
||||||
|
admin_allow_filter_untranslated_text:
|
||||||
|
hidden: true
|
||||||
|
default: false
|
||||||
|
client: true
|
||||||
|
@ -78,7 +78,17 @@ module I18n
|
|||||||
results = {}
|
results = {}
|
||||||
regexp = I18n::Backend::DiscourseI18n.create_search_regexp(query)
|
regexp = I18n::Backend::DiscourseI18n.create_search_regexp(query)
|
||||||
|
|
||||||
if opts[:only_overridden]
|
if opts[:only_untranslated]
|
||||||
|
target = opts[:backend] || backend
|
||||||
|
|
||||||
|
target_strings = target.search(locale, query)
|
||||||
|
override_strings = overrides_by_locale(locale)
|
||||||
|
all_locale_strings = target_strings.merge(override_strings)
|
||||||
|
original_strings = target.search(:en, query)
|
||||||
|
untranslated =
|
||||||
|
original_strings.reject { |key, value| all_locale_strings.key?(key) || !value.present? }
|
||||||
|
add_if_matches(untranslated, results, regexp)
|
||||||
|
elsif opts[:only_overridden]
|
||||||
add_if_matches(overrides_by_locale(locale), results, regexp)
|
add_if_matches(overrides_by_locale(locale), results, regexp)
|
||||||
else
|
else
|
||||||
target = opts[:backend] || backend
|
target = opts[:backend] || backend
|
||||||
|
@ -187,6 +187,34 @@ RSpec.describe Admin::SiteTextsController do
|
|||||||
expect(value).to eq("education.new-topic override")
|
expect(value).to eq("education.new-topic override")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "returns only untranslated (english) strings" do
|
||||||
|
available_locales = I18n.config.available_locales
|
||||||
|
I18n.config.available_locales = %i[en test]
|
||||||
|
|
||||||
|
I18n.backend.store_translations(:en, { shrubbery: "Shrubbery" })
|
||||||
|
I18n.backend.store_translations(:en, { shrubbery2: "Shrubbery2" })
|
||||||
|
|
||||||
|
params = { q: "shrubbery", locale: "test", untranslated: "true" }
|
||||||
|
|
||||||
|
get "/admin/customize/site_texts.json", params: params
|
||||||
|
expect(response.status).to eq(200)
|
||||||
|
expect(response.parsed_body["site_texts"].size).to eq(2)
|
||||||
|
|
||||||
|
I18n.backend.store_translations(:test, { shrubbery: "Arbusto" })
|
||||||
|
|
||||||
|
get "/admin/customize/site_texts.json", params: params
|
||||||
|
expect(response.status).to eq(200)
|
||||||
|
expect(response.parsed_body["site_texts"].size).to eq(1)
|
||||||
|
|
||||||
|
TranslationOverride.upsert!(:test, "shrubbery2", "Arbusto2")
|
||||||
|
|
||||||
|
get "/admin/customize/site_texts.json", params: params
|
||||||
|
expect(response.status).to eq(200)
|
||||||
|
expect(response.parsed_body["site_texts"].size).to eq(0)
|
||||||
|
|
||||||
|
I18n.config.available_locales = available_locales
|
||||||
|
end
|
||||||
|
|
||||||
context "with plural keys" do
|
context "with plural keys" do
|
||||||
before do
|
before do
|
||||||
I18n.backend.store_translations(
|
I18n.backend.store_translations(
|
||||||
|
Loading…
Reference in New Issue
Block a user