fast_gettext 4.1.1 → 4.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c5e2843e35fbde82280e708ad953d0e2e4db2046c401f228d8f80b2c678eb149
4
- data.tar.gz: 300f5b287b2398b0706f79050eca58556c16ee54f8f8b88ab504c8f417cc8b3a
3
+ metadata.gz: 2add114a98a74b14ab732ccee6fbe25e0298c6d766f166ae7656304ff1bb29d7
4
+ data.tar.gz: aaee771bc595d542e3954da371d3cb661a2b6d7f4b38ed1d5b71ab9909fda919
5
5
  SHA512:
6
- metadata.gz: 7a0c08120aa700cb08721d646e6665d2a124ec560306e5464af1b7ba8eb966225f1ae582328b56e6d74dc0354dc7d09046244a0587c6d08ad9a5845254965a1c
7
- data.tar.gz: 754482e2e9301da6aa510b7d6005074fd94c7aec9d195a29b4a5dfa97822c37cf82022ff8f4d13dabe4364982ff7e284734e51b114f1aa27e99a65b6d756bcf4
6
+ metadata.gz: 5df7240d2fa1f5e42e8e552358dd3ba2e564edb837e22d9e64380d3c08404b1d1c4d5cd93d3c4da2546934d430474746cf475393936b7500a727e52ff625fe48
7
+ data.tar.gz: 58c342df8b8fba16c25003d5b8126984556acf8fd9c0bab9ae8393fa1d7e111c5b5bd3360fd562342da0985c81da3965a8998af79a5c670e55b577e4a7eb268b
data/CHANGELOG CHANGED
@@ -1,3 +1,4 @@
1
+ 4.2.0 -- cache pluralisation rule
1
2
  4.1.0 -- drop EOL rubies + add racc dependency
2
3
  4.0.0 -- Remove String#% hack that would make it not blow up when using invalid keys, can temporarily restore with `FastGettext.allow_invalid_keys!`
3
4
  3.1.0 -- Work with frozen strings
@@ -25,17 +25,12 @@ module FastGettext
25
25
  split_plurals(self[msgids * PLURAL_SEPARATOR].to_s)
26
26
  end
27
27
 
28
+ # n_() asks for this on every call: read from the header and compiled the
29
+ # first time, then kept (nil when the file has none).
28
30
  def pluralisation_rule
29
- # gettext uses 0 as default rule, which would turn off all pluralisation, very clever...
30
- # additionally parsing fails when directly accessing po files, so this line was taken from gettext/mofile
31
- (data[''] || '').split("\n").each do |line|
32
- if /^Plural-Forms:\s*nplurals\s*\=\s*(\d*);\s*plural\s*\=\s*([^;]*)\n?/ =~ line
33
- return ->(n) do # rubocop:disable Lint/UnusedBlockArgument
34
- eval($2) # rubocop:disable Security/Eval
35
- end
36
- end
37
- end
38
- nil
31
+ return @pluralisation_rule if defined?(@pluralisation_rule)
32
+
33
+ @pluralisation_rule = read_pluralisation_rule
39
34
  end
40
35
 
41
36
  def data
@@ -44,11 +39,28 @@ module FastGettext
44
39
  end
45
40
 
46
41
  def self.empty
47
- @empty ||= MoFile.new(File.join(__dir__, 'vendor', 'empty.mo'), eager_load: true).freeze
42
+ @empty ||= begin
43
+ empty = MoFile.new(File.join(__dir__, 'vendor', 'empty.mo'), eager_load: true)
44
+ # pluralisation_rule keeps what it computed in an instance variable, which
45
+ # it can't set once the object is frozen: compute it first
46
+ empty.pluralisation_rule
47
+ empty.freeze
48
+ end
48
49
  end
49
50
 
50
51
  private
51
52
 
53
+ def read_pluralisation_rule
54
+ # gettext uses 0 as default rule, which would turn off all pluralisation, very clever...
55
+ # additionally parsing fails when directly accessing po files, so this line was taken from gettext/mofile
56
+ (data[''] || '').split("\n").each do |line|
57
+ if /^Plural-Forms:\s*nplurals\s*=\s*(\d*);\s*plural\s*=\s*([^;]*)\n?/ =~ line
58
+ return eval("->(n) { #{$2} }", nil, __FILE__, __LINE__) # rubocop:disable Security/Eval
59
+ end
60
+ end
61
+ nil
62
+ end
63
+
52
64
  def load_data
53
65
  @data =
54
66
  if @filename.is_a? FastGettext::GetText::MOFile
@@ -63,7 +63,9 @@ module FastGettext
63
63
  # if overwritten by user( FastGettext.pluralisation_rule = xxx) use it,
64
64
  # otherwise fall back to repo or to default lambda
65
65
  def pluralisation_rule
