ruby-on-railsinternationalizationdecoratorlazy-evaluationpresenter

Rails Internationalization – Lazy Lookup with a Presenter class


4.1.4 of the Rails Guide explains "Lazy" Lookup for the Internationalization gem.

As an example:

en.yml

en:
  clients:
    show:
      good_client: 5 Star Client

app/views clients/show.html.erb

<%= t '.good_client' %>

renders 5 Star Client (inferring the clients.show bit from the view). If I now want to move my view logic into a Presenter or Decorator Class, I can change the view to

<%= ClientPresenter.new.good_client %>

and add app/presenters/client_presenter.rb

class ClientPresenter
  def good_client
    I18n.t('clients.show.good_client')
  end
end

I have gained the benefit of a Presenter class but at the expense of a more verbose argument to the translate method. (clients.show won’t be inferred outside of the view/controller). I could change en.yml to

en:
  good client: 5 Star Client

and the presenter’s method to

  def good_client
    I18n.t('good_client')
  end

but then I lose the organizational structure in the yml file...

Can I extract the view logic to a Presenter class and keep the translate argument succinct and keep the yml file nicely organized?


Solution

  • You have to pass view instance into your presenter:

    class ClientPresenter
      def initialize(view)
        @view = view
      end
    
      delegate :t, to: :@view
    
      def good_client
        t ".good_client"
      end
    end
    
    <%= ClientPresenter.new(self).good_client %>
    

    You could also pass t method itself, but this is probably overthinking it:

    class ClientPresenter
      def initialize(t:)
        @translate = t
      end
    
      def good_client
        t ".good_client"
      end
    
      private
    
      def t(...)
        @translate.call(...)
      end
    end
    
    <%= ClientPresenter.new(t: method(:t)).good_client %>