File: exceptions.rb

package info (click to toggle)
ruby-i18n 1.14.7-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 768 kB
  • sloc: ruby: 6,548; makefile: 5
file content (157 lines) | stat: -rw-r--r-- 4,788 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
# frozen_string_literal: true

require 'cgi'

module I18n
  class ExceptionHandler
    def call(exception, _locale, _key, _options)
      if exception.is_a?(MissingTranslation)
        exception.message
      else
        raise exception
      end
    end
  end

  class ArgumentError < ::ArgumentError; end

  class Disabled < ArgumentError
    def initialize(method)
      super(<<~MESSAGE)
        I18n.#{method} is currently disabled, likely because your application is still in its loading phase.

        This method is meant to display text in the user locale, so calling it before the user locale has
        been set is likely to display text from the wrong locale to some users.

        If you have a legitimate reason to access i18n data outside of the user flow, you can do so by passing
        the desired locale explicitly with the `locale` argument, e.g. `I18n.#{method}(..., locale: :en)`
      MESSAGE
    end
  end

  class InvalidLocale < ArgumentError
    attr_reader :locale
    def initialize(locale)
      @locale = locale
      super "#{locale.inspect} is not a valid locale"
    end
  end

  class InvalidLocaleData < ArgumentError
    attr_reader :filename
    def initialize(filename, exception_message)
      @filename, @exception_message = filename, exception_message
      super "can not load translations from #{filename}: #{exception_message}"
    end
  end

  class MissingTranslation < ArgumentError
    module Base
      PERMITTED_KEYS = [:scope, :default].freeze

      attr_reader :locale, :key, :options

      def initialize(locale, key, options = EMPTY_HASH)
        @key, @locale, @options = key, locale, options.slice(*PERMITTED_KEYS)
        options.each { |k, v| self.options[k] = v.inspect if v.is_a?(Proc) }
      end

      def keys
        @keys ||= I18n.normalize_keys(locale, key, options[:scope]).tap do |keys|
          keys << 'no key' if keys.size < 2
        end
      end

      def message
        if (default = options[:default]).is_a?(Array) && default.any?
          other_options = ([key, *default]).map { |k| normalized_option(k).prepend('- ') }.join("\n")
          "Translation missing. Options considered were:\n#{other_options}"
        else
          "Translation missing: #{keys.join('.')}"
        end
      end

      def normalized_option(key)
        I18n.normalize_keys(locale, key, options[:scope]).join('.')
      end

      alias :to_s :message

      def to_exception
        MissingTranslationData.new(locale, key, options)
      end
    end

    include Base
  end

  class MissingTranslationData < ArgumentError
    include MissingTranslation::Base
  end

  class InvalidPluralizationData < ArgumentError
    attr_reader :entry, :count, :key
    def initialize(entry, count, key)
      @entry, @count, @key = entry, count, key
      super "translation data #{entry.inspect} can not be used with :count => #{count}. key '#{key}' is missing."
    end
  end

  class MissingInterpolationArgument < ArgumentError
    attr_reader :key, :values, :string
    def initialize(key, values, string)
      @key, @values, @string = key, values, string
      super "missing interpolation argument #{key.inspect} in #{string.inspect} (#{values.inspect} given)"
    end
  end

  class ReservedInterpolationKey < ArgumentError
    attr_reader :key, :string
    def initialize(key, string)
      @key, @string = key, string
      super "reserved key #{key.inspect} used in #{string.inspect}"
    end
  end

  class UnknownFileType < ArgumentError
    attr_reader :type, :filename
    def initialize(type, filename)
      @type, @filename = type, filename
      super "can not load translations from #{filename}, the file type #{type} is not known"
    end
  end

  class UnsupportedMethod < ArgumentError
    attr_reader :method, :backend_klass, :msg
    def initialize(method, backend_klass, msg)
      @method = method
      @backend_klass = backend_klass
      @msg = msg
      super "#{backend_klass} does not support the ##{method} method. #{msg}"
    end
  end

  class InvalidFilenames < ArgumentError
    NUMBER_OF_ERRORS_SHOWN = 20
    def initialize(file_errors)
      super <<~MSG
        Found #{file_errors.count} error(s).
        The first #{[file_errors.count, NUMBER_OF_ERRORS_SHOWN].min} error(s):
        #{file_errors.map(&:message).first(NUMBER_OF_ERRORS_SHOWN).join("\n")}

        To use the LazyLoadable backend:
        1. Filenames must start with the locale.
        2. An underscore must separate the locale with any optional text that follows.
        3. The file must only contain translation data for the single locale.

        Example:
        "/config/locales/fr.yml" which contains:
        ```yml
          fr:
            dog:
              chien
        ```
      MSG
    end
  end
end