66
- Thread.current[:fast_gettext_pluralisation_rule] || current_repository.pluralisation_rule || DEFAULT_PLURALIZATION_RULE
66
+ Thread.current[:fast_gettext_pluralisation_rule] ||
67
+ current_repository.pluralisation_rule ||
68
+ DEFAULT_PLURALIZATION_RULE
67
69
  end
68
70
 
69
71
  def cache
@@ -72,7 +74,7 @@ module FastGettext
72
74
 
73
75
  def reload!
74
76
  cache.reload!
75
- translation_repositories.values.each(&:reload)
77
+ translation_repositories.each_value(&:reload)
76
78
  end
77
79
 
78
80
  # global, since re-parsing whole folders takes too much time...
@@ -94,7 +96,7 @@ module FastGettext
94
96
  end
95
97
 
96
98
  def cached_plural_find(*keys)
97
- key = '||||' + keys * '||||'
99
+ key = "||||#{keys * '||||'}"
98
100
  cache.fetch(key) { current_repository.plural(*keys) }
99
101
  end
100
102
 
@@ -134,7 +136,8 @@ module FastGettext
134
136
  # IE6/7 de
135
137
  # nil if nothing matches
136
138
  def best_locale_in(locales)
137
- formatted_sorted_locales(locales).each do |candidate|
139
+ candidates = plain_locale(locales) || formatted_sorted_locales(locales)
140
+ candidates.each do |candidate|
138
141
  return candidate unless available_locales
139
142
  return candidate if available_locales.include?(candidate)
140
143
  return candidate[0..1] if available_locales.include?(candidate[0..1]) # available locales include a langauge
@@ -160,9 +163,21 @@ module FastGettext
160
163
 
161
164
  private
162
165
 
166
+ # A single locale already in the de / de_DE form, as set_locale gets it on
167
+ # every I18n.locale= or with_locale (gettext_i18n_rails): parsing it as
168
+ # an Accept-Language header would give the same one candidate.
169
+ PLAIN_LOCALE = /\A[a-z]{2,3}(?:_[A-Z]{2,3})?\z/
170
+ private_constant :PLAIN_LOCALE
171
+
172
+ def plain_locale(locale)
173
+ locale = locale.name if locale.is_a?(Symbol)
174
+ [locale.dup] if locale.is_a?(String) && PLAIN_LOCALE.match?(locale)
175
+ end
176
+
163
177
  # de-de,DE-CH;q=0.9 -> ['de_DE','de_CH']
164
178
  def formatted_sorted_locales(locales)
165
- found = weighted_locales(locales).reject(&:empty?).sort_by(&:last).reverse # sort them by weight which is the last entry
179
+ # sort them by weight which is the last entry
180
+ found = weighted_locales(locales).reject(&:empty?).sort_by(&:last).reverse
166
181
  found.flatten.map { |l| format_locale(l) }
167
182
  end
168
183
 
@@ -173,7 +188,7 @@ module FastGettext
173
188
  found = [[]]
174
189
  locales.split(',').each do |part|
175
190
  if part.include? ';q=' # contains language and weight ?
176
- found.last << part.split(/;q=/)
191
+ found.last << part.split(';q=')
177
192
  found.last.flatten!
178
193
  found << []
179
194
  else
@@ -185,7 +200,7 @@ module FastGettext
185
200
 
186
201
  # de-de -> de_DE
187
202
  def format_locale(locale)
188
- locale.sub(/^([a-zA-Z]{2,3})[-_]([a-zA-Z]{2,3})$/) { $1.downcase + '_' + $2.upcase }
203
+ locale.sub(/^([a-zA-Z]{2,3})[-_]([a-zA-Z]{2,3})$/) { "#{$1.downcase}_#{$2.upcase}" }
189
204
  end
190
205
 
191
206
  def switch_cache
@@ -2,7 +2,7 @@
2
2
 
3
3
  module FastGettext
4
4
  TRANSLATION_METHODS = [:_, :n_, :s_, :p_, :ns_, :np_].freeze
5
- NIL_BLOCK = -> { nil }
5
+ NIL_BLOCK = -> {}
6
6
 
7
7
  # this module should be included
8
8
  # Responsibility:
@@ -90,6 +90,7 @@ module FastGettext
90
90
 
91
91
  module TranslationAliased
92
92
  include Translation
93
+
93
94
  TRANSLATION_METHODS.each { |m| alias_method "#{m.to_s.delete('_')}gettext", m }
94
95
  end
95
96
 
@@ -8,7 +8,9 @@ class TranslationKey < ActiveRecord::Base
8
8
  validates_uniqueness_of :key
9
9
  validates_presence_of :key
10
10
 
11
- attr_accessible :key, :translations, :translations_attributes if ActiveRecord::VERSION::MAJOR == 3 || defined?(ProtectedAttributes)
11
+ if ActiveRecord::VERSION::MAJOR == 3 || defined?(ProtectedAttributes)
12
+ attr_accessible :key, :translations, :translations_attributes
13
+ end
12
14
 
