Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Using Rails 3.1.3 with Ruby 1.9.3p0.

I've discovered that by default, Rails does not use sentence case for form buttons. For example, instead of an "Update user" button, it generates an "Update User" button.

The button names come from the ActionView locale file. Is there a way to create a default that downcases the model name? This is not covered in the Ruby on Rails Guides i18n section on Interpolation so maybe it is not possible. The following doesn't work:

en:
  helpers:
    submit:
      update: 'Update %{model}.downcase'

In general, I'd be glad to find a reference for the syntax of the locale YAML files. The i18n guide covers some of the syntax, but it would be helpful to find documentation on all the exclamation points, various date/time formats, etc. Or maybe I should be using a Ruby Hash instead of a YAML file for this purpose?

like image 622
Mark Berry Avatar asked Mar 10 '12 00:03

Mark Berry


2 Answers

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.

like image 75
Mark Berry Avatar answered Jan 03 '23 13:01

Mark Berry


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
like image 28
Knut Stenmark Avatar answered Jan 03 '23 11:01

Knut Stenmark