diff --git a/app/assets/javascripts/admin/addon/components/site-setting.gjs b/app/assets/javascripts/admin/addon/components/site-setting.gjs
index 60f47b22a98..0b989cacff7 100644
--- a/app/assets/javascripts/admin/addon/components/site-setting.gjs
+++ b/app/assets/javascripts/admin/addon/components/site-setting.gjs
@@ -43,6 +43,8 @@ const CUSTOM_TYPES = [
"file_size_restriction",
"file_types_list",
"font_list",
+ "locale_list",
+ "locale_enum",
];
export default class SiteSettingComponent extends Component {
diff --git a/app/assets/javascripts/admin/addon/components/site-settings/locale-enum.gjs b/app/assets/javascripts/admin/addon/components/site-settings/locale-enum.gjs
new file mode 100644
index 00000000000..eeab52edb8f
--- /dev/null
+++ b/app/assets/javascripts/admin/addon/components/site-settings/locale-enum.gjs
@@ -0,0 +1,34 @@
+import Component from "@glimmer/component";
+import { hash } from "@ember/helper";
+import { action } from "@ember/object";
+import { service } from "@ember/service";
+import ComboBox from "select-kit/components/combo-box";
+
+export default class LocaleEnum extends Component {
+ @service languageNameLookup;
+
+ get content() {
+ return this.args.setting.validValues.map(({ value }) => ({
+ name: this.languageNameLookup.getLanguageName(value),
+ value,
+ }));
+ }
+
+ @action
+ onChangeLocale(value) {
+ this.args.changeValueCallback(value);
+ }
+
+
+
+
+ {{@preview}}
+
+}
diff --git a/app/assets/javascripts/admin/addon/components/site-settings/locale-list.gjs b/app/assets/javascripts/admin/addon/components/site-settings/locale-list.gjs
new file mode 100644
index 00000000000..3972933619d
--- /dev/null
+++ b/app/assets/javascripts/admin/addon/components/site-settings/locale-list.gjs
@@ -0,0 +1,43 @@
+import Component from "@glimmer/component";
+import { hash } from "@ember/helper";
+import { action } from "@ember/object";
+import { service } from "@ember/service";
+import ListSetting from "select-kit/components/list-setting";
+
+export default class LocaleList extends Component {
+ @service siteSettings;
+
+ tokenSeparator = "|";
+
+ get choices() {
+ const allLocales = this.siteSettings.available_locales;
+ return this.args.setting.validValues.map(({ value, name }) => ({
+ name: allLocales.find((locale) => locale.value === value)?.name || name,
+ value,
+ }));
+ }
+
+ get settingValue() {
+ return this.args.value
+ .toString()
+ .split(this.tokenSeparator)
+ .filter(Boolean);
+ }
+
+ @action
+ onChangeListSetting(value) {
+ this.args.changeValueCallback(value.join(this.tokenSeparator));
+ }
+
+
+
+
+}
diff --git a/app/assets/javascripts/admin/addon/controllers/admin-customize-themes-show-index.js b/app/assets/javascripts/admin/addon/controllers/admin-customize-themes-show-index.js
index 8f9c5a1814a..72961091e1c 100644
--- a/app/assets/javascripts/admin/addon/controllers/admin-customize-themes-show-index.js
+++ b/app/assets/javascripts/admin/addon/controllers/admin-customize-themes-show-index.js
@@ -285,7 +285,7 @@ export default class AdminCustomizeThemesShowIndexController extends Controller
}
get availableLocales() {
- return JSON.parse(this.siteSettings.available_locales);
+ return this.siteSettings.available_locales;
}
get locale() {
diff --git a/app/assets/javascripts/admin/addon/controllers/admin-site-text-index.js b/app/assets/javascripts/admin/addon/controllers/admin-site-text-index.js
index 07aa61b57ef..51ba7a1b8ca 100644
--- a/app/assets/javascripts/admin/addon/controllers/admin-site-text-index.js
+++ b/app/assets/javascripts/admin/addon/controllers/admin-site-text-index.js
@@ -79,7 +79,7 @@ export default class AdminSiteTextIndexController extends Controller {
}
get availableLocales() {
- return JSON.parse(this.siteSettings.available_locales);
+ return this.siteSettings.available_locales;
}
get fallbackLocaleFullName() {
diff --git a/app/assets/javascripts/admin/addon/routes/admin-site-text-edit.js b/app/assets/javascripts/admin/addon/routes/admin-site-text-edit.js
index 817f91f389d..d96e492c4cb 100644
--- a/app/assets/javascripts/admin/addon/routes/admin-site-text-edit.js
+++ b/app/assets/javascripts/admin/addon/routes/admin-site-text-edit.js
@@ -15,7 +15,7 @@ export default class AdminSiteTextEditRoute extends Route {
}
setupController(controller, siteText) {
- const locales = JSON.parse(this.siteSettings.available_locales);
+ const locales = this.siteSettings.available_locales;
const localeFullName = locales.find((locale) => {
return locale.value === controller.locale;
diff --git a/app/assets/javascripts/discourse/app/components/language-switcher.gjs b/app/assets/javascripts/discourse/app/components/language-switcher.gjs
index 1c23e975386..fa872f17055 100644
--- a/app/assets/javascripts/discourse/app/components/language-switcher.gjs
+++ b/app/assets/javascripts/discourse/app/components/language-switcher.gjs
@@ -11,6 +11,7 @@ export default class LanguageSwitcher extends Component {
@service site;
@service siteSettings;
@service router;
+ @service languageNameLookup;
@action
async changeLocale(locale) {
@@ -21,6 +22,15 @@ export default class LanguageSwitcher extends Component {
window.location.reload();
}
+ get content() {
+ return this.siteSettings.available_content_localization_locales.map(
+ ({ value }) => ({
+ name: this.languageNameLookup.getLanguageName(value),
+ value,
+ })
+ );
+ }
+
@action
onRegisterApi(api) {
this.dMenu = api;
@@ -36,10 +46,7 @@ export default class LanguageSwitcher extends Component {
>
<:content>
- {{#each
- this.siteSettings.available_content_localization_locales
- as |option|
- }}
+ {{#each this.content as |option|}}
diff --git a/app/assets/javascripts/discourse/app/components/post-language-selector.gjs b/app/assets/javascripts/discourse/app/components/post-language-selector.gjs
index 749249007fa..a9698213fd8 100644
--- a/app/assets/javascripts/discourse/app/components/post-language-selector.gjs
+++ b/app/assets/javascripts/discourse/app/components/post-language-selector.gjs
@@ -8,6 +8,7 @@ import DMenu from "float-kit/components/d-menu";
export default class PostLanguageSelector extends Component {
@service siteSettings;
+ @service languageNameLookup;
get selectedLanguage() {
return (
@@ -17,6 +18,15 @@ export default class PostLanguageSelector extends Component {
);
}
+ get content() {
+ return this.siteSettings.available_content_localization_locales.map(
+ ({ value }) => ({
+ name: this.languageNameLookup.getLanguageName(value),
+ value,
+ })
+ );
+ }
+
@action
selectPostLanguage(locale) {
this.args.composerModel.locale = locale;
@@ -40,10 +50,7 @@ export default class PostLanguageSelector extends Component {
>
<:content>
- {{#each
- this.siteSettings.available_content_localization_locales
- as |locale|
- }}
+ {{#each this.content as |locale|}}
locale.value !== originalPostLocale
- );
+ return this.siteSettings.available_content_localization_locales
+ .filter(({ value }) => value !== originalPostLocale)
+ .map(({ native_name, name, value }) => {
+ name =
+ i18n(name) === native_name
+ ? native_name
+ : `${i18n(name)} (${native_name})`;
+
+ return { name, value };
+ });
}
@action
diff --git a/app/assets/javascripts/discourse/app/components/post/meta-data/language.gjs b/app/assets/javascripts/discourse/app/components/post/meta-data/language.gjs
index a4691facd7e..0625d56aade 100644
--- a/app/assets/javascripts/discourse/app/components/post/meta-data/language.gjs
+++ b/app/assets/javascripts/discourse/app/components/post/meta-data/language.gjs
@@ -1,12 +1,16 @@
import Component from "@glimmer/component";
+import { service } from "@ember/service";
import { i18n } from "discourse-i18n";
import DTooltip from "float-kit/components/d-tooltip";
export default class PostMetaDataLanguage extends Component {
// TODO (glimmer-post-stream) once we switch to glimmer, we can remove `this.args.data.x` from the following 2 getters
+ @service languageNameLookup;
+
get language() {
- return this.args.data?.language || this.args.post?.language;
+ const lang = this.args.data?.language || this.args.post?.language;
+ return this.languageNameLookup.getLanguageName(lang);
}
get outdated() {
diff --git a/app/assets/javascripts/discourse/app/controllers/preferences/interface.js b/app/assets/javascripts/discourse/app/controllers/preferences/interface.js
index 7794b7486a8..ad3cd7c1c15 100644
--- a/app/assets/javascripts/discourse/app/controllers/preferences/interface.js
+++ b/app/assets/javascripts/discourse/app/controllers/preferences/interface.js
@@ -91,7 +91,7 @@ export default class InterfaceController extends Controller {
@discourseComputed()
availableLocales() {
- return JSON.parse(this.siteSettings.available_locales);
+ return this.siteSettings.available_locales;
}
@discourseComputed
diff --git a/app/assets/javascripts/discourse/app/controllers/topic.js b/app/assets/javascripts/discourse/app/controllers/topic.js
index 83c6ae8a8ea..3945bb99b95 100644
--- a/app/assets/javascripts/discourse/app/controllers/topic.js
+++ b/app/assets/javascripts/discourse/app/controllers/topic.js
@@ -73,6 +73,7 @@ export default class TopicController extends Controller {
@service siteSettings;
@service site;
@service appEvents;
+ @service languageNameLookup;
@tracked model;
@@ -897,9 +898,10 @@ export default class TopicController extends Controller {
return this._openComposerForEdit(topic, post);
}
+ const language = this.languageNameLookup.getLanguageName(post.language);
return this.dialog.alert({
message: i18n("post.localizations.edit_warning.message", {
- language: post.language,
+ language,
}),
buttons: [
{
diff --git a/app/assets/javascripts/discourse/app/services/language-name-lookup.js b/app/assets/javascripts/discourse/app/services/language-name-lookup.js
new file mode 100644
index 00000000000..13ed14403dd
--- /dev/null
+++ b/app/assets/javascripts/discourse/app/services/language-name-lookup.js
@@ -0,0 +1,14 @@
+import Service, { service } from "@ember/service";
+import { disableImplicitInjections } from "discourse/lib/implicit-injections";
+
+@disableImplicitInjections
+export default class LanguageNameLookup extends Service {
+ @service siteSettings;
+
+ getLanguageName(locale) {
+ const name = this.siteSettings.available_locales.find(
+ ({ value }) => value === locale
+ )?.name;
+ return name || locale;
+ }
+}
diff --git a/app/assets/javascripts/discourse/app/services/site-settings.js b/app/assets/javascripts/discourse/app/services/site-settings.js
index f5df616a0fa..6de9918574c 100644
--- a/app/assets/javascripts/discourse/app/services/site-settings.js
+++ b/app/assets/javascripts/discourse/app/services/site-settings.js
@@ -1,6 +1,7 @@
import { TrackedObject } from "@ember-compat/tracked-built-ins";
import { disableImplicitInjections } from "discourse/lib/implicit-injections";
import PreloadStore from "discourse/lib/preload-store";
+import i18n from "discourse-i18n";
export function createSiteSettingsFromPreloaded(
siteSettings,
@@ -15,6 +16,22 @@ export function createSiteSettingsFromPreloaded(
settings.themeSiteSettingOverrides = themeSiteSettingOverrides;
}
+ // localize locale names here as they are not localized in the backend
+ // due to initialization order and caching
+ if (settings.available_locales) {
+ const locales = JSON.parse(settings.available_locales);
+ const localizedLocales = locales.map(({ native_name, value, name }) => {
+ const localized_name = i18n.t(name);
+ const displayName =
+ localized_name && localized_name !== native_name
+ ? `${localized_name} (${native_name})`
+ : native_name;
+ return { value, name: displayName };
+ });
+
+ settings.available_locales = localizedLocales;
+ }
+
settings.groupSettingArray = (groupSetting) => {
const setting = settings[groupSetting];
if (!setting) {
diff --git a/app/assets/javascripts/discourse/app/static/wizard/components/fields/dropdown.gjs b/app/assets/javascripts/discourse/app/static/wizard/components/fields/dropdown.gjs
index b6366671af0..64d7c0a6971 100644
--- a/app/assets/javascripts/discourse/app/static/wizard/components/fields/dropdown.gjs
+++ b/app/assets/javascripts/discourse/app/static/wizard/components/fields/dropdown.gjs
@@ -1,6 +1,7 @@
import Component from "@glimmer/component";
import { hash } from "@ember/helper";
import { action, set } from "@ember/object";
+import { service } from "@ember/service";
import { Choice } from "discourse/static/wizard/models/wizard";
import { i18n } from "discourse-i18n";
import ColorPalettes from "select-kit/components/color-palettes";
@@ -9,6 +10,8 @@ import FontSelector from "select-kit/components/font-selector";
import HomepageStyleSelector from "select-kit/components/homepage-style-selector";
export default class Dropdown extends Component {
+ @service siteSettings;
+
constructor() {
super(...arguments);
@@ -69,6 +72,16 @@ export default class Dropdown extends Component {
);
}
}
+
+ if (this.args.field.id === "default_locale") {
+ this.args.field.choices = this.siteSettings.available_locales.map(
+ (locale) =>
+ new Choice({
+ id: locale.value,
+ label: locale.name,
+ })
+ );
+ }
}
get component() {
@@ -86,6 +99,15 @@ export default class Dropdown extends Component {
}
}
+ get nameProperty() {
+ switch (this.args.field.id) {
+ case "default_locale":
+ return "name";
+ default:
+ return "label";
+ }
+ }
+
keyPress(event) {
event.stopPropagation();
}
@@ -101,7 +123,7 @@ export default class Dropdown extends Component {
class="wizard-container__dropdown"
value=@field.value
content=@field.choices
- nameProperty="label"
+ nameProperty=this.nameProperty
tabindex="9"
onChange=this.onChangeValug
options=(hash translatedNone=false)
diff --git a/app/assets/javascripts/discourse/tests/acceptance/admin-site-text-test.js b/app/assets/javascripts/discourse/tests/acceptance/admin-site-text-test.js
index 1dcf0fc5a37..783811c1236 100644
--- a/app/assets/javascripts/discourse/tests/acceptance/admin-site-text-test.js
+++ b/app/assets/javascripts/discourse/tests/acceptance/admin-site-text-test.js
@@ -5,7 +5,7 @@ import { acceptance } from "discourse/tests/helpers/qunit-helpers";
acceptance("Admin - Site Texts", function (needs) {
needs.user();
needs.settings({
- available_locales: JSON.stringify([{ name: "English", value: "en" }]),
+ available_locales: [{ name: "English", value: "en" }],
default_locale: "en",
});
diff --git a/app/assets/javascripts/discourse/tests/integration/components/post/post-test.gjs b/app/assets/javascripts/discourse/tests/integration/components/post/post-test.gjs
index eae3b73e19b..6cbefff243a 100644
--- a/app/assets/javascripts/discourse/tests/integration/components/post/post-test.gjs
+++ b/app/assets/javascripts/discourse/tests/integration/components/post/post-test.gjs
@@ -292,29 +292,35 @@ module("Integration | Component | Post", function (hooks) {
test("language", async function (assert) {
this.post.is_localized = true;
- this.post.language = "English";
+ this.post.language = "en";
+ this.siteSettings.available_locales = [
+ { value: "en", name: "English (US)" },
+ ];
await renderComponent(this.post);
await triggerEvent(".fk-d-tooltip__trigger", "pointermove");
assert.dom(".post-language").hasText(
i18n("post.original_language", {
- language: "English",
+ language: "English (US)",
})
);
});
test("outdated localization", async function (assert) {
this.post.is_localized = true;
- this.post.language = "English";
+ this.post.language = "en";
this.post.localization_outdated = true;
+ this.siteSettings.available_locales = [
+ { value: "en", name: "English (US)" },
+ ];
await renderComponent(this.post);
await triggerEvent(".fk-d-tooltip__trigger", "pointermove");
assert.dom(".post-language").hasText(
i18n("post.original_language_and_outdated", {
- language: "English",
+ language: "English (US)",
})
);
});
diff --git a/app/models/locale_site_setting.rb b/app/models/locale_site_setting.rb
index 5d23a146566..704690c6d9d 100644
--- a/app/models/locale_site_setting.rb
+++ b/app/models/locale_site_setting.rb
@@ -1,16 +1,20 @@
# frozen_string_literal: true
class LocaleSiteSetting < EnumSiteSetting
+ def self.translate_names?
+ true
+ end
+
def self.valid_value?(val)
- supported_locales.include?(val)
+ val.split("|").all? { |v| supported_locales.include?(v) }
end
def self.values
- @values ||=
- supported_locales.map do |locale|
- lang = language_names[locale] || language_names[locale.split("_")[0]]
- { name: lang ? lang["nativeName"] : locale, value: locale }
- end
+ supported_locales.map do |locale|
+ lang = language_names[locale] || language_names[locale.split("_").first]
+ native_name = lang&.dig("nativeName")
+ { native_name:, value: locale, name: "languages.#{locale}.name" }
+ end
end
@lock = Mutex.new
@@ -53,10 +57,6 @@ class LocaleSiteSetting < EnumSiteSetting
@lock.synchronize { @values = @language_names = @supported_locales = nil }
end
- def self.get_language_name(locale)
- values.find { |v| v[:value] == locale.to_s.sub("-", "_") }&.[](:name)
- end
-
FALLBACKS = { en_GB: :en }
def self.fallback_locale(locale)
diff --git a/app/serializers/post_revision_serializer.rb b/app/serializers/post_revision_serializer.rb
index da4bf5da057..fa4f92bec0f 100644
--- a/app/serializers/post_revision_serializer.rb
+++ b/app/serializers/post_revision_serializer.rb
@@ -194,9 +194,8 @@ class PostRevisionSerializer < ApplicationSerializer
end
def locale_changes
- prev = LocaleSiteSetting.get_language_name(previous["locale"])
- cur = LocaleSiteSetting.get_language_name(current["locale"])
-
+ prev = previous["locale"].presence
+ cur = current["locale"].presence
{ previous: prev, current: cur }
end
diff --git a/app/serializers/post_serializer.rb b/app/serializers/post_serializer.rb
index cb5a6828864..b3d3ae8b881 100644
--- a/app/serializers/post_serializer.rb
+++ b/app/serializers/post_serializer.rb
@@ -688,7 +688,7 @@ class PostSerializer < BasicPostSerializer
end
def language
- LocaleSiteSetting.get_language_name(object.locale) || locale
+ locale
end
def include_language?
diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml
index 15bd736d12b..cbae1ab3577 100644
--- a/config/locales/client.en.yml
+++ b/config/locales/client.en.yml
@@ -155,6 +155,105 @@ en:
placeholder: date
from_placeholder: "from date"
to_placeholder: "to date"
+ languages:
+ ar:
+ name: Arabic
+ be:
+ name: Belarusian
+ bg:
+ name: Bulgarian
+ bs_BA:
+ name: Bosnian
+ ca:
+ name: Catalan
+ cs:
+ name: Czech
+ da:
+ name: Danish
+ de:
+ name: German
+ el:
+ name: Greek
+ en:
+ name: English (US)
+ en_GB:
+ name: English (UK)
+ es:
+ name: Spanish
+ et:
+ name: Estonian
+ fa_IR:
+ name: Persian
+ fi:
+ name: Finnish
+ fr:
+ name: French
+ gl:
+ name: Galician
+ he:
+ name: Hebrew
+ hr:
+ name: Croatian
+ hu:
+ name: Hungarian
+ hy:
+ name: Armenian
+ id:
+ name: Indonesian
+ it:
+ name: Italian
+ ja:
+ name: Japanese
+ ko:
+ name: Korean
+ lt:
+ name: Lithuanian
+ lv:
+ name: Latvian
+ nb_NO:
+ name: Norwegian Bokmål
+ nl:
+ name: Dutch
+ pl_PL:
+ name: Polish
+ pt:
+ name: Portuguese
+ pt_BR:
+ name: Portuguese
+ ro:
+ name: Romanian
+ ru:
+ name: Russian
+ sk:
+ name: Slovak
+ sl:
+ name: Slovene
+ sq:
+ name: Albanian
+ sr:
+ name: Serbian
+ sv:
+ name: Swedish
+ sw:
+ name: Swahili
+ te:
+ name: Telugu
+ th:
+ name: Thai
+ tr_TR:
+ name: Turkish
+ ug:
+ name: Uyghur
+ uk:
+ name: Ukrainian
+ ur:
+ name: Urdu
+ vi:
+ name: Vietnamese
+ zh_TW:
+ name: Chinese
+ zh_CN:
+ name: Chinese Simplified
share:
topic_html: 'Topic: %{topicTitle}'
post: "post #%{postNumber} by @%{username}"
diff --git a/config/site_settings.yml b/config/site_settings.yml
index cac27714e9a..52806c34af4 100644
--- a/config/site_settings.yml
+++ b/config/site_settings.yml
@@ -1638,9 +1638,9 @@ content_localization:
default: ""
type: list
client: true
- list_type: named
+ list_type: locale
allow_any: false
- choices: "LocaleSiteSetting.values"
+ enum: "LocaleSiteSetting"
area: "localization"
validator: "ContentLocalizationLocalesValidator"
content_localization_max_locales:
diff --git a/lib/site_setting_extension.rb b/lib/site_setting_extension.rb
index a579189024b..ae90df2c9e9 100644
--- a/lib/site_setting_extension.rb
+++ b/lib/site_setting_extension.rb
@@ -273,7 +273,7 @@ module SiteSettingExtension
default: SiteSettings::DefaultsProvider::DEFAULT_LOCALE,
category: "required",
description: description("default_locale"),
- type: SiteSetting.types[SiteSetting.types[:enum]],
+ type: SiteSetting.types[SiteSetting.types[:locale_enum]],
preview: nil,
value: self.default_locale,
valid_values: LocaleSiteSetting.values,
@@ -963,10 +963,8 @@ module SiteSettingExtension
plugins[name] = opts[:plugin] if opts[:plugin]
- type_supervisor.load_setting(
- name,
- opts.extract!(*SiteSettings::TypeSupervisor::CONSUMED_OPTS),
- )
+ choices_opts = opts.extract!(*SiteSettings::TypeSupervisor::CONSUMED_OPTS)
+ type_supervisor.load_setting(name, choices_opts)
if !shadowed_val.nil?
setup_shadowed_methods(name, shadowed_val)
diff --git a/lib/site_settings/type_supervisor.rb b/lib/site_settings/type_supervisor.rb
index dc16881b9eb..46b81e282d6 100644
--- a/lib/site_settings/type_supervisor.rb
+++ b/lib/site_settings/type_supervisor.rb
@@ -61,6 +61,7 @@ class SiteSettings::TypeSupervisor
tag_group_list: 26,
file_size_restriction: 27,
objects: 28,
+ locale_enum: 29,
)
end
@@ -180,9 +181,10 @@ class SiteSettings::TypeSupervisor
def type_hash(name)
name = name.to_sym
type = get_type(name)
+ list_type = get_list_type(name)
result = { type: type.to_s }
- if type == :enum
+ if type == :enum || list_type == "locale"
if (klass = get_enum_class(name))
result.merge!(valid_values: klass.values, translate_names: klass.translate_names?)
else
@@ -231,7 +233,7 @@ class SiteSettings::TypeSupervisor
end
def validate_value(name, type, val)
- if type == self.class.types[:enum]
+ if type == self.class.types[:enum] || get_list_type(name) == "locale"
if get_enum_class(name)
unless get_enum_class(name).valid_value?(val)
raise Discourse::InvalidParameters.new("Invalid value `#{val}` for `#{name}`")
@@ -243,9 +245,7 @@ class SiteSettings::TypeSupervisor
raise Discourse::InvalidParameters.new(:value) if choice.exclude?(val)
end
- end
-
- if type == self.class.types[:list] || type == self.class.types[:string]
+ elsif type == self.class.types[:list] || type == self.class.types[:string]
if @allow_any.key?(name) && !@allow_any[name]
split = val.to_s.split("|")
resolved_choices = @choices[name]
diff --git a/lib/wizard/builder.rb b/lib/wizard/builder.rb
index a40ffaeb25f..2c011223ffa 100644
--- a/lib/wizard/builder.rb
+++ b/lib/wizard/builder.rb
@@ -39,17 +39,12 @@ class Wizard
value: SiteSetting.site_description,
)
- languages =
- step.add_field(
- id: "default_locale",
- type: "dropdown",
- required: false,
- value: SiteSetting.default_locale,
- )
-
- LocaleSiteSetting.values.each do |locale|
- languages.add_choice(locale[:value], label: locale[:name])
- end
+ step.add_field(
+ id: "default_locale",
+ type: "dropdown",
+ required: false,
+ value: SiteSetting.default_locale,
+ )
step.on_update do |updater|
updater.ensure_changed(:title)
diff --git a/plugins/discourse-ai/assets/javascripts/discourse/components/ai-composer-helper-menu.gjs b/plugins/discourse-ai/assets/javascripts/discourse/components/ai-composer-helper-menu.gjs
index 40a35e425c3..3523e14e6cc 100644
--- a/plugins/discourse-ai/assets/javascripts/discourse/components/ai-composer-helper-menu.gjs
+++ b/plugins/discourse-ai/assets/javascripts/discourse/components/ai-composer-helper-menu.gjs
@@ -42,9 +42,7 @@ export default class AiComposerHelperMenu extends Component {
// Since we want site default translations (and we are using: force_default_locale)
// we need to replace the translated_name with the site default locale name
const siteLocale = this.siteSettings.default_locale;
- const availableLocales = JSON.parse(
- this.siteSettings.available_locales
- );
+ const availableLocales = this.siteSettings.available_locales;
const locale = availableLocales.find((l) => l.value === siteLocale);
const translatedName = i18n(
"discourse_ai.ai_helper.context_menu.translate_prompt",
diff --git a/plugins/discourse-calendar/assets/javascripts/discourse/components/region-input.js b/plugins/discourse-calendar/assets/javascripts/discourse/components/region-input.js
index 372bf508946..b62df85756a 100644
--- a/plugins/discourse-calendar/assets/javascripts/discourse/components/region-input.js
+++ b/plugins/discourse-calendar/assets/javascripts/discourse/components/region-input.js
@@ -22,7 +22,7 @@ export default class RegionInput extends ComboBoxComponent {
const localeNames = {};
let regions = [];
- JSON.parse(this.siteSettings.available_locales).forEach((locale) => {
+ this.siteSettings.available_locales.forEach((locale) => {
localeNames[locale.value] = locale.name;
});
diff --git a/plugins/discourse-calendar/test/javascripts/acceptance/admin-holidays-test.js b/plugins/discourse-calendar/test/javascripts/acceptance/admin-holidays-test.js
index 50f097a8979..e6d6f885a3d 100644
--- a/plugins/discourse-calendar/test/javascripts/acceptance/admin-holidays-test.js
+++ b/plugins/discourse-calendar/test/javascripts/acceptance/admin-holidays-test.js
@@ -7,7 +7,7 @@ acceptance("Admin - Discourse Calendar - Holidays", function (needs) {
needs.user();
needs.settings({
calendar_enabled: true,
- available_locales: JSON.stringify([{ name: "English", value: "en" }]),
+ available_locales: [{ name: "English", value: "en" }],
});
needs.pretender((server, helper) => {
diff --git a/plugins/discourse-calendar/test/javascripts/integration/components/region-input-test.gjs b/plugins/discourse-calendar/test/javascripts/integration/components/region-input-test.gjs
index 5b6825144d2..74c5800dc4d 100644
--- a/plugins/discourse-calendar/test/javascripts/integration/components/region-input-test.gjs
+++ b/plugins/discourse-calendar/test/javascripts/integration/components/region-input-test.gjs
@@ -8,9 +8,7 @@ module("Integration | Component | region-input", function (hooks) {
setupRenderingTest(hooks);
test("displaying the 'None' region option", async function (assert) {
- this.siteSettings.available_locales = JSON.stringify([
- { name: "English", value: "en" },
- ]);
+ this.siteSettings.available_locales = [{ name: "English", value: "en" }];
await render(
@@ -26,9 +24,7 @@ module("Integration | Component | region-input", function (hooks) {
});
test("hiding the 'None' region option", async function (assert) {
- this.siteSettings.available_locales = JSON.stringify([
- { name: "English", value: "en" },
- ]);
+ this.siteSettings.available_locales = [{ name: "English", value: "en" }];
await render(
diff --git a/spec/models/locale_site_setting_spec.rb b/spec/models/locale_site_setting_spec.rb
index 8df0cbe6fa2..38ecffb1d1f 100644
--- a/spec/models/locale_site_setting_spec.rb
+++ b/spec/models/locale_site_setting_spec.rb
@@ -8,7 +8,7 @@ RSpec.describe LocaleSiteSetting do
def native_locale_name(locale)
value = LocaleSiteSetting.values.find { |v| v[:value] == locale }
- value[:name]
+ value[:native_name]
end
describe ".valid_value?" do
@@ -56,7 +56,11 @@ RSpec.describe LocaleSiteSetting do
end
after do
- DiscoursePluginRegistry.reset!
+ DiscoursePluginRegistry.unregister_locale("foo")
+ DiscoursePluginRegistry.unregister_locale("bar")
+ DiscoursePluginRegistry.unregister_locale("de")
+ DiscoursePluginRegistry.unregister_locale("de_AT")
+ DiscoursePluginRegistry.unregister_locale("tlh")
LocaleSiteSetting.reset!
end
@@ -64,6 +68,7 @@ RSpec.describe LocaleSiteSetting do
it "returns true for locales from core" do
expect(LocaleSiteSetting.valid_value?("en")).to eq(true)
expect(LocaleSiteSetting.valid_value?("de")).to eq(true)
+ expect(LocaleSiteSetting.valid_value?("en|de")).to eq(true)
end
it "returns true for locales added by plugins" do
@@ -82,8 +87,8 @@ RSpec.describe LocaleSiteSetting do
expect(native_locale_name("de")).to eq("Deutsch")
end
- it "returns the language code when no nativeName is set" do
- expect(native_locale_name("tlh")).to eq("tlh")
+ it "returns nothing when no nativeName is set" do
+ expect(native_locale_name("tlh")).to eq(nil)
end
end
@@ -116,19 +121,4 @@ RSpec.describe LocaleSiteSetting do
end
end
end
-
- describe ".get_language_name" do
- it "returns the language name for a valid locale" do
- expect(LocaleSiteSetting.get_language_name("en")).to eq("English (US)")
- expect(LocaleSiteSetting.get_language_name("es")).to eq("Español")
- end
-
- it "returns nil for a locale that doesn't exist" do
- expect(LocaleSiteSetting.get_language_name("xx")).to be_nil
- end
-
- it "handles symbol locales" do
- expect(LocaleSiteSetting.get_language_name(:en_GB)).to eq("English (UK)")
- end
- end
end
diff --git a/spec/requests/steps_controller_spec.rb b/spec/requests/steps_controller_spec.rb
index 5defbd84fe5..e31529b4511 100644
--- a/spec/requests/steps_controller_spec.rb
+++ b/spec/requests/steps_controller_spec.rb
@@ -43,7 +43,8 @@ RSpec.describe StepsController do
end
it "returns errors if the field has them" do
- put "/wizard/steps/introduction.json", params: { fields: { title: "" } }
+ title = SiteSetting.title
+ put "/wizard/steps/introduction.json", params: { fields: { title: } }
expect(response.status).to eq(422)
end
diff --git a/spec/serializers/post_revision_serializer_spec.rb b/spec/serializers/post_revision_serializer_spec.rb
index ce4e7739ff6..b8b81a5a2e3 100644
--- a/spec/serializers/post_revision_serializer_spec.rb
+++ b/spec/serializers/post_revision_serializer_spec.rb
@@ -156,7 +156,7 @@ RSpec.describe PostRevisionSerializer do
root: false,
).as_json
- expect(json[:locale_changes][:previous]).to eq("日本語")
+ expect(json[:locale_changes][:previous]).to eq("ja")
expect(json[:locale_changes][:current]).to eq(nil)
end
@@ -173,7 +173,7 @@ RSpec.describe PostRevisionSerializer do
).as_json
expect(json[:locale_changes][:previous]).to eq(nil)
- expect(json[:locale_changes][:current]).to eq("日本語")
+ expect(json[:locale_changes][:current]).to eq("ja")
end
end
end
diff --git a/spec/serializers/post_serializer_spec.rb b/spec/serializers/post_serializer_spec.rb
index 8927e36784e..967baa531a9 100644
--- a/spec/serializers/post_serializer_spec.rb
+++ b/spec/serializers/post_serializer_spec.rb
@@ -788,7 +788,7 @@ RSpec.describe PostSerializer do
SiteSetting.content_localization_enabled = true
post.update!(locale: "ja")
- expect(json[:language]).to eq("日本語")
+ expect(json[:language]).to eq("ja")
end
it "defaults to locale if language does not exist" do
diff --git a/spec/system/admin_site_setting_locale_spec.rb b/spec/system/admin_site_setting_locale_spec.rb
new file mode 100644
index 00000000000..a3eba49b152
--- /dev/null
+++ b/spec/system/admin_site_setting_locale_spec.rb
@@ -0,0 +1,51 @@
+# frozen_string_literal: true
+
+describe "Admin Site Setting Locales", type: :system do
+ let(:settings_page) { PageObjects::Pages::AdminSiteSettings.new }
+ fab!(:admin)
+
+ before do
+ sign_in(admin)
+ SiteSetting.default_locale = "es"
+ SiteSetting.content_localization_supported_locales = "es|en"
+ end
+
+ context "for locale enum" do
+ it "allows selection of a different locale" do
+ settings_page.visit
+
+ settings_page.type_in_search("default locale")
+ expect(settings_page.find_setting("default_locale")).to have_content("Spanish (Español)")
+
+ settings_page.select_enum_value("default_locale", "en")
+ settings_page.save_setting("default_locale")
+
+ settings_page.type_in_search("default locale")
+ expect(settings_page.find_setting("default_locale")).to have_content("English (US)")
+ end
+ end
+
+ context "for locale lists" do
+ it "allows adding and removing locales" do
+ SiteSetting.content_localization_supported_locales = "ja"
+ sign_in(admin)
+
+ settings_page.visit("content_localization_supported_locales")
+ expect(settings_page.find_setting("content_localization_supported_locales")).to have_content(
+ "Japanese (日本語)",
+ )
+
+ settings_page.select_list_values("content_localization_supported_locales", %w[en])
+ settings_page.save_setting("content_localization_supported_locales")
+ expect(settings_page.find_setting("content_localization_supported_locales")).to have_content(
+ "Japanese (日本語), English (US)",
+ )
+
+ # confirm persist on reload
+ settings_page.visit("content_localization_supported_locales")
+ expect(settings_page.find_setting("content_localization_supported_locales")).to have_content(
+ "Japanese (日本語), English (US)",
+ )
+ end
+ end
+end
diff --git a/spec/system/anon_language_switcher_spec.rb b/spec/system/anon_language_switcher_spec.rb
index 919971621a1..b4e28e1cbb1 100644
--- a/spec/system/anon_language_switcher_spec.rb
+++ b/spec/system/anon_language_switcher_spec.rb
@@ -45,8 +45,8 @@ RSpec.describe "Anonymous user language switcher", type: :system do
switcher.expand
expect(switcher).to have_content("English (US)")
- expect(switcher).to have_content("日本語")
- expect(switcher).to have_content("Español")
+ expect(switcher).to have_content("Japanese (日本語)")
+ expect(switcher).to have_content("Spanish (Español)")
SiteSetting.content_localization_supported_locales = "ja"
visit("/")
diff --git a/spec/system/content_localization_spec.rb b/spec/system/content_localization_spec.rb
index 456ed0f4426..7efc1d42ebe 100644
--- a/spec/system/content_localization_spec.rb
+++ b/spec/system/content_localization_spec.rb
@@ -191,11 +191,16 @@ describe "Content Localization" do
let(:banner) { PageObjects::Components::AdminChangesBanner.new }
it "does not allow more than the maximum number of locales" do
+ SiteSetting.content_localization_supported_locales = "en|ja"
SiteSetting.content_localization_max_locales = 2
sign_in(admin)
settings_page.visit("content_localization_supported_locales")
- settings_page.select_list_values("content_localization_supported_locales", %w[en ja es])
+ expect(settings_page.find_setting("content_localization_supported_locales")).to have_content(
+ "English (US), Japanese",
+ )
+
+ settings_page.select_list_values("content_localization_supported_locales", %w[es])
settings_page.save_setting("content_localization_supported_locales")
expect(settings_page.error_message("content_localization_supported_locales")).to have_content(
I18n.t(
diff --git a/spec/system/page_objects/pages/admin_site_settings.rb b/spec/system/page_objects/pages/admin_site_settings.rb
index ff306c74976..92865892497 100644
--- a/spec/system/page_objects/pages/admin_site_settings.rb
+++ b/spec/system/page_objects/pages/admin_site_settings.rb
@@ -41,6 +41,16 @@ module PageObjects
self
end
+ def select_enum_value(setting_name, value)
+ setting =
+ PageObjects::Components::SelectKit.new(
+ ".row.setting[data-setting='#{setting_name}'] .single-select",
+ )
+ setting.expand
+ setting.select_row_by_value(value)
+ self
+ end
+
def has_setting?(setting_name)
has_css?(".row.setting[data-setting=\"#{setting_name}\"]")
end
diff --git a/spec/system/post_translation_spec.rb b/spec/system/post_translation_spec.rb
index 58aed5e5fde..29dcb069c9c 100644
--- a/spec/system/post_translation_spec.rb
+++ b/spec/system/post_translation_spec.rb
@@ -28,6 +28,8 @@ describe "Post translations", type: :system do
context "when a post does not have translations" do
it "should only show the languages listed in the site setting" do
+ post.update!(locale: "en")
+
topic_page.visit_topic(topic)
find("#post_#{post.post_number} .post-action-menu__add-translation").click
translation_selector.expand
@@ -156,9 +158,9 @@ describe "Post translations", type: :system do
page.find("#create-topic").click
post_language_selector.expand
expect(post_language_selector).to have_content("English (US)") # default locale
- expect(post_language_selector).to have_content("Français")
- expect(post_language_selector).to have_content("Español")
- expect(post_language_selector).to have_content("Português (BR)")
+ expect(post_language_selector).to have_content("French (Français)")
+ expect(post_language_selector).to have_content("Spanish (Español)")
+ expect(post_language_selector).to have_content("Portuguese (Português (BR))")
expect(post_language_selector).to have_content(
I18n.t("js.post.localizations.post_language_selector.none"),
)