13
15
  before_save :normalize_newlines
14
16
 
@@ -20,13 +22,11 @@ class TranslationKey < ActiveRecord::Base
20
22
  end
21
23
 
22
24
  def self.available_locales
23
- @available_locales ||= begin
24
- if ActiveRecord::VERSION::MAJOR >= 3
25
- TranslationText.group(:locale).count
26
- else
27
- TranslationText.count(group: :locale)
28
- end.keys.sort
29
- end
25
+ @available_locales ||= if ActiveRecord::VERSION::MAJOR >= 3
26
+ TranslationText.group(:locale).count
27
+ else
28
+ TranslationText.count(group: :locale)
29
+ end.keys.sort
30
30
  end
31
31
 
32
32
  def self.newline_normalize(string)
@@ -4,7 +4,9 @@ class TranslationText < ActiveRecord::Base
4
4
  belongs_to :translation_key, class_name: 'TranslationKey'
5
5
  validates_presence_of :locale
6
6
  validates_uniqueness_of :locale, scope: :translation_key_id
7
- attr_accessible :text, :locale, :translation_key, :translation_key_id if ActiveRecord::VERSION::MAJOR == 3 || defined?(ProtectedAttributes)
7
+ if ActiveRecord::VERSION::MAJOR == 3 || defined?(ProtectedAttributes)
8
+ attr_accessible :text, :locale, :translation_key, :translation_key_id
9
+ end
8
10
  after_update :expire_cache
9
11
 
10
12
  protected
@@ -11,7 +11,7 @@ module FastGettext
11
11
  class Merge < Base
12
12
  def initialize(name, options = {})
13
13
  clear
14
- super(name, options)
14
+ super
15
15
  options.fetch(:chain, []).each do |repo|
16
16
  add_repo(repo)
17
17
  end
@@ -24,12 +24,14 @@ module FastGettext
24
24
  end
25
25
  end
26
26
 
27
+ # n_() asks for this on every call: each rule is compiled once, keyed by
28
+ # its text, so locales with different rules get their own lambda and
29
+ # locales with the same rule share one.
27
30
  def pluralisation_rule
28
31
  return unless rule = self['pluralisation_rule']
29
32
 
30
- ->(n) do # rubocop:disable Lint/UnusedBlockArgument n can be used from pluralisation_rule code
31
- eval(rule) # rubocop:disable Security/Eval TODO remove eval
32
- end
33
+ (@pluralisation_rules ||= {})[rule] ||=
34
+ eval("->(n) { #{rule} }", nil, __FILE__, __LINE__) # rubocop:disable Security/Eval -- TODO remove eval
33
35
  end
34
36
 
35
37
  def reload
@@ -79,7 +81,7 @@ module FastGettext
79
81
  result
80
82
  end
81
83
 
82
- def yaml_dot_notation(a, b) # rubocop:disable Naming/UncommunicativeMethodParamName
84
+ def yaml_dot_notation(a, b)
83
85
  a ? "#{a}.#{b}" : b
84
86
  end
85
87
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module FastGettext
4
- VERSION = Version = '4.1.1' # rubocop:disable Naming/ConstantName
4
+ VERSION = Version = '4.2.0' # rubocop:disable Naming/ConstantName
5
5
  end
data/lib/fast_gettext.rb CHANGED
@@ -11,7 +11,7 @@ module FastGettext
11
11
  extend FastGettext::Storage
12
12
  extend FastGettext::Translation
13
13
 
14
- LOCALE_REX = /^[a-z]{2,3}$|^[a-z]{2,3}_[A-Z]{2,3}$/.freeze
14
+ LOCALE_REX = /^[a-z]{2,3}$|^[a-z]{2,3}_[A-Z]{2,3}$/
15
15
  NAMESPACE_SEPARATOR = '|'
16
16
  CONTEXT_SEPARATOR = "\004"
17
17
 
@@ -30,7 +30,7 @@ module FastGettext
30
30
 
31
31
  # deprecated, just a crutch to migrate to new api
32
32
  def self.allow_invalid_keys!
33
- eval(<<~CODE)
33
+ eval(<<~CODE, binding, __FILE__, __LINE__ + 1)
34
34
  class ::String
35
35
  alias :_fast_gettext_old_format_m :%
36
36
  def %(*args)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fast_gettext
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.1.1
4
+ version: 4.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Grosser
@@ -221,7 +221,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
221
221
  requirements:
222
222
  - - ">="
223
223
  - !ruby/object:Gem::Version
224
- version: 3.2.0
224
+ version: 3.3.0
225
225
  required_rubygems_version: !ruby/object:Gem::Requirement
226
226
  requirements:
227
227
  - - ">="