mirror of
https://github.com/discourse/discourse.git
synced 2024-11-21 16:38:15 -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 overridden;
|
||||
@tracked outdated;
|
||||
@tracked untranslated;
|
||||
|
||||
@tracked model;
|
||||
|
||||
@tracked searching = false;
|
||||
@tracked preferred = false;
|
||||
|
||||
queryParams = ["q", "overridden", "outdated", "locale"];
|
||||
queryParams = ["q", "overridden", "outdated", "locale", "untranslated"];
|
||||
|
||||
get resolvedOverridden() {
|
||||
return [true, "true"].includes(this.overridden) ?? false;
|
||||
@ -35,10 +36,21 @@ export default class AdminSiteTextIndexController extends Controller {
|
||||
return [true, "true"].includes(this.outdated) ?? false;
|
||||
}
|
||||
|
||||
get resolvedUntranslated() {
|
||||
return [true, "true"].includes(this.untranslated) ?? false;
|
||||
}
|
||||
|
||||
get resolvedLocale() {
|
||||
return this.locale ?? this.siteSettings.default_locale;
|
||||
}
|
||||
|
||||
get showUntranslated() {
|
||||
return (
|
||||
this.siteSettings.admin_allow_filter_untranslated_text &&
|
||||
this.resolvedLocale !== "en"
|
||||
);
|
||||
}
|
||||
|
||||
async _performSearch() {
|
||||
try {
|
||||
this.model = await this.store.find("site-text", {
|
||||
@ -46,6 +58,7 @@ export default class AdminSiteTextIndexController extends Controller {
|
||||
overridden: this.resolvedOverridden,
|
||||
outdated: this.resolvedOutdated,
|
||||
locale: this.resolvedLocale,
|
||||
untranslated: this.resolvedUntranslated,
|
||||
});
|
||||
} finally {
|
||||
this.searching = false;
|
||||
@ -95,6 +108,17 @@ export default class AdminSiteTextIndexController extends Controller {
|
||||
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
|
||||
search() {
|
||||
const q = this.q;
|
||||
|
@ -11,6 +11,7 @@ export default class AdminSiteTextIndexRoute extends Route {
|
||||
q: { replace: true },
|
||||
overridden: { replace: true },
|
||||
outdated: { replace: true },
|
||||
untranslated: { replace: true },
|
||||
locale: { replace: true },
|
||||
};
|
||||
|
||||
@ -19,6 +20,7 @@ export default class AdminSiteTextIndexRoute extends Route {
|
||||
q: params.q,
|
||||
overridden: params.overridden ?? false,
|
||||
outdated: params.outdated ?? false,
|
||||
untranslated: params.untranslated ?? false,
|
||||
locale: params.locale ?? this.siteSettings.default_locale,
|
||||
});
|
||||
}
|
||||
|
@ -51,6 +51,18 @@
|
||||
/>
|
||||
{{i18n "admin.site_text.show_outdated"}}
|
||||
</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>
|
||||
</div>
|
||||
|
||||
|
@ -21,17 +21,18 @@ class Admin::SiteTextsController < Admin::AdminController
|
||||
def index
|
||||
overridden = params[:overridden] == "true"
|
||||
outdated = params[:outdated] == "true"
|
||||
untranslated = params[:untranslated] == "true"
|
||||
extras = {}
|
||||
|
||||
query = params[:q] || ""
|
||||
|
||||
locale = fetch_locale(params[:locale])
|
||||
|
||||
if query.blank? && !overridden && !outdated
|
||||
if query.blank? && !overridden && !outdated && !untranslated
|
||||
extras[:recommended] = true
|
||||
results = self.class.preferred_keys.map { |k| record_for(key: k, locale: locale) }
|
||||
else
|
||||
results = find_translations(query, overridden, outdated, locale)
|
||||
results = find_translations(query, overridden, outdated, locale, untranslated)
|
||||
|
||||
if results.any?
|
||||
extras[:regex] = I18n::Backend::DiscourseI18n.create_search_regexp(query, as_string: true)
|
||||
@ -209,9 +210,12 @@ class Admin::SiteTextsController < Admin::AdminController
|
||||
raise Discourse::NotFound
|
||||
end
|
||||
|
||||
def find_translations(query, overridden, outdated, locale)
|
||||
def find_translations(query, overridden, outdated, locale, untranslated)
|
||||
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
|
||||
outdated_keys =
|
||||
|
@ -6706,6 +6706,7 @@ en:
|
||||
recommended: "We recommend customizing the following text to suit your needs:"
|
||||
show_overriden: "Only show overridden"
|
||||
show_outdated: "Only show outdated/invalid"
|
||||
show_untranslated: "Only show untranslated"
|
||||
locale: "Language:"
|
||||
more_than_50_results: "There are more than 50 results. Please refine your search."
|
||||
no_results: "No matching site texts found"
|
||||
|
@ -3225,3 +3225,7 @@ dashboard:
|
||||
hot_topics_recent_days:
|
||||
hidden: true
|
||||
default: 7
|
||||
admin_allow_filter_untranslated_text:
|
||||
hidden: true
|
||||
default: false
|
||||
client: true
|
||||
|
@ -78,7 +78,17 @@ module I18n
|
||||
results = {}
|
||||
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)
|
||||
else
|
||||
target = opts[:backend] || backend
|
||||
|
@ -187,6 +187,34 @@ RSpec.describe Admin::SiteTextsController do
|
||||
expect(value).to eq("education.new-topic override")
|
||||
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
|
||||
before do
|
||||
I18n.backend.store_translations(
|
||||
|
Loading…
Reference in New Issue
Block a user