exceptions.rb 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. module I18n
  2. # Handles exceptions raised in the backend. All exceptions except for
  3. # MissingTranslationData exceptions are re-thrown. When a MissingTranslationData
  4. # was caught the handler returns an error message string containing the key/scope.
  5. # Note that the exception handler is not called when the option :throw was given.
  6. class ExceptionHandler
  7. include Module.new {
  8. def call(exception, locale, key, options)
  9. if exception.is_a?(MissingTranslation)
  10. options[:rescue_format] == :html ? exception.html_message : exception.message
  11. elsif exception.is_a?(Exception)
  12. raise exception
  13. else
  14. throw :exception, exception
  15. end
  16. end
  17. }
  18. end
  19. class ArgumentError < ::ArgumentError; end
  20. class InvalidLocale < ArgumentError
  21. attr_reader :locale
  22. def initialize(locale)
  23. @locale = locale
  24. super "#{locale.inspect} is not a valid locale"
  25. end
  26. end
  27. class InvalidLocaleData < ArgumentError
  28. attr_reader :filename
  29. def initialize(filename)
  30. @filename = filename
  31. super "can not load translations from #{filename}, expected it to return a hash, but does not"
  32. end
  33. end
  34. class MissingTranslation
  35. module Base
  36. attr_reader :locale, :key, :options
  37. def initialize(locale, key, options = nil)
  38. @key, @locale, @options = key, locale, options.dup || {}
  39. options.each { |k, v| self.options[k] = v.inspect if v.is_a?(Proc) }
  40. end
  41. def html_message
  42. key = keys.last.to_s.gsub('_', ' ').gsub(/\b('?[a-z])/) { $1.capitalize }
  43. %(<span class="translation_missing" title="translation missing: #{keys.join('.')}">#{key}</span>)
  44. end
  45. def keys
  46. @keys ||= I18n.normalize_keys(locale, key, options[:scope]).tap do |keys|
  47. keys << 'no key' if keys.size < 2
  48. end
  49. end
  50. def message
  51. "translation missing: #{keys.join('.')}"
  52. end
  53. alias :to_s :message
  54. def to_exception
  55. MissingTranslationData.new(locale, key, options)
  56. end
  57. end
  58. include Base
  59. end
  60. class MissingTranslationData < ArgumentError
  61. include MissingTranslation::Base
  62. end
  63. class InvalidPluralizationData < ArgumentError
  64. attr_reader :entry, :count
  65. def initialize(entry, count)
  66. @entry, @count = entry, count
  67. super "translation data #{entry.inspect} can not be used with :count => #{count}"
  68. end
  69. end
  70. class MissingInterpolationArgument < ArgumentError
  71. attr_reader :values, :string
  72. def initialize(values, string)
  73. @values, @string = values, string
  74. super "missing interpolation argument in #{string.inspect} (#{values.inspect} given)"
  75. end
  76. end
  77. class ReservedInterpolationKey < ArgumentError
  78. attr_reader :key, :string
  79. def initialize(key, string)
  80. @key, @string = key, string
  81. super "reserved key #{key.inspect} used in #{string.inspect}"
  82. end
  83. end
  84. class UnknownFileType < ArgumentError
  85. attr_reader :type, :filename
  86. def initialize(type, filename)
  87. @type, @filename = type, filename
  88. super "can not load translations from #{filename}, the file type #{type} is not known"
  89. end
  90. end
  91. end