diff --git a/app/assets/javascripts/globalize.js.coffee b/app/assets/javascripts/globalize.js.coffee index 027ac498e..09c13fd04 100644 --- a/app/assets/javascripts/globalize.js.coffee +++ b/app/assets/javascripts/globalize.js.coffee @@ -23,7 +23,10 @@ App.Globalize = element.addClass('is-active'); remove_language: (locale) -> - $(".js-globalize-attribute[data-locale=" + locale + "]").val('').hide() + $(".js-globalize-attribute[data-locale=" + locale + "]").each -> + $(this).val('').hide() + if CKEDITOR.instances[$(this).attr('id')] + CKEDITOR.instances[$(this).attr('id')].setData('') $(".js-globalize-locale-link[data-locale=" + locale + "]").hide() next = $(".js-globalize-locale-link:visible").first() App.Globalize.highlight_locale(next) diff --git a/app/controllers/admin/poll/questions/answers_controller.rb b/app/controllers/admin/poll/questions/answers_controller.rb index 3833111b9..225665b94 100644 --- a/app/controllers/admin/poll/questions/answers_controller.rb +++ b/app/controllers/admin/poll/questions/answers_controller.rb @@ -1,4 +1,6 @@ class Admin::Poll::Questions::AnswersController < Admin::Poll::BaseController + include Translatable + before_action :load_answer, only: [:show, :edit, :update, :documents] load_and_authorize_resource :question, class: "::Poll::Question" @@ -49,11 +51,15 @@ class Admin::Poll::Questions::AnswersController < Admin::Poll::BaseController def answer_params documents_attributes = [:id, :title, :attachment, :cached_attachment, :user_id, :_destroy] attributes = [:title, :description, :question_id, documents_attributes: documents_attributes] - params.require(:poll_question_answer).permit(*attributes) + params.require(:poll_question_answer).permit(*attributes, *translation_params(Poll::Question::Answer)) end def load_answer @answer = ::Poll::Question::Answer.find(params[:id] || params[:answer_id]) end + def resource + load_answer unless @answer + @answer + end end diff --git a/app/models/poll/answer.rb b/app/models/poll/answer.rb index 78122188a..851ce2fbc 100644 --- a/app/models/poll/answer.rb +++ b/app/models/poll/answer.rb @@ -9,7 +9,9 @@ class Poll::Answer < ActiveRecord::Base validates :author, presence: true validates :answer, presence: true - validates :answer, inclusion: { in: ->(a) { a.question.question_answers.pluck(:title) }}, + validates :answer, inclusion: { in: ->(a) { a.question.question_answers + .joins(:translations) + .pluck("poll_question_answer_translations.title") }}, unless: ->(a) { a.question.blank? } scope :by_author, ->(author_id) { where(author_id: author_id) } diff --git a/app/models/poll/partial_result.rb b/app/models/poll/partial_result.rb index 0550650a5..72a3372b3 100644 --- a/app/models/poll/partial_result.rb +++ b/app/models/poll/partial_result.rb @@ -10,7 +10,9 @@ class Poll::PartialResult < ActiveRecord::Base validates :question, presence: true validates :author, presence: true validates :answer, presence: true - validates :answer, inclusion: { in: ->(a) { a.question.question_answers.pluck(:title) }}, + validates :answer, inclusion: { in: ->(a) { a.question.question_answers + .joins(:translations) + .pluck("poll_question_answer_translations.title") }}, unless: ->(a) { a.question.blank? } validates :origin, inclusion: { in: VALID_ORIGINS } diff --git a/app/models/poll/question/answer.rb b/app/models/poll/question/answer.rb index 1c10e2b5c..4697fb0b5 100644 --- a/app/models/poll/question/answer.rb +++ b/app/models/poll/question/answer.rb @@ -1,6 +1,11 @@ class Poll::Question::Answer < ActiveRecord::Base include Galleryable include Documentable + + translates :title, touch: true + translates :description, touch: true + globalize_accessors locales: [:en, :es, :fr, :nl, :pt_br] + documentable max_documents_allowed: 3, max_file_size: 3.megabytes, accepted_content_types: [ "application/pdf" ] @@ -15,7 +20,7 @@ class Poll::Question::Answer < ActiveRecord::Base before_validation :set_order, on: :create def description - super.try :html_safe + self[:description].try :html_safe end def self.order_answers(ordered_array) diff --git a/app/views/admin/poll/questions/answers/_form.html.erb b/app/views/admin/poll/questions/answers/_form.html.erb index cbc450813..975f0995e 100644 --- a/app/views/admin/poll/questions/answers/_form.html.erb +++ b/app/views/admin/poll/questions/answers/_form.html.erb @@ -1,15 +1,30 @@ -<%= form_for(@answer, url: form_url) do |f| %> +<%= render "admin/shared/globalize_locales", resource: @answer %> + +<%= translatable_form_for(@answer, url: form_url) do |f| %> <%= render 'shared/errors', resource: @answer %> <%= f.hidden_field :question_id, value: @answer.question_id || @question.id %> - <%= f.text_field :title %> + <%= f.translatable_text_field :title %>
#{Faker::Lorem.paragraphs.join('
')}
" - Poll::Question::Answer.create!(question: question, - title: answer.capitalize, - description: description) + answer = Poll::Question::Answer.new(question: question, + title: title.capitalize, + description: description) + I18n.available_locales.map do |locale| + neutral_locale = locale.to_s.downcase.underscore.to_sym + Globalize.with_locale(neutral_locale) do + answer.title = "#{title} (#{locale})" + answer.description = "#{description} (#{locale})" + end + end + answer.save! end end end @@ -196,10 +204,19 @@ section "Creating Poll Questions from Proposals" do proposal = Proposal.all.sample poll = Poll.current.first question = Poll::Question.create(poll: poll) - Faker::Lorem.words((2..4).to_a.sample).each do |answer| - Poll::Question::Answer.create!(question: question, - title: answer.capitalize, - description: Faker::ChuckNorris.fact) + Faker::Lorem.words((2..4).to_a.sample).each do |title| + description = "#{Faker::ChuckNorris.fact}
" + answer = Poll::Question::Answer.new(question: question, + title: title.capitalize, + description: description) + I18n.available_locales.map do |locale| + neutral_locale = locale.to_s.downcase.underscore.to_sym + Globalize.with_locale(neutral_locale) do + answer.title = "#{title} (#{locale})" + answer.description = "#{description} (#{locale})" + end + end + answer.save! end question.copy_attributes_from_proposal(proposal) title = question.title @@ -218,10 +235,19 @@ section "Creating Successful Proposals" do proposal = Proposal.all.sample poll = Poll.current.first question = Poll::Question.create(poll: poll) - Faker::Lorem.words((2..4).to_a.sample).each do |answer| - Poll::Question::Answer.create!(question: question, - title: answer.capitalize, - description: Faker::ChuckNorris.fact) + Faker::Lorem.words((2..4).to_a.sample).each do |title| + description = "#{Faker::ChuckNorris.fact}
" + answer = Poll::Question::Answer.new(question: question, + title: title.capitalize, + description: description) + I18n.available_locales.map do |locale| + neutral_locale = locale.to_s.downcase.underscore.to_sym + Globalize.with_locale(neutral_locale) do + answer.title = "#{title} (#{locale})" + answer.description = "#{description} (#{locale})" + end + end + answer.save! end question.copy_attributes_from_proposal(proposal) title = question.title diff --git a/db/migrate/20180801114529_add_poll_question_answer_translations.rb b/db/migrate/20180801114529_add_poll_question_answer_translations.rb new file mode 100644 index 000000000..91643f443 --- /dev/null +++ b/db/migrate/20180801114529_add_poll_question_answer_translations.rb @@ -0,0 +1,14 @@ +class AddPollQuestionAnswerTranslations < ActiveRecord::Migration + + def self.up + Poll::Question::Answer.create_translation_table!( + title: :string, + description: :text + ) + end + + def self.down + Poll::Question::Answer.drop_translation_table! + end + +end diff --git a/db/schema.rb b/db/schema.rb index 88d4c73d9..d06ce8a4a 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -829,6 +829,18 @@ ActiveRecord::Schema.define(version: 20180813141443) do add_index "poll_partial_results", ["origin"], name: "index_poll_partial_results_on_origin", using: :btree add_index "poll_partial_results", ["question_id"], name: "index_poll_partial_results_on_question_id", using: :btree + create_table "poll_question_answer_translations", force: :cascade do |t| + t.integer "poll_question_answer_id", null: false + t.string "locale", null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.string "title" + t.text "description" + end + + add_index "poll_question_answer_translations", ["locale"], name: "index_poll_question_answer_translations_on_locale", using: :btree + add_index "poll_question_answer_translations", ["poll_question_answer_id"], name: "index_85270fa85f62081a3a227186b4c95fe4f7fa94b9", using: :btree + create_table "poll_question_answer_videos", force: :cascade do |t| t.string "title" t.string "url" diff --git a/spec/features/admin/poll/questions/answers/answers_spec.rb b/spec/features/admin/poll/questions/answers/answers_spec.rb index 288f514a4..dbcf8cf5c 100644 --- a/spec/features/admin/poll/questions/answers/answers_spec.rb +++ b/spec/features/admin/poll/questions/answers/answers_spec.rb @@ -15,8 +15,8 @@ feature 'Answers' do visit admin_question_path(question) click_link 'Add answer' - fill_in 'poll_question_answer_title', with: title - fill_in 'poll_question_answer_description', with: description + fill_in 'poll_question_answer_title_en', with: title + fill_in 'poll_question_answer_description_en', with: description click_button 'Save' @@ -33,8 +33,8 @@ feature 'Answers' do visit admin_question_path(question) click_link 'Add answer' - fill_in 'poll_question_answer_title', with: title - fill_in 'poll_question_answer_description', with: description + fill_in 'poll_question_answer_title_en', with: title + fill_in 'poll_question_answer_description_en', with: description click_button 'Save' @@ -53,7 +53,7 @@ feature 'Answers' do old_title = answer.title new_title = 'Ex Machina' - fill_in 'poll_question_answer_title', with: new_title + fill_in 'poll_question_answer_title_en', with: new_title click_button 'Save' diff --git a/spec/features/polls/answers_spec.rb b/spec/features/polls/answers_spec.rb index 8bb87c94e..6daffc0eb 100644 --- a/spec/features/polls/answers_spec.rb +++ b/spec/features/polls/answers_spec.rb @@ -28,8 +28,8 @@ feature 'Answers' do visit admin_question_path(question) click_link "Add answer" - fill_in "poll_question_answer_title", with: "¿Would you like to reform Central Park?" - fill_in "poll_question_answer_description", with: "Adding more trees, creating a play area..." + fill_in "poll_question_answer_title_en", with: "¿Would you like to reform Central Park?" + fill_in "poll_question_answer_description_en", with: "Adding more trees, creating a play area..." click_button "Save" expect(page).to have_content "Answer created successfully" diff --git a/spec/features/translations/poll_question_answers_spec.rb b/spec/features/translations/poll_question_answers_spec.rb new file mode 100644 index 000000000..3de1bfb38 --- /dev/null +++ b/spec/features/translations/poll_question_answers_spec.rb @@ -0,0 +1,138 @@ +# coding: utf-8 +require 'rails_helper' + +feature "Translations" do + + context "Polls" do + + let(:poll) { create(:poll, name_en: "Name in English", + name_es: "Nombre en Español", + summary_en: "Summary in English", + summary_es: "Resumen en Español", + description_en: "Description in English", + description_es: "Descripción en Español") } + + background do + admin = create(:administrator) + login_as(admin.user) + end + + context "Questions" do + + let(:question) { create(:poll_question, poll: poll, + title_en: "Question in English", + title_es: "Pregunta en Español") } + + context "Answers" do + + let(:answer) { create(:poll_question_answer, question: question, + title_en: "Answer in English", + title_es: "Respuesta en Español", + description_en: "Description in English", + description_es: "Descripción en Español") } + + before do + @edit_answer_url = edit_admin_answer_path(answer) + end + + scenario "Add a translation", :js do + visit @edit_answer_url + + select "Français", from: "translation_locale" + fill_in 'poll_question_answer_title_fr', with: 'Answer en Français' + fill_in_ckeditor 'poll_question_answer_description_fr', with: 'Description en Français' + + click_button 'Save' + expect(page).to have_content "Changes saved" + + expect(page).to have_content "Answer in English" + expect(page).to have_content "Description in English" + + select('Español', from: 'locale-switcher') + expect(page).to have_content "Respuesta en Español" + expect(page).to have_content "Descripción en Español" + + select('Français', from: 'locale-switcher') + expect(page).to have_content "Answer en Français" + expect(page).to have_content "Description en Français" + end + + scenario "Update a translation", :js do + visit @edit_answer_url + + click_link "Español" + fill_in 'poll_question_answer_title_es', with: 'Pregunta correcta en Español' + fill_in_ckeditor 'poll_question_answer_description_es', with: 'Descripción correcta en Español' + + click_button 'Save' + expect(page).to have_content "Changes saved" + + expect(page).to have_content("Answer in English") + expect(page).to have_content("Description in English") + + select('Español', from: 'locale-switcher') + expect(page).to have_content("Pregunta correcta en Español") + expect(page).to have_content("Descripción correcta en Español") + end + + scenario "Remove a translation", :js do + visit @edit_answer_url + + click_link "Español" + click_link "Remove language" + + expect(page).not_to have_link "Español" + + click_button "Save" + visit @edit_answer_url + expect(page).not_to have_link "Español" + end + + context "Globalize javascript interface" do + + scenario "Highlight current locale", :js do + visit @edit_answer_url + + expect(find("a.js-globalize-locale-link.is-active")).to have_content "English" + + select('Español', from: 'locale-switcher') + + expect(find("a.js-globalize-locale-link.is-active")).to have_content "Español" + end + + scenario "Highlight selected locale", :js do + visit @edit_answer_url + + expect(find("a.js-globalize-locale-link.is-active")).to have_content "English" + + click_link "Español" + + expect(find("a.js-globalize-locale-link.is-active")).to have_content "Español" + end + + scenario "Show selected locale form", :js do + visit @edit_answer_url + + expect(page).to have_field('poll_question_answer_title_en', with: 'Answer in English') + + click_link "Español" + + expect(page).to have_field('poll_question_answer_title_es', with: 'Respuesta en Español') + end + + scenario "Select a locale and add it to the poll form", :js do + visit @edit_answer_url + + select "Français", from: "translation_locale" + + expect(page).to have_link "Français" + + click_link "Français" + + expect(page).to have_field('poll_question_answer_title_fr') + end + end + end + end + end +end diff --git a/spec/helpers/ckeditor_spec.rb b/spec/helpers/ckeditor_spec.rb new file mode 100644 index 000000000..9ad868123 --- /dev/null +++ b/spec/helpers/ckeditor_spec.rb @@ -0,0 +1,7 @@ +def fill_in_ckeditor(id, with:) + + within_frame find("#cke_#{id} iframe") do + find('body').base.send_keys with + end + +end