Merge pull request #2619 from wairbut-m2c/globalize

Allow admin generated content to be translatable
This commit is contained in:
Raimond Garcia
2018-05-10 12:04:27 +02:00
committed by GitHub
20 changed files with 413 additions and 41 deletions

View File

@@ -51,6 +51,8 @@ gem 'turnout', '~> 2.4.0'
gem 'uglifier', '~> 4.1.2'
gem 'unicorn', '~> 5.4.0'
gem 'whenever', '~> 0.10.0', require: false
gem 'globalize', '~> 5.0.0'
gem 'globalize-accessors', '~> 0.2.1'
source 'https://rails-assets.org' do
gem 'rails-assets-leaflet'

View File

@@ -176,6 +176,11 @@ GEM
geocoder (1.4.4)
globalid (0.4.1)
activesupport (>= 4.2.0)
globalize (5.0.1)
activemodel (>= 4.2.0, < 4.3)
activerecord (>= 4.2.0, < 4.3)
globalize-accessors (0.2.1)
globalize (~> 5.0, >= 5.0.0)
graphiql-rails (1.4.8)
rails
graphql (1.7.8)
@@ -518,6 +523,8 @@ DEPENDENCIES
faker (~> 1.8.7)
foundation-rails (~> 6.2.4.0)
foundation_rails_helper (~> 2.0.0)
globalize (~> 5.0.0)
globalize-accessors (~> 0.2.1)
graphiql-rails (~> 1.4.1)
graphql (~> 1.7.8)
groupdate (~> 3.2.0)

View File

