Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,9 @@ gem "uri-idna"
# For converting HTML to Markdown
gem "reverse_markdown"

# For reading translations from a spreadsheet
gem "roo"

group :development, :test do
# See https://guides.rubyonrails.org/debugging_rails_applications.html#debugging-with-the-debug-gem
gem "debug", platforms: %i[mri windows], require: "debug/prelude"
Expand Down
8 changes: 8 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -653,6 +653,12 @@ GEM
reverse_markdown (3.0.2)
nokogiri
rexml (3.4.4)
roo (3.0.0)
base64 (~> 0.2)
csv (~> 3)
logger (~> 1)
nokogiri (~> 1)
rubyzip (>= 3.0.0, < 4.0.0)
rspec (3.13.2)
rspec-core (~> 3.13.0)
rspec-expectations (~> 3.13.0)
Expand Down Expand Up @@ -851,6 +857,7 @@ DEPENDENCIES
rails (~> 8.1.3)
rails-controller-testing
reverse_markdown
roo
rspec-rails (>= 3.9.0)
rubocop-govuk
selenium-webdriver
Expand Down Expand Up @@ -1091,6 +1098,7 @@ CHECKSUMS
request_store (1.7.0) sha256=e1b75d5346a315f452242a68c937ef8e48b215b9453a77a6c0acdca2934c88cb
reverse_markdown (3.0.2) sha256=818ebb92ce39dbb1a291690dd1ec9a6d62530d4725296b17e9c8f668f9a5b8af
rexml (3.4.4) sha256=19e0a2c3425dfbf2d4fc1189747bdb2f849b6c5e74180401b15734bc97b5d142
roo (3.0.0) sha256=6fdd7a9158d657c69768b4168754ff2110cc21fdc01a1bec1010820cb05c91b1
rspec (3.13.2) sha256=206284a08ad798e61f86d7ca3e376718d52c0bc944626b2349266f239f820587
rspec-core (3.13.6) sha256=a8823c6411667b60a8bca135364351dda34cd55e44ff94c4be4633b37d828b2d
rspec-expectations (3.13.5) sha256=33a4d3a1d95060aea4c94e9f237030a8f9eae5615e9bd85718fe3a09e4b58836
Expand Down
26 changes: 26 additions & 0 deletions app/controllers/forms/welsh_translation_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,28 @@ def download
disposition: "attachment; filename=#{form_content_service.filename}"
end

def show_upload
authorize current_form, :can_edit_form?
render :show_upload, locals: { current_form:, welsh_translation_upload_input: WelshTranslationUploadInput.new }
end

def upload
authorize current_form, :can_edit_form?

welsh_translation_upload_input = WelshTranslationUploadInput.new(**welsh_translation_upload_params)

data = welsh_translation_upload_input.read_file
unless data
return render :show_upload, status: :unprocessable_entity, locals: { current_form:, welsh_translation_upload_input: }
end

@welsh_translation_input = WelshTranslationInput.new(form: form_with_pages_and_conditions).assign_form_values
@welsh_translation_input.assign_from_spreadsheet(data)
@table_presenter = Forms::TranslationTablePresenter.new

render :new
end

private

def preview_html
Expand All @@ -96,5 +118,9 @@ def delete_welsh_translation_params
def form_with_pages_and_conditions
Form.includes(pages: [:routing_conditions]).find(current_form.id)
end

def welsh_translation_upload_params
params.fetch(:forms_welsh_translation_upload_input, ActionController::Parameters.new).permit(:file)
end
end
end
12 changes: 11 additions & 1 deletion app/input_objects/forms/welsh_condition_translation_input.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
class Forms::WelshConditionTranslationInput < BaseInput
include ActionView::Helpers::FormTagHelper
include ActiveModel::Attributes
include WelshTranslationContentId

attr_accessor :condition

Expand Down Expand Up @@ -39,8 +40,17 @@ def assign_condition_values
self
end

def assign_from_spreadsheet(data)
%i[exit_page_heading exit_page_markdown].each do |attr|
spreadsheet_id = condition_content_id(condition.id, attr)
send(:"#{attr}_cy=", data[spreadsheet_id]) if data.key?(spreadsheet_id)
end

self
end

def form_field_id(attribute)
field_id(:forms_welsh_condition_translation_input, condition.id, :condition_translations, attribute)
condition_content_id(condition.id, attribute)
end

def condition_has_exit_page?
Expand Down
21 changes: 20 additions & 1 deletion app/input_objects/forms/welsh_page_translation_input.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ class Forms::WelshPageTranslationInput < BaseInput
include TextInputHelper
include ActionView::Helpers::FormTagHelper
include ActiveModel::Attributes
include WelshTranslationContentId

