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); + } + + +} 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"), )