Fazendo o will_paginate traduzir o "Previous" e "Next"

Eu precisei traduzir para várias línguas os links de “Previous” e “Next” do will_paginate, mas não seria nada dry passar os parâmetros em todas as chamadas a will_paginate(). Outra solução seria criar um método helper que faria a chamada ao will_paginate() passando os parâmetros e nas minhas views eu chamaria esse helper no lugar de chamar will_paginate(). O problema é que sempre que fosse criada uma nova tela com paginação a pessoa teria que lembrar de chamar o método helper e não chamar o will_paginate() diretamente.

Então pra mim a melhor solução foi criar uma extensão, que deixa tudo transparente. Eu coloquei em /lib dentro do projeto rails.

module WillPaginate
  module ViewHelpers
    def will_paginate_with_translate(collection = nil, options = {})
      options, collection = collection, nil if collection.is_a? Hash
      options.merge!(:prev_label => _("« Previous"), :next_label => _("Next »"))

      if collection
        will_paginate_without_translate(collection, options)
      else
        will_paginate_without_translate(options)
      end
    end
    alias_method_chain :will_paginate, :translate
  end
end

O método _() que é chamado é o método que faz a tradução no plugin de localização que estou utilizando, você deve alterar para a forma como você faz a localização no seu projeto. Também criei as specs para assegurar o funcionamento:

require File.dirname(__FILE__) + '/../spec_helper'

describe WillPaginate::ViewHelpers do
  describe "will_paginate translations" do
    before(:each) do
      @expected = 'paginate_mock'
      @model = mock('model-mock')

      @translation_options = {:prev_label => _("« Previous"), :next_label => _("Next »")}
      @options = {:option1 => '1', :option2 => '2', :next_label => 'next-fake'}
    end

    it "should will_paginate only with translations" do
      helper.should_receive(:will_paginate_without_translate).with(@translation_options).and_return(@expected)
      helper.will_paginate == @expected
    end

    it "should will_paginate with @model parameter" do
      helper.should_receive(:will_paginate_without_translate).with(@model, @translation_options).and_return(@expected)
      helper.will_paginate(@model) == @expected
    end

    it "should will_paginate with @model parameter and options" do
      helper.should_receive(:will_paginate_without_translate).with(@model, @options.merge(@translation_options)).and_return(@expected)
      helper.will_paginate(@model, @options) == @expected
    end
  end
end

Espero que seja útil para alguém ;)

24.11.2008 12:52 PM

4 Responses to “Fazendo o will_paginate traduzir o "Previous" e "Next"”

  1. daniel lopes Says:

    Bacana, só não entendi onde está o método will_paginate_without_translate

  2. Sylvestre Mergulhão Says:

    Bom comentário Daniel. Esse método é criado pelo alias_method_chain.

    O alias_method_chain é como um encadiador de chamadas para um método. Repare que em momento algum eu sobrescrevi o método original will_paginate, mas sim criei um método will_paginate_with_translate e depois chamei o alias_method_chain.

    O que o alias_method_chain faz é criar um alias para o método que foi passado por parâmetro + “without” + o segundo parâmetro. Nesse caso então ele cria um alias de will_paginate para will_paginate_without_translate.

    O que acontece é que ao chamar will_paginate são verificados todos os chains que foram criados e todos são executados um a um(ou seja são executados em cascata os métodos will_paginate_with*). O último executará o método original will_paginate.

    Dessa forma pode-se estender a funcionalidade de um método, sem atrapalhar o que ele já faz e sem atrapalhar qualquer chamada a ele. E pode-se fazer isso em diversas partes do sistema que uma não inibe o funcionamento da outra(a não ser que sejam conflitantes de fato, por exemplo quererem forçar a passagem de um mesmo parâmetro cada um com valor diferente).

    Grande abraço!

  3. daniel lopes Says:

    Bacana, olhando o código do método vc ve que ele faz é chamar o alias_method duas vezes:

        def alias_method_chain(target, feature)
          # Strip out punctuation on predicates or bang methods since
          # e.g. target?_without_feature is not a valid method name.
          aliased_target, punctuation = target.to_s.sub(/([?!=])$/, ''), $1
          yield(aliased_target, punctuation) if block_given?
    
          with_method, without_method = "#{aliased_target}_with_#{feature}#{punctuation}", "#{aliased_target}_without_#{feature}#{punctuation}" 
    
          alias_method without_method, target
          alias_method target, with_method
    
          case
            when public_method_defined?(without_method)
              public target
            when protected_method_defined?(without_method)
              protected target
            when private_method_defined?(without_method)
              private target
          end
        end
  4. daniel lopes Says:

    Cara, no meu caso, como estou usando o I18N no Rails 2.2 isso aqui me resolveu: http://blog.areacriacoes.com.br/2008/12/1/dica-traduzindo-will_paginate

Deixe seu comentário