attr_accessor :condition_translations, :selection_options_cy
attr_reader :page
Expand Down Expand Up @@ -82,6 +83,24 @@ def assign_page_values
self
end

def assign_from_spreadsheet(data)
%i[question_text hint_text page_heading guidance_markdown none_of_the_above_question].each do |attr|
spreadsheet_id = page_content_id(page.id, attr)
send(:"#{attr}_cy=", data[spreadsheet_id]) if data.key?(spreadsheet_id)
end

selection_options_cy&.each_with_index do |option, index|
spreadsheet_id = page_content_id(page.id, "option_#{index}")
option.name_cy = data[spreadsheet_id] if data.key?(spreadsheet_id)
end

condition_translations.each do |condition_translation|
condition_translation.assign_from_spreadsheet(data)
end

self
end

def condition_translations_attributes=(attributes)
submitted_condition_ids = attributes.values.map { |attrs| attrs["id"] }.compact

Expand Down Expand Up @@ -112,7 +131,7 @@ def selection_options_cy_attributes=(attributes)
end

def form_field_id(attribute)
field_id(:forms_welsh_page_translation_input, page.id, :page_translations, attribute)
page_content_id(page.id, attribute)
end

def page_has_hint_text?
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,14 @@ def assign_selection_option_values
self
end

def assign_selection_option_values_from_csv_values(csv_values)
return self unless selection_option

spreadsheet_id = page_content_id(page.id, "option_#{index}")
self.name_cy = csv_values[spreadsheet_id] if csv_values.key?(spreadsheet_id)
self
end

def as_selection_option
{ name: name_cy, value: selection_option.value }
end
Expand Down
13 changes: 13 additions & 0 deletions app/input_objects/forms/welsh_translation_input.rb
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,19 @@ def assign_form_values
self
end

def assign_from_spreadsheet(data)
WelshSpreadsheetImportService::FORM_FIELD_IDS.each do |field_id|
attr = :"#{field_id}_cy"
send(:"#{attr}=", data[field_id]) if data.key?(field_id)
end

page_translations.each do |page_translation|
page_translation.assign_from_spreadsheet(data)
end

self
end

def blanked?
all_fields_empty? && page_translations.all?(&:blanked?)
end
Expand Down
27 changes: 27 additions & 0 deletions app/input_objects/forms/welsh_translation_upload_input.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
class Forms::WelshTranslationUploadInput < BaseInput
attr_accessor :file

validates :file, presence: true
validate :validate_file_type

FILE_TYPES = %w[
text/csv
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
application/vnd.oasis.opendocument.spreadsheet
].freeze

def read_file
return false if invalid?

WelshSpreadsheetImportService.new(file).read
rescue CSV::MalformedCSVError, WelshSpreadsheetImportService::InvalidHeadersError
errors.add(:file, :invalid_csv)
false
end

def validate_file_type
if file.present? && FILE_TYPES.exclude?(file.content_type)
errors.add(:file, :disallowed_type)
end
end
end
9 changes: 9 additions & 0 deletions app/lib/welsh_translation_content_id.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
module WelshTranslationContentId
def page_content_id(page_id, attribute)
"page_#{page_id}_#{attribute}"
end

def condition_content_id(condition_id, attribute)
"condition_#{condition_id}_#{attribute}"
end
end
43 changes: 23 additions & 20 deletions app/services/welsh_csv_service.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
class WelshCsvService
include WelshTranslationContentId

MAX_FILENAME_LENGTH = 80
FILENAME_SEPARATOR = "_".freeze

Expand Down Expand Up @@ -29,11 +31,11 @@ def filename
private

def add_header(csv)
csv << ["", "English content", "Welsh content"]
csv << [WelshSpreadsheetImportService::ID_COLUMN, "Content", "English content", "Welsh content"]
end

def add_form_name(csv)
csv << ["Form name", form.name, form.name_cy]
csv << ["name", "Form name", form.name, form.name_cy]
end

def add_page_content(csv)
Expand All @@ -48,16 +50,16 @@ def add_page_content(csv)
end

def add_question_content(csv, page)
csv << ["#{question_name(page)} - question text", page.question_text, page.question_text_cy]
csv << [page_content_id(page.id, :question_text), "#{question_name(page)} - question text", page.question_text, page.question_text_cy]
if page.hint_text.present?
csv << ["#{question_name(page)} - hint text", page.hint_text, page.hint_text_cy]
csv << [page_content_id(page.id, :hint_text), "#{question_name(page)} - hint text", page.hint_text, page.hint_text_cy]
end
end

