From 8b0b1c6745063f06e501c1ce242115c6bcf57268 Mon Sep 17 00:00:00 2001 From: sto Date: Thu, 27 Mar 2025 12:55:12 +0100 Subject: [PATCH] Add language settings for users, and translate titles to French --- app/controllers/application_controller.rb | 6 ++- app/controllers/users_controller.rb | 2 +- app/lib/languages.rb | 3 ++ app/models/user.rb | 2 + app/views/users/_form.html.slim | 11 ++++++ config/application.rb | 4 ++ config/locales/fr.yml | 37 +++++++++++++++++++ db/migrate/20250327111835_add_lang_to_user.rb | 5 +++ db/schema.rb | 3 +- spec/factories/contests.rb | 22 +++++++++++ spec/factories/users.rb | 17 +++++++++ spec/models/user_spec.rb | 17 +++++++++ test/fixtures/users.yml | 1 + test/models/user_test.rb | 1 + 14 files changed, 128 insertions(+), 3 deletions(-) create mode 100644 app/lib/languages.rb create mode 100644 config/locales/fr.yml create mode 100644 db/migrate/20250327111835_add_lang_to_user.rb diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index dadab43..9fd693f 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -2,7 +2,7 @@ class ApplicationController < ActionController::Base include Authentication include Pundit::Authorization - before_action :set_title, :set_current_user + before_action :set_title, :set_current_user, :set_lang after_action :verify_authorized # Only allow modern browsers supporting webp images, web push, badges, import maps, CSS nesting, and CSS :has. @@ -23,6 +23,10 @@ class ApplicationController < ActionController::Base @current_user = current_user end + def set_lang + I18n.locale = @current_user.lang if @current_user + end + def user_not_authorized(exception) policy_name = exception.policy.class.to_s.underscore diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 0615600..bbdec6d 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -55,6 +55,6 @@ class UsersController < ApplicationController end def user_params - params.expect(user: [ :username, :email_address, :password ]) + params.expect(user: [ :username, :email_address, :lang, :password ]) end end diff --git a/app/lib/languages.rb b/app/lib/languages.rb new file mode 100644 index 0000000..daddfa1 --- /dev/null +++ b/app/lib/languages.rb @@ -0,0 +1,3 @@ +module Languages + AVAILABLE_LANGUAGES = [ { id: "en", name: "English" }, { id: "fr", name: "French" } ] +end diff --git a/app/models/user.rb b/app/models/user.rb index 0148425..a1aa86f 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -5,6 +5,7 @@ # id :integer not null, primary key # admin :boolean default(FALSE), not null # email_address :string not null +# lang :string default("en") # password_digest :string not null # username :string # created_at :datetime not null @@ -22,4 +23,5 @@ class User < ApplicationRecord normalizes :email_address, with: ->(e) { e.strip.downcase } validates :username, presence: true, uniqueness: true + validates :lang, inclusion: { in: Languages::AVAILABLE_LANGUAGES.map { |lang| lang[:id] } } end diff --git a/app/views/users/_form.html.slim b/app/views/users/_form.html.slim index 5da6344..f4487fa 100644 --- a/app/views/users/_form.html.slim +++ b/app/views/users/_form.html.slim @@ -1,6 +1,7 @@ = form_with model: user, method: method do |form| - if method == :patch h4 General settings + .row.mb-3 .col .input-group @@ -8,11 +9,20 @@ .form-floating = form.text_field :username, autocomplete: "off", class: "form-control" = form.label :username, class: "required" + .row.mb-3 .col .form-floating = form.text_field :email_address, autocomplete: "off", class: "form-control" = form.label :email_address, class: "required" + + .row.mb-3 + .col + .form-floating + = form.select :lang, Languages::AVAILABLE_LANGUAGES.map { |lang| [ lang[:name], lang[:id] ] }, {}, class: "form-select" + = form.label :lang + | Language + - if method == :post .row.mb-3 .col @@ -23,6 +33,7 @@ - if method == :patch h4.mt-5 Change password + = form_with model: user, method: method do |form| .row.mb-3 .col diff --git a/config/application.rb b/config/application.rb index a69828d..3d54895 100644 --- a/config/application.rb +++ b/config/application.rb @@ -14,6 +14,7 @@ module PuzzleScoreboard # Please, add to the `ignore` list any other `lib` subdirectories that do # not contain `.rb` files, or that should not be reloaded or eager loaded. # Common ones are `templates`, `generators`, or `middleware`, for example. + config.autoload_paths << Rails.root.join("lib") config.autoload_lib(ignore: %w[assets tasks]) # Configuration for the application, engines, and railties goes here. @@ -23,5 +24,8 @@ module PuzzleScoreboard # # config.time_zone = "Central Time (US & Canada)" # config.eager_load_paths << Rails.root.join("extras") + + config.i18n.default_locale = :en + config.i18n.available_locales = [ :en, :fr ] end end diff --git a/config/locales/fr.yml b/config/locales/fr.yml new file mode 100644 index 0000000..d552ce2 --- /dev/null +++ b/config/locales/fr.yml @@ -0,0 +1,37 @@ +fr: + completions: + edit: + title: "Modifier la complétion" + new: + title: "Nouvelle complétion" + contests: + edit: + title: "Paramètres du concours" + index: + title: "Bienvenue %{username}!" + new: + title: "Nouveau concours" + scoreboard: + title: "%{name}" + show: + title: "%{name}" + contestants: + edit: + title: "Participant" + new: + title: "Nouveau.elle participant.e" + puzzles: + edit: + title: "Modifier le puzzle" + new: + title: "Nouveau puzzle" + sessions: + new: + title: "Se connecter à l'app Public Scoreboard" + users: + edit: + title: "Mes paramètres" + index: + title: "Tous.tes les utilisateur.ices" + new: + title: "Nouveau.elle utilisateur.ice" diff --git a/db/migrate/20250327111835_add_lang_to_user.rb b/db/migrate/20250327111835_add_lang_to_user.rb new file mode 100644 index 0000000..1ccf6dd --- /dev/null +++ b/db/migrate/20250327111835_add_lang_to_user.rb @@ -0,0 +1,5 @@ +class AddLangToUser < ActiveRecord::Migration[8.0] + def change + add_column :users, :lang, :string, default: 'en' + end +end diff --git a/db/schema.rb b/db/schema.rb index d823306..b9ef96b 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[8.0].define(version: 2025_03_26_162920) do +ActiveRecord::Schema[8.0].define(version: 2025_03_27_111835) do create_table "active_storage_attachments", force: :cascade do |t| t.string "name", null: false t.string "record_type", null: false @@ -111,6 +111,7 @@ ActiveRecord::Schema[8.0].define(version: 2025_03_26_162920) do t.datetime "updated_at", null: false t.string "username" t.boolean "admin", default: false, null: false + t.string "lang", default: "en" t.index ["email_address"], name: "index_users_on_email_address", unique: true end diff --git a/spec/factories/contests.rb b/spec/factories/contests.rb index 6070d05..9017752 100644 --- a/spec/factories/contests.rb +++ b/spec/factories/contests.rb @@ -1,3 +1,25 @@ +# == Schema Information +# +# Table name: contests +# +# id :integer not null, primary key +# allow_registration :boolean default(FALSE) +# name :string +# slug :string +# team :boolean default(FALSE) +# created_at :datetime not null +# updated_at :datetime not null +# user_id :integer not null +# +# Indexes +# +# index_contests_on_slug (slug) UNIQUE +# index_contests_on_user_id (user_id) +# +# Foreign Keys +# +# user_id (user_id => users.id) +# FactoryBot.define do factory :contest do name { Faker::Company.unique.name } diff --git a/spec/factories/users.rb b/spec/factories/users.rb index fc36e24..7f0cd8c 100644 --- a/spec/factories/users.rb +++ b/spec/factories/users.rb @@ -1,3 +1,20 @@ +# == Schema Information +# +# Table name: users +# +# id :integer not null, primary key +# admin :boolean default(FALSE), not null +# email_address :string not null +# lang :string default("en") +# password_digest :string not null +# username :string +# created_at :datetime not null +# updated_at :datetime not null +# +# Indexes +# +# index_users_on_email_address (email_address) UNIQUE +# FactoryBot.define do factory :user do username { Faker::Internet.unique.username } diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index cdcf2c6..6da689a 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -1,3 +1,20 @@ +# == Schema Information +# +# Table name: users +# +# id :integer not null, primary key +# admin :boolean default(FALSE), not null +# email_address :string not null +# lang :string default("en") +# password_digest :string not null +# username :string +# created_at :datetime not null +# updated_at :datetime not null +# +# Indexes +# +# index_users_on_email_address (email_address) UNIQUE +# require 'rails_helper' RSpec.describe User, type: :model do diff --git a/test/fixtures/users.yml b/test/fixtures/users.yml index 882ab7d..369b2d7 100644 --- a/test/fixtures/users.yml +++ b/test/fixtures/users.yml @@ -8,6 +8,7 @@ # id :integer not null, primary key # admin :boolean default(FALSE), not null # email_address :string not null +# lang :string default("en") # password_digest :string not null # username :string # created_at :datetime not null diff --git a/test/models/user_test.rb b/test/models/user_test.rb index b468c81..aaa8d5c 100644 --- a/test/models/user_test.rb +++ b/test/models/user_test.rb @@ -5,6 +5,7 @@ # id :integer not null, primary key # admin :boolean default(FALSE), not null # email_address :string not null +# lang :string default("en") # password_digest :string not null # username :string # created_at :datetime not null