Add a form to edit available locales

We're using different controls depending on the number of available
locales.

When there are only a few locales, the solution is obvious: radio
buttons to select the default language, and checkboxes to select the
available ones are simple and intuitive.

With many languages, showing two consecutive lists of 30 languages could
be confusing, though, particularly on small devices, where scrolling
through both lists could be hard.

So, in this case, we're rendering a <select> to choose the default
language. For selecting the available languages, however, we're sticking
to checkboxes because all the other existing options (like multiple
selects) are hard to use. We think it's OK because the form doesn't have
any additional fields, and there's only one big list of options to
scroll through.

While testing the application, we noticed that if we use the
`admin-fieldset-separator` styles when there's only one fieldset, it's
harder to notice that there's an additional field to select the default
language. So we're only using the `admin-fieldset-separator` styles when
all the fields are grouped in fieldsets.

Regarding the help text for the fieldset, if we leave the help text
outside the <legend> tag, people using screen readers won't hear about
this content. However, if we include it inside the <legend> tag, some
screen readers might read it every time they move to a different
checkbox (or radio button), which can be annoying. Since I don't think
these help messages are really essential, I'm leaving them out of the
<legend> tag. It's also easier to style them if they're outside the
<legend> tag.

Note we're using `display: table` for the labels, for the reasons
mentioned in commit 923c2a7ee.

Also note that, when there's only one available locale, this section is
useless. In this case, we aren't disabling it for now because there's a
chance people see it in the official Consul Democracy demo and then
wonder why it isn't available on their installation. We might disable it
in the future, though.
This commit is contained in:
Javi Martín
2024-04-09 03:18:01 +02:00
parent 999d5c2f67
commit 78bbf430d5
13 changed files with 249 additions and 1 deletions

View File

