Сопоставление доступных языков с названиями языков

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

Для этой цели я, конечно же, перевел сайт более чем на один язык. Используя 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   |

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

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

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

# 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

person HansCz    schedule 05.10.2009    source источник


Ответы (3)


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

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

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

person Peter Wagenet    schedule 05.10.2009
comment
Спасибо, Питер. Таблица Language не отображается напрямую, поэтому я попробую Language.all(:conditions =› { :code =› I18n.available_locales }) - person HansCz; 05.10.2009
comment
Если вам нужен авторитетный список всех двухбуквенных языковых кодов, которые сопоставляются с файлами .yml перевода I18n, я думаю, что этот список довольно авторитетен: loc.gov/standards/iso639-2/php/English_list.php --- чтобы получить список названий языков на их родных языках, вы можете используйте: en.wikipedia.org/wiki/List_of_ISO_639-1_codes - person HansCz; 05.10.2009

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

в es-AR.yml

es-AR:
  locale_name: "Castellano"

в en.yml

en:
  locale_name: "English"
person dwaynemac    schedule 19.01.2010
comment
I18n.t('locale_name') или в erb просто t('locale_name') - person dwaynemac; 14.08.2012
comment
Что, если вы хотите выпадающий список со всеми локалями? - person Francesco Belladonna; 27.02.2013
comment
Я бы сделал что-то вроде: options_for_select AVAILABLE_LOCALES.map{|l| [I18n.t(l), l]} - person dwaynemac; 28.02.2013

Вот более полный ответ, основанный на решении Дуэйнмака:

  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)

person Ben Maraney    schedule 25.06.2013