@@ -77,6 +77,7 @@
//= require investment_report_alert
//= require send_newsletter_alert
//= require managers
//= require globalize
var initialize_modules = function() {
App.Comments.initialize();
@@ -121,6 +122,7 @@ var initialize_modules = function() {
App.InvestmentReportAlert.initialize();
App.SendNewsletterAlert.initialize();
App.Managers.initialize();
App.Globalize.initialize();
};
$(function(){

View File

@@ -0,0 +1,46 @@
App.Globalize =
display_locale: (locale) ->
$(".js-globalize-locale-link").each ->
if $(this).data("locale") == locale
$(this).show()
App.Globalize.highlight_locale($(this))
$(".js-globalize-locale option:selected").removeAttr("selected");
return
display_translations: (locale) ->
$(".js-globalize-attribute").each ->
if $(this).data("locale") == locale
$(this).show()
else
$(this).hide()
$('.js-delete-language').hide()
$('#delete-' + locale).show()
highlight_locale: (element) ->
$('.js-globalize-locale-link').removeClass('is-active');
element.addClass('is-active');
remove_language: (locale) ->
$(".js-globalize-attribute[data-locale=" + locale + "]").val('').hide()
$(".js-globalize-locale-link[data-locale=" + locale + "]").hide()
next = $(".js-globalize-locale-link:visible").first()
App.Globalize.highlight_locale(next)
App.Globalize.display_translations(next.data("locale"))
$("#delete_translations_" + locale).val(1)
initialize: ->
$('.js-globalize-locale').on 'change', ->
App.Globalize.display_translations($(this).val())
App.Globalize.display_locale($(this).val())
$('.js-globalize-locale-link').on 'click', ->
locale = $(this).data("locale")
App.Globalize.display_translations(locale)
App.Globalize.highlight_locale($(this))
$('.js-delete-language').on 'click', ->
locale = $(this).data("locale")
$(this).hide()
App.Globalize.remove_language(locale)

View File

@@ -1,4 +1,5 @@
class Admin::BudgetInvestmentMilestonesController < Admin::BaseController
include Translatable
before_action :load_budget_investment, only: [:index, :new, :create, :edit, :update, :destroy]
before_action :load_budget_investment_milestone, only: [:edit, :update, :destroy]
@@ -46,7 +47,8 @@ class Admin::BudgetInvestmentMilestonesController < Admin::BaseController
documents_attributes = [:id, :title, :attachment, :cached_attachment, :user_id, :_destroy]
attributes = [:title, :description, :publication_date, :budget_investment_id,
image_attributes: image_attributes, documents_attributes: documents_attributes]
params.require(:budget_investment_milestone).permit(*attributes)
params.require(:budget_investment_milestone).permit(*attributes, translation_params(params[:budget_investment_milestone]))
end
def load_budget_investment
@@ -54,7 +56,19 @@ class Admin::BudgetInvestmentMilestonesController < Admin::BaseController
end
def load_budget_investment_milestone
@milestone = Budget::Investment::Milestone.find(params[:id])
@milestone = get_milestone
end
def get_milestone
Budget::Investment::Milestone.find(params[:id])
end
def resource_model
Budget::Investment::Milestone
end
def resource
get_milestone
end
end

View File

@@ -0,0 +1,29 @@
module Translatable
extend ActiveSupport::Concern
included do
before_action :set_translation_locale
before_action :delete_translations, only: [:update]
end
private
def translation_params(params)
resource_model.globalize_attribute_names.select { |k, v| params.include?(k.to_sym) && params[k].present? }
end
def set_translation_locale
Globalize.locale = I18n.locale
end
def delete_translations
locales = resource_model.globalize_locales.
select { |k, v| params[:delete_translations].include?(k.to_sym) && params[:delete_translations][k] == "1" }
locales.each do |l|
Globalize.with_locale(l) do
resource.translation.destroy
end
end
end
end

View File

@@ -0,0 +1,43 @@
module GlobalizeHelper
def options_for_locale_select
options_for_select(locale_options, nil)
end
def locale_options
I18n.available_locales.map do |locale|
[name_for_locale(locale), neutral_locale(locale)]
end
end
def display_translation?(locale)
same_locale?(neutral_locale(I18n.locale), neutral_locale(locale)) ? "" : "display: none"
end
def css_to_display_translation?(resource, locale)
resource.translated_locales.include?(neutral_locale(locale)) || locale == I18n.locale ? "" : "display: none"
end
def highlight_current?(locale)
same_locale?(I18n.locale, locale) ? 'is-active' : ''
end
def show_delete?(locale)
display_translation?(locale)
end
def neutral_locale(locale)
locale.to_s.downcase.underscore.to_sym
end
def globalize(locale, &block)
Globalize.with_locale(locale) do
yield
end
end
def same_locale?(locale1, locale2)
locale1 == locale2
end
end

View File

@@ -7,6 +7,9 @@ class Budget
max_file_size: 3.megabytes,
accepted_content_types: [ "application/pdf" ]
translates :title, :description, touch: true
globalize_accessors locales: [:en, :es, :fr, :nl, :val, :pt_br]
belongs_to :investment
validates :title, presence: true

View File

@@ -1,7 +1,22 @@
<%= render "globalize_locales" %>
<%= form_for [:admin, @investment.budget, @investment, @milestone] do |f| %>
<%= f.hidden_field :title, value: l(Time.current, format: :datetime), maxlength: Budget::Investment::Milestone.title_max_length %>
<%= f.text_area :description, rows: 5 %>
<%= f.hidden_field :title, value: l(Time.current, format: :datetime),
maxlength: Budget::Investment::Milestone.title_max_length %>
<%= f.label :description, t("admin.milestones.new.description") %>
<% @milestone.globalize_locales.each do |locale| %>
<%= hidden_field_tag "delete_translations[#{locale}]", 0 %>
<% globalize(locale) do %>
<%= f.text_area "description_#{locale}", rows: 5,
class: "js-globalize-attribute",
data: { locale: locale },
style: display_translation?(locale),
label: false %>
<% end %>
<% end %>
<%= f.label :publication_date, t("admin.milestones.new.date") %>
<%= f.text_field :publication_date,
value: @milestone.publication_date.present? ? l(@milestone.publication_date.to_date) : nil,

View File

@@ -0,0 +1,27 @@
<% I18n.available_locales.each do |locale| %>
<%= link_to t("admin.milestones.form.remove_language"), "#",
id: "delete-#{neutral_locale(locale)}",
style: show_delete?(locale),
class: 'float-right delete js-delete-language',
data: { locale: neutral_locale(locale) } %>
<% end %>
<ul class="tabs" data-tabs id="globalize_locale">
<% I18n.available_locales.each do |locale| %>
<li class="tabs-title">
<%= link_to name_for_locale(locale), "#",
style: css_to_display_translation?(@milestone, locale),
class: "js-globalize-locale-link #{highlight_current?(locale)}",
data: { locale: neutral_locale(locale) },
remote: true %>
</li>
<% end %>
</ul>
<div class="small-12 medium-6">
<%= select_tag :translation_locale,
options_for_locale_select,
prompt: t("admin.milestones.form.add_language"),
class: "js-globalize-locale" %>
</div>

View File

@@ -9,37 +9,7 @@
<section class="timeline">
<ul class="no-bullet">
<% @investment.milestones.order_by_publication_date.each do |milestone| %>
<li>
<div class="milestone-content">
<% if milestone.publication_date.present? %>
<span class="milestone-date">
<strong>
<%= t("budgets.investments.show.milestone_publication_date",
publication_date: l(milestone.publication_date.to_date)) %>
</strong>
</span>
<% end %>
<%= image_tag(milestone.image_url(:large),
{ alt: milestone.image.title.unicode_normalize,
class: "margin",
id: "image_#{milestone.id}" }) if milestone.image.present? %>
<p><%= text_with_links milestone.description %></p>
<% if milestone.documents.present? %>
<div class="document-link text-center">
<p>
<span class="icon-document"></span>&nbsp;
<strong><%= t("shared.documentation") %></strong>
</p>
<% milestone.documents.each do |document| %>
<%= link_to document.title,
document.attachment.url,
target: "_blank",
rel: "nofollow" %><br>
<% end %>
</div>
<% end %>
</div>
</li>
<%= render 'budgets/investments/milestones/milestone', milestone: milestone %>
<% end %>
</ul>
</section>

View File

@@ -0,0 +1,37 @@
<li>
<div class="milestone-content">
<% if milestone.publication_date.present? %>
<span class="milestone-date">
<strong>
<%= t("budgets.investments.show.milestone_publication_date",
publication_date: l(milestone.publication_date.to_date)) %>
</strong>
</span>
<% end %>
<%= image_tag(milestone.image_url(:large), { id: "image_#{milestone.id}", alt: milestone.image.title, class: "margin" }) if milestone.image.present? %>
<% globalize(neutral_locale(locale)) do %>
<p>
<%= text_with_links milestone.description %>
</p>
<% end %>
<% if milestone.documents.present? %>
<div class="document-link text-center">
<p>
<span class="icon-document"></span>&nbsp;
<strong><%= t("shared.documentation") %></strong>
</p>
<% milestone.documents.each do |document| %>
<%= link_to document.title,
document.attachment.url,
target: "_blank",
rel: "nofollow" %><br>
<% end %>
</div>
<% end %>
</div>
</li>

View File

@@ -254,9 +254,13 @@ en:
image: "Image"
show_image: "Show image"
documents: "Documents"
form:
add_language: Add language
remove_language: Remove language
new:
creating: Create milestone
date: Date
description: Description
edit:
title: Edit milestone
create:

View File

@@ -254,9 +254,13 @@ es:
image: "Imagen"
show_image: "Mostrar imagen"
documents: "Documentos"
form:
add_language: Añadir idioma
remove_language: Eliminar idioma
new:
creating: Crear hito
date: Fecha
description: Descripción
edit:
title: Editar hito
create:

View File

@@ -109,3 +109,17 @@ section "Creating Valuation Assignments" do
Budget::Investment.all.sample.valuators << Valuator.first
end
end
section "Creating investment milestones" do
Budget::Investment.all.each do |investment|
milestone = Budget::Investment::Milestone.new(investment_id: investment.id, publication_date: Date.tomorrow)
I18n.available_locales.map do |locale|
neutral_locale = locale.to_s.downcase.underscore.to_sym
Globalize.with_locale(neutral_locale) do
milestone.description = "Description for locale #{locale}"
milestone.title = I18n.l(Time.current, format: :datetime)
milestone.save!
end
end
end
end

View File

@@ -0,0 +1,12 @@
class AddTranslateMilestones < ActiveRecord::Migration
def self.up
Budget::Investment::Milestone.create_translation_table!({
title: :string,
description: :text
})
end
def self.down
Budget::Investment::Milestone.drop_translation_table!
end
end

View File

@@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20180320104823) do
ActiveRecord::Schema.define(version: 20180323190027) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -118,6 +118,18 @@ ActiveRecord::Schema.define(version: 20180320104823) do
add_index "budget_headings", ["group_id"], name: "index_budget_headings_on_group_id", using: :btree
create_table "budget_investment_milestone_translations", force: :cascade do |t|
t.integer "budget_investment_milestone_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 "budget_investment_milestone_translations", ["budget_investment_milestone_id"], name: "index_6770e7675fe296cf87aa0fd90492c141b5269e0b", using: :btree
add_index "budget_investment_milestone_translations", ["locale"], name: "index_budget_investment_milestone_translations_on_locale", using: :btree
create_table "budget_investment_milestones", force: :cascade do |t|
t.integer "investment_id"
t.string "title", limit: 80
@@ -162,8 +174,8 @@ ActiveRecord::Schema.define(version: 20180320104823) do
t.boolean "winner", default: false
t.boolean "incompatible", default: false
t.integer "community_id"
t.boolean "visible_to_valuators", default: false
t.integer "valuator_group_assignments_count", default: 0
t.boolean "visible_to_valuators", default: false
end
add_index "budget_investments", ["administrator_id"], name: "index_budget_investments_on_administrator_id", using: :btree

View File

@@ -39,7 +39,7 @@ feature 'Admin budget investment milestones' do
click_link 'Create new milestone'
fill_in 'budget_investment_milestone_description', with: 'New description milestone'
fill_in 'budget_investment_milestone_description_en', with: 'New description milestone'
fill_in 'budget_investment_milestone_publication_date', with: Date.current
click_button 'Create milestone'
@@ -53,7 +53,7 @@ feature 'Admin budget investment milestones' do
click_link 'Create new milestone'
fill_in 'budget_investment_milestone_description', with: 'New description milestone'
fill_in 'budget_investment_milestone_description_en', with: 'New description milestone'
click_button 'Create milestone'
@@ -77,7 +77,7 @@ feature 'Admin budget investment milestones' do
expect(page).to have_css("img[alt='#{milestone.image.title}']")
fill_in 'budget_investment_milestone_description', with: 'Changed description'
fill_in 'budget_investment_milestone_description_en', with: 'Changed description'
fill_in 'budget_investment_milestone_publication_date', with: Date.current
fill_in 'budget_investment_milestone_documents_attributes_0_title', with: 'New document title'

View File

@@ -995,7 +995,8 @@ feature 'Budget Investments' do
user = create(:user)
investment = create(:budget_investment)
create(:budget_investment_milestone, investment: investment,
description: "Last milestone with a link to https://consul.dev",
description_en: "Last milestone with a link to https://consul.dev",
description_es: "Último hito con el link https://consul.dev",
publication_date: Date.tomorrow)
first_milestone = create(:budget_investment_milestone, investment: investment,
description: "First milestone",
@@ -1017,6 +1018,15 @@ feature 'Budget Investments' do
expect(page).to have_link(document.title)
expect(page).to have_link("https://consul.dev")
end
select('Español', from: 'locale-switcher')
find("#tab-milestones-label").click
within("#tab-milestones") do
expect(page).to have_content('Último hito con el link https://consul.dev')
expect(page).to have_link("https://consul.dev")
end
end
scenario "Show no_milestones text", :js do

View File

@@ -0,0 +1,121 @@
require 'rails_helper'
feature "Translations" do
context "Milestones" do
let(:investment) { create(:budget_investment) }
let(:milestone) { create(:budget_investment_milestone,
investment: investment,
description_en: "Description in English",
description_es: "Descripción en Español") }
background do
admin = create(:administrator)
login_as(admin.user)
end
before do
@edit_milestone_url = edit_admin_budget_budget_investment_budget_investment_milestone_path(investment.budget, investment, milestone)
end
scenario "Add a translation", :js do
visit @edit_milestone_url
select "Français", from: "translation_locale"
fill_in 'budget_investment_milestone_description_fr', with: 'Description en Français'
click_button 'Update milestone'
expect(page).to have_content "Milestone updated successfully"
visit @edit_milestone_url
expect(page).to have_field('budget_investment_milestone_description_en', with: 'Description in English')
click_link "Español"
expect(page).to have_field('budget_investment_milestone_description_es', with: 'Descripción en Español')
click_link "Français"
expect(page).to have_field('budget_investment_milestone_description_fr', with: 'Description en Français')
end
scenario "Update a translation", :js do
visit @edit_milestone_url
click_link "Español"
fill_in 'budget_investment_milestone_description_es', with: 'Descripción correcta en Español'
click_button 'Update milestone'
expect(page).to have_content "Milestone updated successfully"
visit budget_investment_path(investment.budget, investment)
click_link("Milestones (1)")
expect(page).to have_content("Description in English")
select('Español', from: 'locale-switcher')
click_link("Seguimiento (1)")
expect(page).to have_content("Descripción correcta en Español")
end
scenario "Remove a translation", :js do
visit @edit_milestone_url
click_link "Español"
click_link "Remove language"
expect(page).not_to have_link "Español"
click_button "Update milestone"
visit @edit_milestone_url
expect(page).not_to have_link "Español"
end
context "Globalize javascript interface" do
scenario "Highlight current locale", :js do
visit @edit_milestone_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_milestone_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_milestone_url
expect(page).to have_field('budget_investment_milestone_description_en', with: 'Description in English')
click_link "Español"
expect(page).to have_field('budget_investment_milestone_description_es', with: 'Descripción en Español')
end
scenario "Select a locale and add it to the milestone form", :js do
visit @edit_milestone_url
select "Français", from: "translation_locale"
expect(page).to have_link "Français"
click_link "Français"
expect(page).to have_field('budget_investment_milestone_description_fr')
end
end
end
end