Skip to content

Commit

Permalink
Globalize product model
Browse files Browse the repository at this point in the history
  * Add globalize3 dependency
  * Include UI to translate product fields
  • Loading branch information
huoxito authored and schof committed May 19, 2013
1 parent 5bf0ba0 commit 3f71fd4
Show file tree
Hide file tree
Showing 25 changed files with 380 additions and 9 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ pkg
*.sw?
spec/dummy
.rvmrc
.sass-cache
5 changes: 5 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
source 'http://rubygems.org'

group :assets do
gem 'coffee-rails'
end

group :test do
gem 'i18n-spec'
gem 'factory_girl_rails', '~> 4.2.1'
Expand All @@ -8,5 +12,6 @@ group :test do
end

gem 'spree', github: 'spree/spree'
gem 'globalize3'

gemspec
21 changes: 21 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,27 @@ To install, simply add the Gem to your Gemfile:

2. Run `bundle install`

## Spree Products Translations

We've introduced a product translations feature. Follow the steps to get it working.

Point to the content branch:

gem 'spree_i18n', :git => 'git://github.com/spree/spree_i18n.git', :branch => 'content'

Install and run the migration to create the product translations table:

bundle exec rake railties:install:migrations
bundle exec rake db:migrate

Add the following line to admin/all.js on your app:

//= require admin/spree_i18n

Go to admin products list and click on any product. You should see a TRANSLATIONS link
in the products subtabs on the right. You should be able to set name, description,
meta descriptions, and meta keywords for any product on your Spree project.

## Running the tests

If you would like to run the tests of this project, follow these steps:
Expand Down
38 changes: 38 additions & 0 deletions app/assets/javascripts/admin/product_translations.js.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
display_locale_fields = () ->
attr = $('#attr_list li.active a').data('attr')
locales = $('select#locale').val()
show = $("input[name='show-only']:checked").val()

$('table#attr_fields tr').hide()

for locale in locales
do (locale) ->
value = $('table#attr_fields tr.' + attr + '.' + locale + ' td.translation :input').val().replace /^\s+|\s+$/g, ""

if show == 'incomplete'
display = value == ''
else if show == 'complete'
display = value != ''
else
display = true

if display
$('table#attr_fields tr.' + attr + '.' + locale).show()

if $('table#attr_fields tr:visible').length == 0 and show != 'all'
$('table#attr_fields tfoot tr').show()
$('table#attr_fields tfoot td').html('No <strong>' + show + '</strong> translations for <strong>' + attr + '</strong>.')


$ ->
$('#attr_list a').click ->
$('#attr_list li').removeClass('active')
$(this).parent().addClass('active')

display_locale_fields()
false

$('select#locale').select2({placeholder: 'Please select a language.'})
$('select#locale').change display_locale_fields
$("input[name='show-only']").change display_locale_fields

1 change: 1 addition & 0 deletions app/assets/javascripts/admin/spree_i18n.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
//= require_tree .
9 changes: 9 additions & 0 deletions app/assets/javascripts/store/locale.js.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
$ ->
$('#locale-select select').change ->
$.ajax(
type: 'POST'
url: $(this).data('href')
data:
locale: $(this).val()
).done ->
window.location.reload()
1 change: 1 addition & 0 deletions app/assets/javascripts/store/spree_i18n.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
//= require_tree .
Empty file.
Empty file.
18 changes: 18 additions & 0 deletions app/controllers/spree/admin/translations_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
module Spree
class Admin::TranslationsController < Admin::BaseController
before_filter :load_parent

helper_method :collection_url
helper 'spree/locale'

private

def load_parent
@product ||= Spree::Product.find_by_permalink(params[:product_id])
end

def collection_url
admin_product_url(load_parent)
end
end
end
12 changes: 12 additions & 0 deletions app/controllers/spree/locale_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
module Spree
class LocaleController < Spree::StoreController
def set
session[:locale] = params[:locale]

respond_to do |format|
format.json { render :json => true }
format.html { redirect_to root_path }
end
end
end
end
16 changes: 16 additions & 0 deletions app/helpers/spree/locale_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
module Spree
module LocaleHelper