@@ -0,0 +1,26 @@
.admin .locales-form {
label {
display: table;
}
select {
width: auto;
}
> select + fieldset,
> fieldset + fieldset {
margin-top: $line-height / 2;
}
> [type="hidden"] + fieldset,
> fieldset + fieldset {
@include admin-fieldset-separator;
padding-top: calc(#{$line-height} / 4);
}
[type="submit"] {
@include regular-button;
display: block;
margin-top: $line-height;
}
}

View File

@@ -0,0 +1,40 @@
<%= form_tag admin_locales_path, method: :patch, class: "locales-form" do %>
<% if many_available_locales? %>
<%= label_tag "default_locale", t("admin.locales.default") %>
<p class="help-text"><%= sanitize(t("admin.locales.default_help_text")) %></p>
<%= select_tag "default_locale", locales_options %>
<% else %>
<fieldset>
<legend><%= t("admin.locales.default") %></legend>
<p class="help-text"><%= sanitize(t("admin.locales.default_help_text")) %></p>
<div class="collection-radio-buttons">
<% available_locales.each do |locale| %>
<%= label_tag "default_locale_#{locale}" do %>
<%= radio_button_tag "default_locale", locale, locale == default %>
<%= name_for_locale(locale) %>
<% end %>
<% end %>
</div>
</fieldset>
<% end %>
<fieldset>
<legend><%= t("admin.locales.enabled") %></legend>
<p class="help-text"><%= t("admin.locales.enabled_help_text") %></p>
<div class="collection-check-boxes">
<% available_locales.each do |locale| %>
<%= label_tag "enabled_locales_#{locale}" do %>
<%= check_box_tag "enabled_locales[]",
locale,
enabled_locales.include?(locale),
id: "enabled_locales_#{locale}" %>
<%= name_for_locale(locale) %>
<% end %>
<% end %>
</div>
</fieldset>
<%= submit_tag %>
<% end %>

View File

@@ -0,0 +1,30 @@
class Admin::Locales::FormComponent < ApplicationComponent
attr_reader :enabled_locales, :default
use_helpers :name_for_locale
def initialize(enabled_locales, default:)
@enabled_locales = enabled_locales
@default = default
end
private
def available_locales
I18n.available_locales
end
def many_available_locales?
available_locales.count > select_field_threshold
end
def locales_options
options_for_select(
available_locales.map { |locale| [name_for_locale(locale), locale] },
default
)
end
def select_field_threshold
10
end
end

View File

@@ -0,0 +1,4 @@
<%= header %>
<% provide :main_class, "admin-locales-show" %>
<%= render Admin::Locales::FormComponent.new(locales, default: default) %>

View File

@@ -0,0 +1,13 @@
class Admin::Locales::ShowComponent < ApplicationComponent
include Header
attr_reader :locales, :default
def initialize(locales, default:)
@locales = locales
@default = default
end
def title
t("admin.menu.locales")
end
end

View File

@@ -54,7 +54,7 @@ class Admin::MenuComponent < ApplicationComponent
end
def settings?
controllers_names = ["settings", "tenants", "tags", "geozones", "local_census_records", "imports"]
controllers_names = %w[settings tenants tags locales geozones local_census_records imports]
controllers_names.include?(controller_name)
end
@@ -462,6 +462,7 @@ class Admin::MenuComponent < ApplicationComponent
settings_link,
tenants_link,
tags_link,
locales_link,
geozones_link,
local_census_records_link
)
@@ -494,6 +495,14 @@ class Admin::MenuComponent < ApplicationComponent
]
end
def locales_link
[
t("admin.menu.locales"),
admin_locales_path,
controller_name == "locales"
]
end
def geozones_link
[
t("admin.menu.geozones"),

View File

@@ -0,0 +1,15 @@
class Admin::LocalesController < Admin::BaseController
def show
@enabled_locales = Setting.enabled_locales
@default_locale = Setting.default_locale
end
def update
Setting.transaction do
Setting["locales.default"] = params["default_locale"]
Setting["locales.enabled"] = [params["default_locale"], *params["enabled_locales"]].join(" ")
end
redirect_to admin_locales_path, notice: t("admin.locales.update.notice")
end
end

View File

@@ -0,0 +1 @@
<%= render Admin::Locales::ShowComponent.new(@enabled_locales, default: @default_locale) %>

View File

@@ -710,6 +710,13 @@ en:
milestones:
index:
title: Following
locales:
default: Default language
default_help_text: "This is the default language of the application, and changing it will <strong>affect every user</strong> visiting the website for the first time."
enabled: Enabled languages
enabled_help_text: The default language, selected above, will be included automatically.
update:
notice: Languages updated successfully
managers:
index:
title: Managers
@@ -732,6 +739,7 @@ en:
proposals_topics: Proposals topics
budgets: Participatory budgets
geozones: Geozones
locales: Languages
hidden_comments: Hidden comments
hidden_debates: Hidden debates
hidden_proposals: Hidden proposals

View File

@@ -710,6 +710,13 @@ es:
milestones:
index:
title: Seguimiento
locales:
default: Idioma por defecto
default_help_text: "Cambiar el idioma por defecto <strong>afectará a todos los usuarios</strong> que visiten la página por primera vez."
enabled: Idiomas habilitados
enabled_help_text: El idioma por defecto, seleccionado con anterioridad, se habilitará automáticamente.
update:
notice: Idiomas actualizados con éxito
managers:
index:
title: Gestores
@@ -732,6 +739,7 @@ es:
proposals_topics: Temas de propuestas
budgets: Presupuestos participativos
geozones: Zonas
locales: Idiomas
hidden_comments: Comentarios ocultos
hidden_debates: Debates ocultos
hidden_proposals: Propuestas ocultas

View File

@@ -242,6 +242,7 @@ namespace :admin do
end
resources :geozones, only: [:index, :new, :create, :edit, :update, :destroy]
resource :locales, only: [:show, :update]
namespace :site_customization do
resources :pages, except: [:show] do

View File

@@ -0,0 +1,39 @@
require "rails_helper"
describe Admin::Locales::FormComponent do
let(:default_locale) { :nl }
let(:enabled_locales) { %i[en nl] }
let(:component) do
Admin::Locales::FormComponent.new(enabled_locales, default: default_locale)
end
describe "default language selector" do
before { allow(I18n).to receive(:available_locales).and_return(%i[de en es nl]) }
it "renders radio buttons when there are only a few locales" do
render_inline component
page.find(:fieldset, "Default language") do |fieldset|
expect(fieldset).to have_checked_field "Nederlands", type: :radio
expect(fieldset).to have_unchecked_field "English", type: :radio
expect(fieldset).to have_unchecked_field "Español", type: :radio
expect(fieldset).to have_unchecked_field "Deutsch", type: :radio
end
expect(page).not_to have_select
end
it "renders a select when there are many locales" do
allow(component).to receive(:select_field_threshold).and_return(3)
render_inline component
expect(page).not_to have_field type: :radio
expect(page).to have_select "Default language",
options: %w[English Español Deutsch Nederlands],
selected: "Nederlands"
end
end
end

View File

@@ -0,0 +1,54 @@
require "rails_helper"
describe "Locales management", :admin do
scenario "Navigate to languages page and update them" do
allow(I18n).to receive(:available_locales).and_return(%i[de en es fr])
Setting["locales.default"] = "en"
Setting["locales.enabled"] = "en de"
visit admin_root_path
within ".locale" do
expect(page).to have_css "[aria-current]", exact_text: "English"
expect(page).to have_link "English"
expect(page).to have_link "Deutsch"
expect(page).not_to have_link "Français"
expect(page).not_to have_link "Español"
end
within "#admin_menu" do
expect(page).not_to have_link "Languages"
click_button "Settings"
click_link "Languages"
expect(page).to have_css "[aria-current]", exact_text: "Languages"
expect(page).to have_link "Languages"
end
within_fieldset "Default language" do
expect(page).to have_checked_field "English"
choose "Español"
end
within_fieldset "Enabled languages" do
uncheck "English"
check "Français"
end
click_button "Save changes"
expect(page).to have_content "Languages updated successfully"
within ".locale" do
expect(page).to have_css "[aria-current]", exact_text: "Español"
expect(page).to have_link "Français"
expect(page).to have_link "Español"
expect(page).to have_link "Deutsch"
expect(page).not_to have_link "English"
end
end
end