Translating Rails Timezones

前端 未结 9 648
滥情空心
滥情空心 2021-02-05 11:09

We internationalized our site months ago, but forgot one part: The drop down where a user picks their timezone.

How do you translate the following line:



        
相关标签:
9条回答
  • 2021-02-05 11:51

    I've come across the same problem. However, when I was trying to implement Peter's solution, a simpler solution occurred to me. The time_zone_select helper takes a :model option, which defaults to ActiveSupport::TimeZone. According to the API documentation, all this model has to do is return an array of timezone objects in the all method. We can then override the to_s method to return the translation (defaulting to the original if the translation isn't found). Here is the class:

    # lib/i18n_time_zone.rb
    class I18nTimeZone < ActiveSupport::TimeZone
      def self.all
        super.map { |z| create(z.name, z.utc_offset) }
      end
    
      def to_s
        translated_name = I18n.t(name, :scope => :timezones, :default => name)
        "(GMT#{formatted_offset}) #{translated_name}"
      end
    end
    

    And in the view:

    <%= time_zone_select :user, :time_zone, nil, :model => I18nTimeZone %>
    

    With the translations specified in the translation file as before:

    # es.yml
    es:
      timezones:
        "International Date Line West":    "Línea de fecha internacional del oeste"
        "Pacific Time (US & Canada)":      "Tiempo pacífico (& de los E.E.U.U.; Canadá)"
        # and so on
    
    0 讨论(0)
  • 2021-02-05 11:53

    I would imagine that this would need to be done manually in the same way that any other I18n translations are done in Rails. This would mean setting up locale files with the translations. Something like:

    # es.yml
    es:
      timezones:
        "International Date Line West":    "Línea de fecha internacional del oeste"
        "Pacific Time (US & Canada)":      "Tiempo pacífico (& de los E.E.U.U.; Canadá)"
        # and so on
    

    You could overwrite the time_zone_options_for_select method (which is used by time_zone_select) with the following:

    def time_zone_options_for_select(selected = nil, priority_zones = nil, model = ::ActiveSupport::TimeZone)
      zone_options = ""
    
      zones = model.all
      convert_zones = lambda do |list|
        list.map do |z|
          localized_name = I18n.t(z.name, :scope => :timezones, :default => z.name)
          [ "(GMT#{z.formatted_offset}) #{localized_name}", z.name ]
        end
      end
    
      if priority_zones
        if priority_zones.is_a?(Regexp)
          priority_zones = model.all.find_all {|z| z =~ priority_zones}
        end
        zone_options += options_for_select(convert_zones[priority_zones], selected)
        zone_options += "<option value=\"\" disabled=\"disabled\">-------------</option>\n"
    
        zones = zones.reject { |z| priority_zones.include?( z ) }
      end
    
      zone_options += options_for_select(convert_zones[zones], selected)
      zone_options
    end
    

    The changes are:

    convert_zones = lambda do |list|
      list.map do |z|
        localized_name = I18n.t(z.name, :scope => :timezones, :default => z.name)
        [ "(GMT#{z.formatted_offset}) #{localized_name}", z.name ]
      end
    end
    

    What we're doing is, getting the localized name from the TimeZone name with I18n.t which is looking in config/locales/LANG.yml formatted as shown above. If we can't find the translation, we just fallback on using the TimeZone name.

    Now that we've done this setup, we should be able to use :

    f.time_zone_select :timezone, ActiveSupport::TimeZone.all
    

    or the shorter

    f.time_zone_select :timezone # defaults to ActiveSupport::TimeZone.all      
    
    0 讨论(0)
  • 2021-02-05 11:53

    I had trouble translating the time zones with .'s in them, like "St. Petersburg"

    "translation missing: en, time_zones, St, Petersburg"

    I removed the .'s from the keys, and changed this:

    translated_name = I18n.t(name, :scope => :time_zones, :default => name)

    to:

    translated_name = I18n.t(name.gsub(".", ""), :scope => :time_zones, :default => name)

    There are four keys with .'s:

    • Cape Verde Is.
    • St. Petersburg
    • Solomon Is.
    • Marshall Is.
    0 讨论(0)
提交回复
热议问题