def options_for_locale_select()
Spree::Config.supported_locales.map do |locale|
[I18n.t(:this_file_language, :locale => locale), locale]
end
end

def admin_options_for_locale_select()
Spree::Config.all_locales.map do |locale|
[I18n.t(:this_file_language, :locale => locale), locale]
end
end
end
end
4 changes: 4 additions & 0 deletions app/models/spree/app_configuration_decorator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Spree::AppConfiguration.class_eval do
preference :all_locales, :array, :default => ['en', 'es', 'de', 'pt-BR']
preference :supported_locales, :array, :default => ['en', 'es', 'de', 'pt-BR']
end
9 changes: 9 additions & 0 deletions app/models/spree/product_decorator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
module Spree
Product.class_eval do
translates :name, :description, :meta_description, :meta_keywords

attr_accessible :translations_attributes

accepts_nested_attributes_for :translations
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!-- insert_bottom '#main-nav-bar' -->
<% if Spree::Config.supported_locales.size > 1 %>
<li id="locale-select" style="float: right; margin-right: 10px;" data-hook>
<%= form_tag(set_locale_path(:format => :html)) do %>
<label for="locale"><%= t(:language) %>:</label>
<%= select_tag(:locale, options_for_select(options_for_locale_select, I18n.locale),
:data => { :href => set_locale_path(:format => :json) }) %>
<noscript>
<%= submit_tag %>
</noscript>
<% end %>
</li>
<% end %>
96 changes: 96 additions & 0 deletions app/views/spree/admin/translations/index.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
<%= render :partial => 'spree/admin/shared/product_sub_menu' %>
<%= render :partial => 'spree/admin/shared/product_tabs', :locals => { :current => 'Translations' } %>
<%= render :partial => 'spree/shared/error_messages', :locals => { :target => @product } %>
<% content_for :page_actions do %>
<li>
<%= link_to_add_fields t(:add_product_translations), 'tbody#product_properties', :class => 'icon-plus button' %>
</li>
<% end %>

<div class="row">
<fieldset class="no-border-top">
<fieldset class="no-border-bottom">
<legend>Settings</legend>

<div class="alpha six columns field">
<label for="show-only">Show only: </label>
<ul>
<li><input type="radio" name="show-only" value="all" checked> <label>All Translations</label></li>
<li><input type="radio" name="show-only" value="incomplete"> <label>Only Incomplete</label></li>
<li><input type="radio" name="show-only"value="complete"> <label>Only Complete</label></li>
</ul>
</div>

<div class="omega six columns">
<label for="locale">Select locale: </label>
<%= select_tag(:locale, options_for_select(admin_options_for_locale_select, Spree::Config.all_locales), :class => 'fullwidth' , :multiple => 'true') %>
</div>
</fieldset>

<fieldset class="alpha four columns no-border-bottom">
<legend>Product fields</legend>
<nav class="menu">
<ul id="attr_list">
<% @product.class.translates.each_with_index do |attr,i| %>
<li class="<%= 'active' if i == 0 %>">
<a data-attr="<%= attr %>" href="#"><%= attr %></a>
</li>
<% end %>
</ul>
</nav>
</fieldset>

<%= form_for [:admin, @product], :method => :put, :html => { :multipart => true } do |f| %>
<fieldset class="omega eight columns no-border-bottom">
<legend>Translations</legend>
<table id="attr_fields" class="no-borders">
<colgroup>
<col style="width: 10%" />
<col style="width: 90%" />
</colgroup>
<tbody>
<% Spree::Config.all_locales.each do |locale| %>
<%= f.globalize_fields_for locale.to_sym do |g| %>
<% @product.class.translates.each_with_index do |attr,i| %>
<tr style="display:<%= i == 0 ? 'auto' : 'none' %>;" class="<%= attr %> <%= locale %> even">
<td style="padding:4px;" colspan="2">
<%= t(:this_file_language, :locale => locale) %> -
<%= t(attr, :locale => locale ) %>
</td>
</tr>
<tr style="display:<%= i == 0 ? 'auto' : 'none' %>;" class="<%= attr %> <%= locale %> odd">
<td class="flag table-column">
<% if locale.include?('-') %>
<img src="http://www.localeapp.com/assets/flags/regions/<%= locale.split('-').last %>.png">
<% else %>
<img src="http://www.localeapp.com/assets/flags/languages/<%= locale %>.png">
<% end %>
</td>
<td class="translation table-column">
<% if @product.class.columns_hash[attr.to_s].type == :text %>
<%= g.text_area attr, :class => "fullwidth", :rows => 4 %>
<% else %>
<%= g.text_field attr, :class => "fullwidth" %>
<% end %>
</td>
</tr>
<% end %>
<% end %>
<% end %>
</tbody>
<tfoot>
<tr style="display:none;">
<td colspan="2"></td>
</tr>
</tfoot>
</table>

