fast_gettext 1.6.0 → 2.1.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 +5 -5
- data/CHANGELOG +4 -3
- data/Readme.md +146 -51
- data/lib/fast_gettext/cache.rb +4 -2
- data/lib/fast_gettext/mo_file.rb +29 -19
- data/lib/fast_gettext/po_file.rb +17 -14
- data/lib/fast_gettext/storage.rb +38 -32
- data/lib/fast_gettext/translation.rb +81 -107
- data/lib/fast_gettext/translation_repository/base.rb +9 -6
- data/lib/fast_gettext/translation_repository/chain.rb +11 -5
- data/lib/fast_gettext/translation_repository/db.rb +12 -13
- data/lib/fast_gettext/translation_repository/db_models/translation_key.rb +11 -8
- data/lib/fast_gettext/translation_repository/db_models/translation_text.rb +4 -2
- data/lib/fast_gettext/translation_repository/logger.rb +4 -2
- data/lib/fast_gettext/translation_repository/merge.rb +9 -4
- data/lib/fast_gettext/translation_repository/mo.rb +8 -4
- data/lib/fast_gettext/translation_repository/po.rb +5 -2
- data/lib/fast_gettext/translation_repository/yaml.rb +16 -6
- data/lib/fast_gettext/translation_repository.rb +5 -5
- data/lib/fast_gettext/version.rb +3 -1
- data/lib/fast_gettext.rb +16 -16
- metadata +33 -6
@@ -1,13 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module FastGettext
|
2
4
|
module TranslationRepository
|
3
5
|
# Responsibility:
|
4
6
|
# - base for all repositories
|
5
7
|
# - fallback as empty repository, that cannot translate anything but does not crash
|
6
8
|
class Base
|
7
|
-
|
8
9
|
attr_reader :name, :options
|
9
10
|
|
10
|
-
def initialize(name,options={})
|
11
|
+
def initialize(name, options = {})
|
11
12
|
@name = name
|
12
13
|
@options = options
|
13
14
|
end
|
@@ -38,17 +39,19 @@ module FastGettext
|
|
38
39
|
MoFile.empty
|
39
40
|
end
|
40
41
|
|
41
|
-
def find_files_in_locale_folders(relative_file_path,path)
|
42
|
+
def find_files_in_locale_folders(relative_file_path, path)
|
42
43
|
path ||= "locale"
|
43
44
|
raise "path #{path} could not be found!" unless File.exist?(path)
|
44
45
|
|
45
46
|
@files = {}
|
46
|
-
Dir[File.join(path,'*')].each do |locale_folder|
|
47
|
+
Dir[File.join(path, '*')].each do |locale_folder|
|
47
48
|
next unless File.basename(locale_folder) =~ LOCALE_REX
|
48
|
-
|
49
|
+
|
50
|
+
file = File.join(locale_folder, relative_file_path)
|
49
51
|
next unless File.exist? file
|
52
|
+
|
50
53
|
locale = File.basename(locale_folder)
|
51
|
-
@files[locale] = yield(locale,file)
|
54
|
+
@files[locale] = yield(locale, file)
|
52
55
|
end
|
53
56
|
end
|
54
57
|
end
|
@@ -1,32 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'fast_gettext/translation_repository/base'
|
2
4
|
|
3
5
|
module FastGettext
|
4
6
|
module TranslationRepository
|
5
7
|
# Responsibility:
|
6
8
|
# - delegate calls to members of the chain in turn
|
7
|
-
#TODO cache should be expired after a repo was added
|
9
|
+
# TODO cache should be expired after a repo was added
|
8
10
|
class Chain < Base
|
9
11
|
attr_accessor :chain
|
10
12
|
|
11
|
-
def initialize(name,options={})
|
13
|
+
def initialize(name, options = {})
|
12
14
|
super
|
13
15
|
self.chain = options[:chain]
|
14
16
|
end
|
15
17
|
|
16
18
|
def available_locales
|
17
|
-
chain.map
|
19
|
+
chain.map(&:available_locales).flatten.uniq
|
18
20
|
end
|
19
21
|
|
20
22
|
def pluralisation_rule
|
21
23
|
chain.each do |c|
|
22
|
-
result = c.pluralisation_rule
|
24
|
+
if result = c.pluralisation_rule
|
25
|
+
return result
|
26
|
+
end
|
23
27
|
end
|
24
28
|
nil
|
25
29
|
end
|
26
30
|
|
27
31
|
def [](key)
|
28
32
|
chain.each do |c|
|
29
|
-
result = c[key]
|
33
|
+
if result = c[key]
|
34
|
+
return result
|
35
|
+
end
|
30
36
|
end
|
31
37
|
nil
|
32
38
|
end
|
@@ -1,4 +1,5 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
2
3
|
module FastGettext
|
3
4
|
module TranslationRepository
|
4
5
|
# Responsibility:
|
@@ -11,13 +12,14 @@ module FastGettext
|
|
11
12
|
# key: find_by_key, translations
|
12
13
|
# translation: text, locale
|
13
14
|
class Db
|
14
|
-
def initialize(
|
15
|
+
def initialize(_name, options = {})
|
15
16
|
@model = options[:model]
|
16
17
|
end
|
17
18
|
|
18
|
-
|
19
|
-
|
20
|
-
|
19
|
+
@separator = '||||' # string that separates multiple plurals
|
20
|
+
class << self
|
21
|
+
attr_accessor :separator
|
22
|
+
end
|
21
23
|
|
22
24
|
def available_locales
|
23
25
|
if @model.respond_to? :available_locales
|
@@ -28,11 +30,7 @@ module FastGettext
|
|
28
30
|
end
|
29
31
|
|
30
32
|
def pluralisation_rule
|
31
|
-
if @model.respond_to? :
|
32
|
-
@model.pluralsation_rule
|
33
|
-
else
|
34
|
-
nil
|
35
|
-
end
|
33
|
+
@model.pluralisation_rule if @model.respond_to? :pluralisation_rule
|
36
34
|
end
|
37
35
|
|
38
36
|
def [](key)
|
@@ -40,8 +38,8 @@ module FastGettext
|
|
40
38
|
end
|
41
39
|
|
42
40
|
def plural(*args)
|
43
|
-
if translation = @model.translation(args*self.class.
|
44
|
-
translation.to_s.split(self.class.
|
41
|
+
if translation = @model.translation(args * self.class.separator, FastGettext.locale)
|
42
|
+
translation.to_s.split(self.class.separator)
|
45
43
|
else
|
46
44
|
[]
|
47
45
|
end
|
@@ -52,11 +50,12 @@ module FastGettext
|
|
52
50
|
end
|
53
51
|
|
54
52
|
def self.require_models
|
53
|
+
require 'active_record'
|
55
54
|
folder = "fast_gettext/translation_repository/db_models"
|
56
55
|
require "#{folder}/translation_key"
|
57
56
|
require "#{folder}/translation_text"
|
58
57
|
Module.new do
|
59
|
-
def self.included(
|
58
|
+
def self.included(_base)
|
60
59
|
puts "you no longer need to include the result of require_models"
|
61
60
|
end
|
62
61
|
end
|
@@ -1,7 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class TranslationKey < ActiveRecord::Base
|
2
|
-
has_many :translations, :
|
4
|
+
has_many :translations, class_name: 'TranslationText', dependent: :destroy
|
3
5
|
|
4
|
-
accepts_nested_attributes_for :translations, :
|
6
|
+
accepts_nested_attributes_for :translations, allow_destroy: true
|
5
7
|
|
6
8
|
validates_uniqueness_of :key
|
7
9
|
validates_presence_of :key
|
@@ -13,25 +15,26 @@ class TranslationKey < ActiveRecord::Base
|
|
13
15
|
def self.translation(key, locale)
|
14
16
|
return unless translation_key = find_by_key(newline_normalize(key))
|
15
17
|
return unless translation_text = translation_key.translations.find_by_locale(locale)
|
18
|
+
|
16
19
|
translation_text.text
|
17
20
|
end
|
18
21
|
|
19
22
|
def self.available_locales
|
20
|
-
|
23
|
+
@available_locales ||= begin
|
21
24
|
if ActiveRecord::VERSION::MAJOR >= 3
|
22
25
|
TranslationText.group(:locale).count
|
23
26
|
else
|
24
|
-
TranslationText.count(:
|
27
|
+
TranslationText.count(group: :locale)
|
25
28
|
end.keys.sort
|
26
29
|
end
|
27
30
|
end
|
28
31
|
|
29
|
-
|
30
|
-
|
31
|
-
def self.newline_normalize(s)
|
32
|
-
s.to_s.gsub("\r\n", "\n")
|
32
|
+
def self.newline_normalize(string)
|
33
|
+
string.to_s.gsub("\r\n", "\n")
|
33
34
|
end
|
34
35
|
|
36
|
+
protected
|
37
|
+
|
35
38
|
def normalize_newlines
|
36
39
|
self.key = self.class.newline_normalize(key)
|
37
40
|
end
|
@@ -1,7 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class TranslationText < ActiveRecord::Base
|
2
|
-
belongs_to :translation_key, :
|
4
|
+
belongs_to :translation_key, class_name: 'TranslationKey'
|
3
5
|
validates_presence_of :locale
|
4
|
-
validates_uniqueness_of :locale, :
|
6
|
+
validates_uniqueness_of :locale, scope: :translation_key_id
|
5
7
|
attr_accessible :text, :locale, :translation_key, :translation_key_id if ActiveRecord::VERSION::MAJOR == 3 || defined?(ProtectedAttributes)
|
6
8
|
after_update :expire_cache
|
7
9
|
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'fast_gettext/translation_repository/base'
|
2
4
|
|
3
5
|
module FastGettext
|
@@ -8,7 +10,7 @@ module FastGettext
|
|
8
10
|
class Logger < Base
|
9
11
|
attr_accessor :callback
|
10
12
|
|
11
|
-
def initialize(name,options={})
|
13
|
+
def initialize(name, options = {})
|
12
14
|
super
|
13
15
|
self.callback = options[:callback]
|
14
16
|
end
|
@@ -24,4 +26,4 @@ module FastGettext
|
|
24
26
|
end
|
25
27
|
end
|
26
28
|
end
|
27
|
-
end
|
29
|
+
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'fast_gettext/translation_repository/po'
|
2
4
|
|
3
5
|
module FastGettext
|
@@ -7,7 +9,7 @@ module FastGettext
|
|
7
9
|
# - can be used instead of searching for translations in multiple domains
|
8
10
|
# - requires reload when current locale is changed
|
9
11
|
class Merge < Base
|
10
|
-
def initialize(name, options={})
|
12
|
+
def initialize(name, options = {})
|
11
13
|
clear
|
12
14
|
super(name, options)
|
13
15
|
options.fetch(:chain, []).each do |repo|
|
@@ -21,7 +23,9 @@ module FastGettext
|
|
21
23
|
|
22
24
|
def pluralisation_rule
|
23
25
|
@repositories.each do |r|
|
24
|
-
result = r.pluralisation_rule
|
26
|
+
if result = r.pluralisation_rule
|
27
|
+
return result
|
28
|
+
end
|
25
29
|
end
|
26
30
|
nil
|
27
31
|
end
|
@@ -45,6 +49,7 @@ module FastGettext
|
|
45
49
|
|
46
50
|
def add_repo(repo)
|
47
51
|
raise "Unsupported repository" unless repo_supported?(repo)
|
52
|
+
|
48
53
|
@repositories << repo
|
49
54
|
load_repo(repo)
|
50
55
|
true
|
@@ -65,8 +70,8 @@ module FastGettext
|
|
65
70
|
repo.respond_to?(:all_translations)
|
66
71
|
end
|
67
72
|
|
68
|
-
def load_repo(
|
69
|
-
@data =
|
73
|
+
def load_repo(repo)
|
74
|
+
@data = repo.all_translations.merge(@data)
|
70
75
|
end
|
71
76
|
end
|
72
77
|
end
|
@@ -1,11 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'fast_gettext/translation_repository/base'
|
2
4
|
module FastGettext
|
3
5
|
module TranslationRepository
|
4
|
-
|
6
|
+
# Responsibility:
|
5
7
|
# - find and store mo files
|
6
8
|
# - provide access to translations in mo files
|
7
9
|
class Mo < Base
|
8
|
-
|
10
|
+
CONTEXT_SEPARATOR = "\u0004"
|
11
|
+
|
12
|
+
def initialize(name, options = {})
|
9
13
|
super
|
10
14
|
@eager_load = options.fetch(:eager_load, false)
|
11
15
|
reload
|
@@ -30,9 +34,9 @@ module FastGettext
|
|
30
34
|
|
31
35
|
protected
|
32
36
|
|
33
|
-
def find_and_store_files(name,options)
|
37
|
+
def find_and_store_files(name, options)
|
34
38
|
# parse all .mo files with the right name, that sit in locale/LC_MESSAGES folders
|
35
|
-
find_files_in_locale_folders(File.join('LC_MESSAGES',"#{name}.mo"), options[:path]) do |
|
39
|
+
find_files_in_locale_folders(File.join('LC_MESSAGES', "#{name}.mo"), options[:path]) do |_locale, file|
|
36
40
|
MoFile.new(file, eager_load: @eager_load)
|
37
41
|
end
|
38
42
|
end
|
@@ -1,15 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'fast_gettext/translation_repository/base'
|
2
4
|
require 'fast_gettext/translation_repository/mo'
|
3
5
|
module FastGettext
|
4
6
|
module TranslationRepository
|
5
|
-
|
7
|
+
# Responsibility:
|
6
8
|
# - find and store po files
|
7
9
|
# - provide access to translations in po files
|
8
10
|
class Po < Mo
|
9
11
|
protected
|
12
|
+
|
10
13
|
def find_and_store_files(name, options)
|
11
14
|
require 'fast_gettext/po_file'
|
12
|
-
find_files_in_locale_folders("#{name}.po", options[:path]) do |
|
15
|
+
find_files_in_locale_folders("#{name}.po", options[:path]) do |_locale, file|
|
13
16
|
PoFile.new(file, options)
|
14
17
|
end
|
15
18
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'fast_gettext/translation_repository/base'
|
2
4
|
require 'yaml'
|
3
5
|
|
@@ -7,7 +9,7 @@ module FastGettext
|
|
7
9
|
# - find and store yaml files
|
8
10
|
# - provide access to translations in yaml files
|
9
11
|
class Yaml < Base
|
10
|
-
def initialize(name,options={})
|
12
|
+
def initialize(name, options = {})
|
11
13
|
super
|
12
14
|
reload
|
13
15
|
end
|
@@ -23,7 +25,11 @@ module FastGettext
|
|
23
25
|
end
|
24
26
|
|
25
27
|
def pluralisation_rule
|
26
|
-
|
28
|
+
return unless rule = self['pluralisation_rule']
|
29
|
+
|
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
|
27
33
|
end
|
28
34
|
|
29
35
|
def reload
|
@@ -39,8 +45,12 @@ module FastGettext
|
|
39
45
|
@files = {}
|
40
46
|
path = options[:path] || 'config/locales'
|
41
47
|
Dir["#{path}/*.yml"].each do |yaml_file|
|
42
|
-
|
43
|
-
|
48
|
+
# Only take into account the last dot separeted part of the file name,
|
49
|
+
# excluding the extension file name
|
50
|
+
# that is, we suppose it to be named `qq.yml` or `foo.qq.yml` where
|
51
|
+
# `qq` stands for a locale name
|
52
|
+
locale = File.basename(yaml_file, '.yml').split('.').last
|
53
|
+
(@files[locale] ||= {}).merge! load_yaml(yaml_file, locale)
|
44
54
|
end
|
45
55
|
end
|
46
56
|
|
@@ -60,7 +70,7 @@ module FastGettext
|
|
60
70
|
|
61
71
|
def add_yaml_key(result, prefix, hash)
|
62
72
|
hash.each_pair do |key, value|
|
63
|
-
if value.
|
73
|
+
if value.is_a?(Hash)
|
64
74
|
add_yaml_key(result, yaml_dot_notation(prefix, key), value)
|
65
75
|
else
|
66
76
|
result[yaml_dot_notation(prefix, key)] = value
|
@@ -69,7 +79,7 @@ module FastGettext
|
|
69
79
|
result
|
70
80
|
end
|
71
81
|
|
72
|
-
def yaml_dot_notation(a,b)
|
82
|
+
def yaml_dot_notation(a, b) # rubocop:disable Naming/UncommunicativeMethodParamName
|
73
83
|
a ? "#{a}.#{b}" : b
|
74
84
|
end
|
75
85
|
end
|
@@ -1,16 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module FastGettext
|
2
4
|
# Responsibility:
|
3
5
|
# - decide which repository to choose from given input
|
4
6
|
module TranslationRepository
|
5
|
-
|
6
|
-
|
7
|
-
def build(name, options)
|
7
|
+
def self.build(name, options)
|
8
8
|
type = options[:type] || :mo
|
9
9
|
class_name = type.to_s.split('_').map(&:capitalize).join
|
10
|
-
unless FastGettext::TranslationRepository.constants.map
|
10
|
+
unless FastGettext::TranslationRepository.constants.map(&:to_s).include?(class_name)
|
11
11
|
require "fast_gettext/translation_repository/#{type}"
|
12
12
|
end
|
13
|
-
|
13
|
+
const_get(class_name).new(name, options)
|
14
14
|
end
|
15
15
|
end
|
16
16
|
end
|
data/lib/fast_gettext/version.rb
CHANGED
data/lib/fast_gettext.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'fast_gettext/mo_file'
|
2
4
|
require 'fast_gettext/storage'
|
3
5
|
require 'fast_gettext/translation'
|
@@ -6,30 +8,28 @@ require 'fast_gettext/vendor/string'
|
|
6
8
|
require 'fast_gettext/version'
|
7
9
|
|
8
10
|
module FastGettext
|
9
|
-
|
10
|
-
extend
|
11
|
+
extend FastGettext::Storage
|
12
|
+
extend FastGettext::Translation
|
11
13
|
|
12
|
-
LOCALE_REX =
|
14
|
+
LOCALE_REX = /^[a-z]{2,3}$|^[a-z]{2,3}_[A-Z]{2,3}$/.freeze
|
13
15
|
NAMESPACE_SEPARATOR = '|'
|
16
|
+
CONTEXT_SEPARATOR = "\004"
|
14
17
|
|
15
|
-
#
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
define_method method do |*args|
|
23
|
-
Translation.send(method,*args)
|
24
|
-
end
|
18
|
+
# helper block for changing domains
|
19
|
+
def self.with_domain(domain)
|
20
|
+
old_domain = FastGettext.text_domain
|
21
|
+
FastGettext.text_domain = domain
|
22
|
+
yield
|
23
|
+
ensure
|
24
|
+
FastGettext.text_domain = old_domain
|
25
25
|
end
|
26
26
|
|
27
|
-
def add_text_domain(name,options)
|
28
|
-
translation_repositories[name] = TranslationRepository.build(name,options)
|
27
|
+
def self.add_text_domain(name, options)
|
28
|
+
translation_repositories[name] = TranslationRepository.build(name, options)
|
29
29
|
end
|
30
30
|
|
31
31
|
# some repositories know where to store their locales
|
32
|
-
def locale_path
|
32
|
+
def self.locale_path
|
33
33
|
translation_repositories[text_domain].instance_variable_get(:@options)[:path]
|
34
34
|
end
|
35
35
|
end
|