How to change case of interpolated variables in Rails locale file?

假如想象 提交于 2019-12-03 06:47:56

After further research, I've concluded that this kind of operation on interpolated values is not possible, at least using a YAML locale file.

YAML is documented here and doesn't support string operations:
http://www.yaml.org/spec/1.2/spec.html

The main page on Ruby localization is here:
http://ruby-i18n.org/wiki

From there, we find the code for the default I18n gem and drill down to the interpolation code. It uses sprintf to do the interpolation:
https://github.com/svenfuchs/i18n/blob/master/lib/i18n/interpolate/ruby.rb

That code is "heavily based on Masao Mutoh's gettext String interpolation extension":
http://github.com/mutoh/gettext/blob/f6566738b981fe0952548c421042ad1e0cdfb31e/lib/gettext/core_ext/string.rb

That extension has an example of formatting numbers:

For strings.
"%{firstname}, %{familyname}" % {:firstname => "Masao", :familyname => "Mutoh"}

With field type to specify format such as d(decimal), f(float),...
"%<age>d, %<weight>.1f" % {:age => 10, :weight => 43.4}

The extension refers to the [Ruby] "Kernel::sprintf for details of the format string":
http://www.ruby-doc.org/core-1.9.2/Kernel.html#method-i-sprintf

In that doc on sprintf, there are lots of ways to format numbers, but no operations for changing the case of strings.

I have solved this problem by changing the I18n interpolation. Put the following code in your initializers directory:

module I18n
  # Implemented to support method call on translation keys
  INTERPOLATION_WITH_METHOD_PATTERN = Regexp.union(
    /%%/,
    /%\{(\w+)\}/,                               # matches placeholders like "%{foo}"
    /%<(\w+)>(.*?\d*\.?\d*[bBdiouxXeEfgGcps])/, # matches placeholders like "%<foo>.d"
    /%\{(\w+)\.(\w+)\}/,                          # matches placeholders like "%{foo.upcase}"
  )

  class << self
    def interpolate_hash(string, values)
      string.gsub(INTERPOLATION_WITH_METHOD_PATTERN) do |match|
        if match == '%%'
          '%'
        else
          key = ($1 || $2 || $4).to_sym
          value = values.key?(key) ? values[key] : raise(MissingInterpolationArgument.new(values, string))
          value = value.call(values) if value.respond_to?(:call)
          $3 ? sprintf("%#{$3}", value) : ( $5 ? value.send($5) : value) 
        end
      end
    end
  end
end

Now, this is what you can do in your locale file:

create: 'Opprett %{model.downcase}'

and test it:

require 'test_helper'

class I18nTest < ActiveSupport::TestCase

  should 'interpolate as usual' do
    assert_equal 'Show Customer', I18n.interpolate("Show %{model}", model: 'Customer')
  end

  should 'interpolate with number formatting' do
    assert_equal 'Show many 100', I18n.interpolate("Show many %<kr>2d", kr: 100)
    assert_equal 'Show many abc', I18n.interpolate("Show many %<str>3.3s", str: 'abcde')
  end

  should 'support method execution' do
    assert_equal 'Show customer', I18n.interpolate("Show %{model.downcase}", model: 'Customer')
  end

end
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!