ruby-on-railsrails-i18nglobalize

Using the gem globalize, how to switch locales for input only and not the whole page?


Context: For a Ruby on Rails app for bike rentals, I am using the gem globalize to deal with input :description in different languages.

Curent state: The globalize implementation worked, depending on my locale I am able to store description in a specific language. The input for :description is dealt with on the basis of the locale of an entire webpage.

This means that everything on this page has to change in language in order to store :description in the correct language.

Alternatively, I am also able to show all available locales and show description for each of them. (See also the commented out code below).

Question: I'm searching for a way to let the user select a language for :description only and then save :description in the correct language without changing the language of the entire webpage.

Code

form

<div class="row">
        <%# I18n.available_locales.each do |locale| %>
          <!-- <h1><%#= locale %></h1> -->
          <%= f.globalize_fields_for locale do |ff| %>
          <div class="col-10">
            <div class="form-group">
              <label class="form-control-label text required" for="accommodation_category_description">Description</label>
              <div><%= ff.text_area :description, :rows =>"5", :cols =>"30",  class:"form-control is-valid text required" %></div>
              </div>
            </div>
          <% end %>
        <%# end %>
        </div>
      </div>

initializers/globalization.rb

module ActionView
  module Helpers
    class FormBuilder
      #
      # Helper that renders 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.

      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.translations.find_by_locale locale.to_s
        @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


Solution

  • You can use Globalize.with_locale to temporarily set locale, this works for views too:

    <% Globalize.with_locale(some_other_locale) do %>
      in this part of the page locale will be <%= locale.inspect %>
    <% end %>
    

    But for your case more user-friendly way would be to make the form dynamic, so that user can add translation for several languages of their liking.

    Globalize translations are just an additional table/model YourModel::Translation with fields for locale and translated fields, so you can work directly with these as with any other nested forms.

    Add gem cocoon to your project, that will handle dynamic forms (if you're using webpacker instead of asset pipeline - that may require additional steps, to add global jquery and require js from gem using erb interpolation, see more here).

    In your model:

    translates :description #, ...
    accepts_nested_attributes_for :translations, allow_destroy: true
    

    in controller:

    def your_some_params
      params.require(:your_model_name).permit(
            ...
            translations_attributes: [
              :id, :_destroy,
              :locale,
              :description,
            ]
          )
    end
    

    in form:

      <div id='translations'>
        <%= form.fields_for :translations do |t| %>
          <%= render 'translation_fields', f: t %>
        <% end %>
    
        <div class='links'>
          <%= link_to_add_association 'add translation', form, :translations  %>
        </div>
      </div>
    

    partial for translations like:

    <div class='nested-fields'>
      <%= f.hidden_field  :id %>
      <%= f.select :locale, I18n.available_locales %>
      <%= f.text_area :description %>
    
      <%= link_to_remove_association "remove this translation", f %>
    </div>