def add_selection_options(csv, page)
page.answer_settings.selection_options.each_with_index do |option, index|
welsh_option_name = page.answer_settings_cy&.selection_options&.dig(index)&.name || ""
csv << ["#{question_name(page)} - option #{index + 1}", option.name, welsh_option_name]
csv << [page_content_id(page.id, "option_#{index}"), "#{question_name(page)} - option #{index + 1}", option.name, welsh_option_name]
end
end

Expand All @@ -66,7 +68,8 @@ def add_none_of_above_question(csv, page)
welsh_question = page.answer_settings_cy&.none_of_the_above_question&.question_text || ""

csv << [
"#{question_name(page)} - question or label if ‘None of the above’ is selected",
page_content_id(page.id, :none_of_the_above_question),
"#{question_name(page)} - question or label if 'None of the above' is selected",
english_question,
welsh_question,
]
Expand All @@ -80,21 +83,21 @@ def has_none_of_the_above?(page)
def add_routing_conditions(csv, page)
page.routing_conditions.each do |condition|
if condition.is_exit_page?
csv << ["#{question_name(page)} - exit page heading", condition.exit_page_heading, condition.exit_page_heading_cy]
csv << ["#{question_name(page)} - exit page content", condition.exit_page_markdown, condition.exit_page_markdown_cy]
csv << [condition_content_id(condition.id, :exit_page_heading), "#{question_name(page)} - exit page heading", condition.exit_page_heading, condition.exit_page_heading_cy]
csv << [condition_content_id(condition.id, :exit_page_markdown), "#{question_name(page)} - exit page content", condition.exit_page_markdown, condition.exit_page_markdown_cy]
end
end
end

def add_page_heading(csv, page)
if page.page_heading.present?
csv << ["#{question_name(page)} - page heading", page.page_heading, page.page_heading_cy]
csv << [page_content_id(page.id, :page_heading), "#{question_name(page)} - page heading", page.page_heading, page.page_heading_cy]
end
end

def add_guidance_text(csv, page)
if page.guidance_markdown.present?
csv << ["#{question_name(page)} - guidance text", page.guidance_markdown, page.guidance_markdown_cy]
csv << [page_content_id(page.id, :guidance_markdown), "#{question_name(page)} - guidance text", page.guidance_markdown, page.guidance_markdown_cy]
end
end

Expand All @@ -103,24 +106,24 @@ def question_name(page)
end

def add_form_metadata(csv)
add_field_if_present(csv, "Declaration", form.declaration_text, form.declaration_text_cy)
add_field_if_present(csv, "Information about what happens next", form.what_happens_next_markdown, form.what_happens_next_markdown_cy)
add_field_if_present(csv, "GOV⁠.⁠UK Pay payment link", form.payment_url, form.payment_url_cy)
add_field_if_present(csv, "Link to privacy information for this form", form.privacy_policy_url, form.privacy_policy_url_cy)
add_field_if_present(csv, "declaration_markdown", "Declaration", form.declaration_text, form.declaration_text_cy)
add_field_if_present(csv, "what_happens_next_markdown", "Information about what happens next", form.what_happens_next_markdown, form.what_happens_next_markdown_cy)
add_field_if_present(csv, "payment_url", "GOV\u2060.\u2060UK Pay payment link", form.payment_url, form.payment_url_cy)
add_field_if_present(csv, "privacy_policy_url", "Link to privacy information for this form", form.privacy_policy_url, form.privacy_policy_url_cy)

add_support_details(csv)
end

def add_support_details(csv)
add_field_if_present(csv, "Contact details for support - email address", form.support_email, form.support_email_cy)
add_field_if_present(csv, "Contact details for support - phone number and opening times", form.support_phone, form.support_phone_cy)
add_field_if_present(csv, "Contact details for support - online contact link", form.support_url, form.support_url_cy)
add_field_if_present(csv, "Contact details for support - online contact link text", form.support_url_text, form.support_url_text_cy)
add_field_if_present(csv, "support_email", "Contact details for support - email address", form.support_email, form.support_email_cy)
add_field_if_present(csv, "support_phone", "Contact details for support - phone number and opening times", form.support_phone, form.support_phone_cy)
add_field_if_present(csv, "support_url", "Contact details for support - online contact link", form.support_url, form.support_url_cy)
add_field_if_present(csv, "support_url_text", "Contact details for support - online contact link text", form.support_url_text, form.support_url_text_cy)
end

def add_field_if_present(csv, label, english_value, welsh_value)
def add_field_if_present(csv, id, label, english_value, welsh_value)
if english_value.present?
csv << [label, english_value, welsh_value || ""]
csv << [id, label, english_value, welsh_value || ""]
end
end
end
Loading