Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Make error messages translatable #87

Closed
wants to merge 6 commits into from
@knapo

Error messages were hardococed. They should be defined in yml files and be translatable.

@matthutchinson

+1 on this request

lib/active_merchant/common/validateable.rb
@@ -42,35 +43,45 @@ module ActiveMerchant #:nodoc:
# if more than one error is available we will only return the first. If no error is available
# we return an empty string
def on(field)
- self[field].to_a.first
+ type = [self[field]].flatten.first
+
+ return nil unless type
+
+ if type.is_a?(String)
+ key, default = nil, type
+ else
+ key, default = :"activemerchant.errors.models.#{@i18n_key}.attributes.#{field}.#{type}", :"activemerchant.errors.messages.#{type}"
@dasch
dasch added a note

That's a pretty long line - perhaps split it in two?

@knapo
knapo added a note

Absolutely agree! Done.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@ntalbott
Collaborator

Curious what the Shopify gang's take on this is - is this a good approach for ActiveMerchant? Don't want to ask @knapo for an updated PR if we're not interested in merging something like this.

At this point I'm ambivalent, though I could see this being handy for us at Spreedly eventually.

@ntalbott ntalbott referenced this pull request
Closed

Support for i18n #254

@ZenCocoon

That would be really useful to us at BookingSync as well. Looking forward to hear from Shopify guys ( @jduff @odorcicd ... ) on that.

@michaek

I think this is a good idea and a good implementation, but it seems like it can't be merged at this point and another PR will be needed.

@ZenCocoon

@michaek I'm curious to know why this can't be merged. What would break ? The additional I18n dependency makes you trouble ?

@michaek

Maybe I'm wrong - I tried to run the patch against the current code and it couldn't find the chunks.

@ZenCocoon

Hmm I see, I guess this patch might need some updates. It's is pretty old but I guess updating it is not the current issue, the main question remaining is whether this update have it's place into activemerchant.

@michaek

Yes, that is the question. I mean that I'm in favor of the change, but it will probably need a new pull request.

@ntalbott
Collaborator

I would review and merge a fresh patch that tracked with how Rails does i18n, but it probably makes sense to wait to do that until we break backwards compatibility with < 3.0.

@ntalbott ntalbott closed this
@cawel

ntalbott: any idea when active_merchant will support i18n so that we can have translatable error messages?

@troex

This was really good implementation!