</fieldset>
<%= render :partial => 'spree/admin/shared/edit_resource_links' %>
<% end %>
</fieldset>
</div>
53 changes: 53 additions & 0 deletions config/initializers/form_builder_globalize_patch.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
module ActionView
module Helpers
class FormBuilder
#
# Helper that renders globalize_translations fields
# on a per-locale basis, so you can use them separately
# in the same form and still saving them all at once
# in the same request.
#
# Use it like this:
#
# <h1>Editing post</h1>
#
# <% form_for(@post) do |f| %>
# <%= f.error_messages %>
#
# <h2>English (default locale)</h2>
# <p><%= f.text_field :title %></p>
# <p><%= f.text_field :teaser %></p>
# <p><%= f.text_field :body %></p>
#
# <hr/>
#
# <h2>Spanish translation</h2>
# <% f.globalize_fields_for :es do |g| %>
# <p><%= g.text_field :title %></p>
# <p><%= g.text_field :teaser %></p>
# <p><%= g.text_field :body %></p>
# <% end %>
#
# <hr/>
#
# <h2>French translation</h2>
# <% f.globalize_fields_for :fr do |g| %>
# <p><%= g.text_field :title %></p>
# <p><%= g.text_field :teaser %></p>
# <p><%= g.text_field :body %></p>
# <% end %>
#
# <% end %>
#
def globalize_fields_for(locale, *args, &proc)
raise ArgumentError, "Missing block" unless block_given?
@index = @index ? @index + 1 : 1
object_name = "#{@object_name}[translations_attributes][#{@index}]"
object = @object.translation_for(locale)
@template.concat @template.hidden_field_tag("#{object_name}[id]", object ? object.id : "")
@template.concat @template.hidden_field_tag("#{object_name}[locale]", locale)
@template.fields_for(object_name, object, *args, &proc)
end
end
end
end
5 changes: 5 additions & 0 deletions config/locales/en.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Sample localization file for English. Add more files in this directory for other locales.
# See https://github.com/svenfuchs/rails-i18n/tree/master/rails%2Flocale for starting points.

en:
this_file_language: "English (US)"
2 changes: 2 additions & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
Spree::Core::Engine.routes.prepend do
match '/locale/set', :to => 'locale#set', :defaults => { :format => :json }, :as => :set_locale

namespace :admin do
resources :products do
resources :translations
Expand Down
13 changes: 13 additions & 0 deletions db/migrate/20130415164940_add_translations_to_products.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
class AddTranslationsToProducts < ActiveRecord::Migration
def up
params = { :name => :string,
:description => :text,
:meta_description => :string,
:meta_keywords => :string }
Spree::Product.create_translation_table!(params, { :migrate_data => true })
end

def down
Spree::Product.drop_translation_table! :migrate_data => true
end
end
3 changes: 2 additions & 1 deletion lib/spree_i18n/engine.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
require 'globalize3'

module SpreeI18n
class Engine < Rails::Engine
engine_name 'spree_i18n'
Expand All @@ -22,7 +24,6 @@ def self.activate
config.to_prepare &method(:activate).to_proc

protected

def self.add(pattern)
files = Dir[File.join(File.dirname(__FILE__), '../..', pattern)]
I18n.load_path.concat(files)
Expand Down
Loading

0 comments on commit 3f71fd4

Please sign in to comment.