Сопоставление доступных языков с названиями языков - PullRequest
3 голосов
/ 05 октября 2009

Я хочу сделать раскрывающийся список выбора языка на странице редактирования / создания пользователем сайта.

Для этого я, конечно, перевел сайт на несколько языков. Используя I18n.available_languages, я могу получить массив кодов локали, например,

development environment (Rails 2.3.4)
> I18n.available_locales
   => [:en, :da]

Кроме того, я создал модель языка и связал ее с пользователем:

# app/models/language.rb
class Language < ActiveRecord::Base
  has_many :users  
end

# app/models/user.rb
class User < ActiveRecord::Base
  belongs_to :language  
end

# db/schema.rb
create_table "languages", :force => true do |t|
  t.string "name"
  t.string "code"
end

create_table "users", :force => true do |t|
  t.integer  "language_id"
end

Таблица языков содержит код языка и название языка на родном языке, например:

| id  | name                | code |
------------------------------------
| 28  | Dansk               | da   |
| 29  | Nederlands          | nl   |
| 30  | English             | en   |
| 31  | Esperanto           | eo   |

У меня затем есть следующее назначение в действиях пользователя new, создания и редактирования:

# app/controllers/users_controller.rb (extract)
@available_languages = I18n.available_locales.collect {|language_code| Language.find_by_code(language_code.to_s)}

, который я использую в представлении следующим образом («available_languages» - локальная переменная, поскольку @available_languages ​​из контроллера было передано в частичное):

# app/views/users/_form.haml (extract)
= f.collection_select(:language_id, available_languages, :id, :name, {:prompt => true})

Результатом всего этого является то, что пользователь получит раскрывающийся список выбора локали, чтобы определить локаль для данного пользователя.

Мой вопрос: Есть ли чистый способ переместить назначение @available_languages ​​из UsersController и в языковую модель, чтобы я мог сократить это:

@available_languages = I18n.available_locales.collect {|language_code| Language.find_by_code(language_code.to_s)}

примерно так:

@available_languages = Language.translations_available

Ответы [ 3 ]

13 голосов
/ 20 января 2010

Я добавляю ключ "locale_name" к каждому yml с его именем на своем родном языке. Например:

в es-AR.yml

es-AR:
  locale_name: "Castellano"

в en.yml

en:
  locale_name: "English"
12 голосов
/ 25 июня 2013

Вот более полный ответ, основанный на решении Dwaynemac:

  1. Добавьте ключ с именем локали в каждый файл yml. Например в en.yml:

    en:
      language: English
    

    и в es.yml:

    es:
      language: Español
    
  2. Добавьте вспомогательный метод (например, в /app/helpers/application_helper.rb), который создает массив пар имен локали и локали:

      def locale_name_pairs
        I18n.available_locales.map do |locale|
          [I18n.t('language', locale: locale), locale.to_s]
        end
      end
    
  3. В вашей форме используйте locale_name_pairs, чтобы создать выпадающий список:

    f.select :locale, options_for_select(locale_name_pairs, @user.locale)
    

Примечание для ленивых: Если вы предпочитаете пропустить шаг 2, тогда вы можете использовать следующую однострочную строку в шаге 3: f.select :locale, options_for_select(I18n.available_locales.map{ |locale| [I18n.t('language', locale: locale), locale.to_s] } , @user.locale)

4 голосов
/ 05 октября 2009

Мне кажется, что вы делаете пару забавных вещей. Во-первых, есть некоторые проблемы со следующим:

I18n.available_locales.collect {|language_code| Language.find_by_code(language_code.to_s)}

Эта настройка заставляет вас генерировать один SQL-запрос для каждой доступной локали. Кроме того, если каждая локаль в I18n.available_locales имеет соответствующий объект Language и наоборот, этот код кажется немного ненужным. Вы могли бы просто сделать:

Language.find(:all) # or even Language.all

Если по какой-то причине они не отображаются напрямую, вы можете использовать это вместо:

Language.all(:conditions => { :code => I18n.available_locales })

который в более подробной форме эквивалентен:

Language.find(:all, :conditions => ["code IN (?)", I18n.available_locales])

Здесь будут найдены все языки, код которых указан в I18n.available_locales. Если вам нужен ярлык для этого метода, вы можете использовать named_scopes:

class Language < ActiveRecord::Base
  has_many :users

  named_scope :translation_available, :conditions => { :code => I18n.available_locales }
end

С этим вы можете позвонить:

Language.translation_available

Я думаю, это то, что вы хотели.

...