diff --git a/Gemfile b/Gemfile index d80a159dd..6fe8fa380 100644 --- a/Gemfile +++ b/Gemfile @@ -65,6 +65,7 @@ gem "auto_strip_attributes" gem "sidekiq" gem "sidekiq-cron" gem "unread" +gem "i18n-active_record", require: "i18n/active_record" group :development, :test do # Check gems for known vulnerabilities diff --git a/Gemfile.lock b/Gemfile.lock index 47895d4f1..1419edd6b 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -191,6 +191,8 @@ GEM activesupport (>= 6.1.4.4) i18n (1.14.1) concurrent-ruby (~> 1.0) + i18n-active_record (1.3.0) + i18n (>= 0.5.0) iniparse (1.5.0) jmespath (1.6.2) jsbundling-rails (1.3.0) @@ -468,6 +470,7 @@ DEPENDENCIES govuk-components (~> 5.1) govuk_design_system_formbuilder (~> 5.0) govuk_markdown + i18n-active_record jsbundling-rails json-schema listen (~> 3.3) diff --git a/app/controllers/translations_controller.rb b/app/controllers/translations_controller.rb new file mode 100644 index 000000000..12147341a --- /dev/null +++ b/app/controllers/translations_controller.rb @@ -0,0 +1,23 @@ +class TranslationsController < ApplicationController + def index + @translation_overrides = Translation.all + + committed_translations = YAML.load_file("config/locales/forms/questions/2024/en.yml") + @default_translations = flatten(committed_translations["en"]).to_a + render "translations/index" + end +end + +private + +def flatten(translation_hash) + translation_hash.each_with_object({}) do |(k, v), h| + if v.is_a? Hash + flatten(v).map do |h_k, h_v| + h["#{k}.#{h_k}".to_sym] = h_v + end + else + h[k] = v + end + end +end diff --git a/app/helpers/translations_helper.rb b/app/helpers/translations_helper.rb new file mode 100644 index 000000000..ed0bd96cb --- /dev/null +++ b/app/helpers/translations_helper.rb @@ -0,0 +1,2 @@ +module TranslationsHelper +end diff --git a/app/models/form/lettings/questions/gender_identity1.rb b/app/models/form/lettings/questions/gender_identity1.rb index 8d48d736f..0f8477c7b 100644 --- a/app/models/form/lettings/questions/gender_identity1.rb +++ b/app/models/form/lettings/questions/gender_identity1.rb @@ -2,7 +2,7 @@ class Form::Lettings::Questions::GenderIdentity1 < ::Form::Question def initialize(id, hsh, page) super @id = "sex1" - @check_answer_label = I18n.t("forms.questions.#{form.start_date.year}.sex1.check_answer_label") + @check_answer_label = I18n.t("forms.questions.#{form.start_date.year}.sex1.check_answer_label", default: "forms.questions.sex1.check_answer_label".to_sym) @header = I18n.t("forms.questions.#{form.start_date.year}.sex1.header") @type = "radio" @check_answers_card_number = 1 diff --git a/app/views/translations/index.html.erb b/app/views/translations/index.html.erb new file mode 100644 index 000000000..7d6986ffd --- /dev/null +++ b/app/views/translations/index.html.erb @@ -0,0 +1,24 @@ +<%= govuk_table do |table| %> + <% @translation_overrides.each do |translation| %> + <%= table.with_body do |body| %> + <%= body.with_row do |row| %> + <%= row.with_cell(text: translation.key) %> + <%= row.with_cell(text: translation.value) %> + <% end %> + <% end %> + <% end %> +<% end %> + +<%= govuk_section_break(visible: true, size: "m") %> + +<%= govuk_table do |table| %> + <% @default_translations.each do |translation| %> + <%= table.with_body do |body| %> + <%= body.with_row do |row| %> + <%= row.with_cell(text: translation[0]) %> + <%= row.with_cell(text: translation[1]) %> + <% end %> + <% end %> + <% end %> +<% end %> + diff --git a/config/initializers/i18n_active_record.rb b/config/initializers/i18n_active_record.rb new file mode 100644 index 000000000..d59197dc5 --- /dev/null +++ b/config/initializers/i18n_active_record.rb @@ -0,0 +1,16 @@ +unless Rails.env.production? + + require "i18n/backend/active_record" + + Translation = I18n::Backend::ActiveRecord::Translation + + if Translation.table_exists? + I18n.backend = I18n::Backend::Chain.new(I18n::Backend::ActiveRecord.new, I18n.backend) + end + + I18n::Backend::ActiveRecord.configure do |config| + # config.cache_translations = true # defaults to false + # config.cleanup_with_destroy = true # defaults to false + end + +end diff --git a/config/locales/forms/questions/2024/en.yml b/config/locales/forms/questions/2024/en.yml index 338143d69..e777cbb33 100644 --- a/config/locales/forms/questions/2024/en.yml +++ b/config/locales/forms/questions/2024/en.yml @@ -1,14 +1,15 @@ en: forms: questions: + sex1: + check_answer_label: "Default" 2024: sex1: header: "Which of these best describes the lead tenant’s gender identity?" - check_answer_label: "Lead tenant’s gender identity" hint_text: "This should be however they personally choose to identify from the options below. This may or may not be the same as their biological sex or the sex they were assigned at birth." question_number: 32 options: - F: "Female" + F: "Female 2024" M: "Male" X: "Non-binary" R: "Tenant prefers not to say" diff --git a/config/routes.rb b/config/routes.rb index b6b362569..9efbc2cdf 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,5 +1,6 @@ # For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html Rails.application.routes.draw do + get 'translations', to: "translations#index" mount_sidekiq = -> { mount Sidekiq::Web => "/sidekiq" } authenticate(:user, :support?.to_proc, &mount_sidekiq) diff --git a/db/migrate/20240423095327_create_translations.rb b/db/migrate/20240423095327_create_translations.rb new file mode 100644 index 000000000..b72da7d39 --- /dev/null +++ b/db/migrate/20240423095327_create_translations.rb @@ -0,0 +1,13 @@ +class CreateTranslations < ActiveRecord::Migration[7.0] + def change + create_table :translations do |t| + t.string :locale + t.string :key + t.text :value + t.text :interpolations + t.boolean :is_proc, default: false + + t.timestamps + end + end +end diff --git a/db/schema.rb b/db/schema.rb index bb13372cd..a190fd597 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[7.0].define(version: 2024_03_19_122706) do +ActiveRecord::Schema[7.0].define(version: 2024_04_23_095327) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -193,14 +193,14 @@ ActiveRecord::Schema[7.0].define(version: 2024_03_19_122706) do t.integer "hb" t.integer "hbrentshortfall" t.integer "property_relet" - t.datetime "mrcdate", precision: nil + t.datetime "mrcdate" t.integer "incref" - t.datetime "startdate", precision: nil + t.datetime "startdate" t.integer "armedforces" t.integer "first_time_property_let_as_social_housing" t.integer "unitletas" t.integer "builtype" - t.datetime "voiddate", precision: nil + t.datetime "voiddate" t.bigint "owning_organisation_id" t.bigint "managing_organisation_id" t.integer "renttype" @@ -304,9 +304,9 @@ ActiveRecord::Schema[7.0].define(version: 2024_03_19_122706) do t.integer "scharge_value_check" t.integer "pscharge_value_check" t.integer "duplicate_set_id" - t.integer "accessible_register" t.integer "nationality_all" t.integer "nationality_all_group" + t.integer "accessible_register" t.integer "reasonother_value_check" t.string "address_line1_input" t.string "postcode_full_input" @@ -727,6 +727,16 @@ ActiveRecord::Schema[7.0].define(version: 2024_03_19_122706) do t.index ["owning_organisation_id"], name: "index_schemes_on_owning_organisation_id" end + create_table "translations", force: :cascade do |t| + t.string "locale" + t.string "key" + t.text "value" + t.text "interpolations" + t.boolean "is_proc", default: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + create_table "users", force: :cascade do |t| t.string "email", default: "", null: false t.string "encrypted_password", default: "", null: false @@ -738,8 +748,8 @@ ActiveRecord::Schema[7.0].define(version: 2024_03_19_122706) do t.string "name" t.bigint "organisation_id" t.integer "sign_in_count", default: 0, null: false - t.datetime "current_sign_in_at", precision: nil - t.datetime "last_sign_in_at", precision: nil + t.datetime "current_sign_in_at" + t.datetime "last_sign_in_at" t.string "current_sign_in_ip" t.string "last_sign_in_ip" t.integer "role" @@ -763,8 +773,8 @@ ActiveRecord::Schema[7.0].define(version: 2024_03_19_122706) do t.datetime "confirmation_sent_at" t.string "unconfirmed_email" t.boolean "initial_confirmation_sent" - t.datetime "discarded_at" t.boolean "reactivate_with_organisation" + t.datetime "discarded_at" t.index ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true t.index ["email"], name: "index_users_on_email", unique: true t.index ["encrypted_otp_secret_key"], name: "index_users_on_encrypted_otp_secret_key", unique: true diff --git a/spec/requests/translations_spec.rb b/spec/requests/translations_spec.rb new file mode 100644 index 000000000..edab522a5 --- /dev/null +++ b/spec/requests/translations_spec.rb @@ -0,0 +1,11 @@ +require 'rails_helper' + +RSpec.describe "Translations", type: :request do + describe "GET /index" do + it "returns http success" do + get "/translations/index" + expect(response).to have_http_status(:success) + end + end + +end diff --git a/test.yml b/test.yml new file mode 100644 index 000000000..62946dc42 --- /dev/null +++ b/test.yml @@ -0,0 +1,9 @@ +--- +forms: + questions: + '2024': + sex1: + options: + F: I'm in the database + M: newly created as db item +"forms\x01questions\x012024\x01sex1\x01options\x01M": newly stored