I18n can be useful for English users too (I'm not speaking about the rest of the world!). Recently needed to make field names more friendly like Your credit card number is invalid, hacked based on this idea:

module ActiveMerchant
  module Validateable
    class Errors < HashWithIndifferentAccess
      def full_messages
        result = []

        self.each do |key, messages|
          next if messages.blank?
          if key == 'base'
            result << "#{messages.first}"
          else
            # result << "#{key.to_s.humanize} #{messages.first}"
            object = @base.class.to_s.demodulize.underscore
            result << "%s %s" % [I18n.t("activemerchant.#{object}.#{key}", :default => key.to_s.humanize), messages.first]
          end
        end

        result
      end
    end
  end
end
@sunny

+1 !

@skateinmars

:+1: any news on this?

@Paveltarno

+1 !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Feb 24, 2011
  1. @knapo

    Make error messages translatable.

    knapo authored
    Not really DRY for now (need use ActiveModel to keep it DRY).
Commits on Feb 25, 2011
  1. @knapo
  2. @knapo
  3. @knapo

    Fixed type in translations

    knapo authored
Commits on Mar 31, 2011
  1. @knapo
Commits on Jul 12, 2011
  1. @knapo
This page is out of date. Refresh to see the latest.
View
1  .gitignore
@@ -3,3 +3,4 @@
*.swp
*.swo
pkg
+.rvmrc
View
3  lib/active_merchant.rb
@@ -49,3 +49,6 @@ module Billing #:nodoc:
autoload :Integrations, 'active_merchant/billing/integrations'
end
end
+
+require 'active_support/i18n'
+I18n.load_path << File.dirname(__FILE__) + '/active_merchant/locale/en.yml'
View
8 lib/active_merchant/billing/check.rb
@@ -29,15 +29,15 @@ def name=(value)
def validate
[:name, :routing_number, :account_number].each do |attr|
- errors.add(attr, "cannot be empty") if self.send(attr).blank?
+ errors.add(attr, :empty) if self.send(attr).blank?
end
- errors.add(:routing_number, "is invalid") unless valid_routing_number?
+ errors.add(:routing_number, :invalid) unless valid_routing_number?
- errors.add(:account_holder_type, "must be personal or business") if
+ errors.add(:account_holder_type, :must_be_personal_or_business) if
!account_holder_type.blank? && !%w[business personal].include?(account_holder_type.to_s)
- errors.add(:account_type, "must be checking or savings") if
+ errors.add(:account_type, :must_be_checking_or_savings) if
!account_type.blank? && !%w[checking savings].include?(account_type.to_s)
end
View
28 lib/active_merchant/billing/credit_card.rb
@@ -122,38 +122,38 @@ def before_validate #:nodoc:
end
def validate_card_number #:nodoc:
- errors.add :number, "is not a valid credit card number" unless CreditCard.valid_number?(number)
- unless errors.on(:number) || errors.on(:type)
- errors.add :type, "is not the correct card type" unless CreditCard.matching_type?(number, type)
+ errors.add :number, :invalid unless CreditCard.valid_number?(number)
+ unless errors[:number] || errors[:type]
+ errors.add :type, :incorrect unless CreditCard.matching_type?(number, type)
end
end
def validate_card_type #:nodoc:
- errors.add :type, "is required" if type.blank?
- errors.add :type, "is invalid" unless CreditCard.card_companies.keys.include?(type)
+ errors.add :type, :required if type.blank?
+ errors.add :type, :invalid unless CreditCard.card_companies.keys.include?(type)
end
def validate_essential_attributes #:nodoc:
- errors.add :first_name, "cannot be empty" if @first_name.blank?
- errors.add :last_name, "cannot be empty" if @last_name.blank?
- errors.add :month, "is not a valid month" unless valid_month?(@month)
- errors.add :year, "expired" if expired?
- errors.add :year, "is not a valid year" unless valid_expiry_year?(@year)
+ errors.add :first_name, :empty if @first_name.blank?
+ errors.add :last_name, :empty if @last_name.blank?
+ errors.add :month, :invalid unless valid_month?(@month)
+ errors.add :year, :expired if expired?
+ errors.add :year, :invalid unless valid_expiry_year?(@year)
end
def validate_switch_or_solo_attributes #:nodoc:
if %w[switch solo].include?(type)
unless valid_month?(@start_month) && valid_start_year?(@start_year) || valid_issue_number?(@issue_number)
- errors.add :start_month, "is invalid" unless valid_month?(@start_month)
- errors.add :start_year, "is invalid" unless valid_start_year?(@start_year)
- errors.add :issue_number, "cannot be empty" unless valid_issue_number?(@issue_number)
+ errors.add :start_month, :invalid unless valid_month?(@start_month)
+ errors.add :start_year, :invalid unless valid_start_year?(@start_year)
+ errors.add :issue_number, :empty unless valid_issue_number?(@issue_number)
end
end
end
def validate_verification_value #:nodoc:
if CreditCard.requires_verification_value?
- errors.add :verification_value, "is required" unless verification_value?
+ errors.add :verification_value, :required unless verification_value?
end
end
end
View
37 lib/active_merchant/common/validateable.rb
@@ -32,6 +32,7 @@ class Errors < HashWithIndifferentAccess
def initialize(base)
@base = base
+ @i18n_key = @base.class.to_s.demodulize.underscore
end
def count
@@ -42,35 +43,47 @@ def count
# if more than one error is available we will only return the first. If no error is available
# we return an empty string
def on(field)
- self[field].to_a.first
+ type = [self[field]].flatten.first
+
+ return nil unless type
+
+ if type.is_a?(String)
+ key = nil
+ default = type
+ else
+ key = :"activemerchant.errors.models.#{@i18n_key}.attributes.#{field}.#{type}"
+ default = :"activemerchant.errors.messages.#{type}"
+ end
+
+ I18n.t(key, :default => default)
end
def add(field, error)
self[field] ||= []
self[field] << error
- end
+ end
def add_to_base(error)
add(:base, error)
end
def each_full
- full_messages.each { |msg| yield msg }
+ full_messages.each { |msg| yield msg }
end
def full_messages
result = []
-
- self.each do |key, messages|
- if key == 'base'
- result << "#{messages.first}"
+
+ self.each do |key, v|
+ if key.to_sym == :base
+ result << "#{self.on(key)}"
else
- result << "#{key.to_s.humanize} #{messages.first}"
+ result << "#{I18n.t("activemerchant.attributes.#{@i18n_key}.#{key}", :default => key.to_s.humanize)} #{self.on(key)}"
end
end
-
+
result
- end
- end
+ end
+ end
end
-end
+end
View
39 lib/active_merchant/locale/en.yml
@@ -0,0 +1,39 @@
+en:
+ activemerchant:
+ attributes:
+ check:
+ name: "Name"
+ routing_number: "Routing number"
+ account_number: "Account number"
+ account_holder_type: "Account holder type"
+ account_type: "Account type"
+ credit_card:
+ issue_number: "Issue number"
+ number: "Card number"
+ type: "Card type"
+ first_name: "First name"
+ last_name: "Last name"
+ month: "Expire month"
+ year: "Expire year"
+ start_month: "Start month"
+ start_year: "Start year"
+ verification_value: "Verification value"
+ errors:
+ messages:
+ empty: "can't be empty"
+ expired: "is expired"
+ invalid: "is invalid"
+ required: "is required"
+ must_be_personal_or_business: "must be personal or business"
+ must_be_checking_or_savings: "must be checking or savings"
+ models:
+ credit_card:
+ attributes:
+ number:
+ invalid: "is not a valid credit card number"
+ type:
+ incorrect: "is not the correct card type"
+ month:
+ invalid: "is not a valid month"
+ year:
+ invalid: "is not a valid year"
View
4 test/test_helper.rb
@@ -18,8 +18,8 @@
begin
gem 'actionpack'
-rescue LoadError
- raise StandardError, "The view tests need ActionPack installed as gem to run"
+rescue LoadError => e
+ raise e, "The view tests need ActionPack installed as gem to run"
end
require 'action_controller'
View
12 test/unit/validateable_test.rb
@@ -6,9 +6,9 @@ class Dood
attr_accessor :name, :email, :country
def validate
- errors.add "name", "cannot be empty" if name.blank?
- errors.add "email", "cannot be empty" if email.blank?
- errors.add_to_base "The country cannot be blank" if country.blank?
+ errors.add "name", :empty if name.blank?
+ errors.add "email", :empty if email.blank?
+ errors.add_to_base "The country can't be blank" if country.blank?
end
end
@@ -46,15 +46,15 @@ def test_multiple_calls
def test_messages
@dood.valid?
- assert_equal "cannot be empty", @dood.errors.on('name')
- assert_equal "cannot be empty", @dood.errors.on('email')
+ assert_equal "can't be empty", @dood.errors.on('name')
+ assert_equal "can't be empty", @dood.errors.on('email')
assert_equal nil, @dood.errors.on('doesnt_exist')
end
def test_full_messages
@dood.valid?
- assert_equal ["Email cannot be empty", "Name cannot be empty", "The country cannot be blank"], @dood.errors.full_messages.sort
+ assert_equal ["Email can't be empty", "Name can't be empty", "The country can't be blank"], @dood.errors.full_messages.sort
end
end
Something went wrong with that request. Please try again.