mini_i18n 0.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 7a18d6e7a53f09252437f9557843123ec13e0838
4
+ data.tar.gz: 07a9b806306b8d5fd249de308fda043f4f855b41
5
+ SHA512:
6
+ metadata.gz: d2b2e9c69c77528d54bbd24d723441d0cbe009001855ce77fe69fe164738956ec021e5ccb6288adf588997c50735a305336b1da7ace3186f8239c9afedd3e4a1
7
+ data.tar.gz: 0ae3f4faa23a0f81088d7180afa463b419f2309af6b0aedc715bb853208b4f7cd0bf91b4a3eecc2eabdb8037db00a83029fb35ed65925f2cc0b134340a2db9c8
@@ -0,0 +1,31 @@
1
+ module MiniI18n
2
+ module Utils
3
+ extend self
4
+
5
+ def interpolate(string, keys)
6
+ string % keys
7
+ rescue KeyError
8
+ string
9
+ end
10
+
11
+ def replace_with(array, old_elem, new_elem)
12
+ array.map { |elem| elem == old_elem ? new_elem : elem }
13
+ end
14
+
15
+ def deep_merge(merge_to, merge_from)
16
+ merged = merge_to.clone
17
+
18
+ merge_from.each do |key, value|
19
+ key = key.to_s
20
+
21
+ if value.is_a?(Hash) && merged[key].is_a?(Hash)
22
+ merged[key] = deep_merge(merged[key], value)
23
+ else
24
+ merged[key] = value
25
+ end
26
+ end
27
+
28
+ merged
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,3 @@
1
+ module MiniI18n
2
+ VERSION = "0.1.0"
3
+ end
data/lib/mini_i18n.rb ADDED
@@ -0,0 +1,105 @@
1
+ require "yaml"
2
+ require "mini_i18n/version"
3
+ require "mini_i18n/utils"
4
+
5
+ module MiniI18n
6
+ class << self
7
+ DEFAULT_LOCALE = :en
8
+ SEPARATOR = '.'
9
+
10
+ attr_accessor :fallbacks
11
+
12
+ def default_locale
13
+ @@default_locale ||= DEFAULT_LOCALE
14
+ end
15
+
16
+ def default_locale=(new_locale)
17
+ @@default_locale = valid_locale?(new_locale) || default_locale
18
+ end
19
+
20
+ def default_available_locales
21
+ @@default_available_locales ||= translations.keys
22
+ end
23
+
24
+ def available_locales
25
+ @@available_locales ||= default_available_locales
26
+ end
27
+
28
+ def available_locales=(new_locales)
29
+ @@available_locales = new_locales.map(&:to_s)
30
+ end
31
+
32
+ def translations
33
+ @@translations ||= {}
34
+ end
35
+
36
+ def locale
37
+ Thread.current[:mini_i18n_locale] ||= default_locale
38
+ end
39
+
40
+ def locale=(new_locale)
41
+ set_locale(new_locale)
42
+ end
43
+
44
+ def configure
45
+ yield(self) if block_given?
46
+ end
47
+
48
+ def load_translations(path)
49
+ Dir[path].each do |file|
50
+ _translations = YAML.load_file(file)
51
+ _translations.each do |locale, values|
52
+ locale = locale.to_s
53
+ @@available_locales << locale unless available_locale?(locale)
54
+
55
+ if translations[locale]
56
+ translations[locale] = Utils.deep_merge(translations[locale], values)
57
+ else
58
+ translations[locale] = values
59
+ end
60
+ end
61
+ end
62
+ end
63
+
64
+ def translate(key, options = {})
65
+ return if key.empty? || translations.empty?
66
+
67
+ _locale = available_locale?(options[:locale]) || locale
68
+ scope = options[:scope]
69
+
70
+ keys = [_locale.to_s]
71
+ keys << scope.to_s.split(SEPARATOR) if scope
72
+ keys << key.to_s.split(SEPARATOR)
73
+ keys = keys.flatten
74
+
75
+ result = translations.dig(*keys)
76
+
77
+ if fallbacks && result.empty?
78
+ keys = Utils.replace_with(keys, _locale, default_locale.to_s)
79
+ result = translations.dig(*keys)
80
+ end
81
+
82
+ if result.respond_to?(:match) && result.match(/%{\w+}/)
83
+ result = Utils.interpolate(result, options)
84
+ end
85
+
86
+ result || options[:default]
87
+ end
88
+ alias t translate
89
+
90
+ private
91
+
92
+ def set_locale(new_locale)
93
+ new_locale = new_locale.to_s
94
+ if available_locale?(new_locale)
95
+ Thread.current[:mini_i18n_locale] = new_locale
96
+ end
97
+ locale
98
+ end
99
+
100
+ def available_locale?(new_locale)
101
+ new_locale = new_locale.to_s
102
+ available_locales.include?(new_locale) && new_locale
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,6 @@
1
+ en:
2
+ hello: "hello"
3
+ hello_interpolation: "hello %{name}"
4
+ fallback: "fallback"
5
+ second_level:
6
+ hello: ""
@@ -0,0 +1,19 @@
1
+ en:
2
+ bye: "bye"
3
+ second_level:
4
+ hello: "hello 2"
5
+
6
+ es:
7
+ hello: "hola"
8
+ hello_interpolation: "hola %{name}"
9
+ fallback: ""
10
+ bye: "adiós"
11
+ second_level:
12
+ hello: "hola 2"
13
+
14
+ fr:
15
+ hello: "bonjour"
16
+ hello_interpolation: "bonjour %{name}"
17
+ bye: "au revoir"
18
+ second_level:
19
+ hello: "bonjour 2"
@@ -0,0 +1,68 @@
1
+ RSpec.describe MiniI18n do
2
+ before(:all) do
3
+ MiniI18n.load_translations File.expand_path(__dir__ + '/fixtures/locales/*')
4
+ end
5
+
6
+ before(:each) do
7
+ MiniI18n.locale = :en
8
+ MiniI18n.fallbacks = false
9
+ end
10
+
11
+ describe 'load_translations' do
12
+ it "allows to load multiple locales and translations from different files" do
13
+ expect(MiniI18n.available_locales).to eq ["en", "es", "fr"]
14
+ expect(MiniI18n.translations.size). to eq 3
15
+ expect(MiniI18n.translations["en"]).to include 'bye'
16
+ end
17
+ end
18
+
19
+ describe 'translate' do
20
+ it "simple key" do
21
+ expect(MiniI18n.t(:hello)).to eq 'hello'
22
+ end
23
+
24
+ it "nested key" do
25
+ expect(MiniI18n.t('second_level')).to be_a Hash
26
+ expect(MiniI18n.t('second_level.hello')).to eq 'hello 2'
27
+ end
28
+
29
+ it "locale" do
30
+ expect(MiniI18n.t('hello', locale: :fr)).to eq 'bonjour'
31
+ expect(MiniI18n.t('hello', locale: :es)).to eq 'hola'
32
+ end
33
+
34
+ it "scope" do
35
+ expect(MiniI18n.t('hello', scope: :second_level)).to eq 'hello 2'
36
+ end
37
+
38
+ it "returns nil if key does not exist" do
39
+ expect(MiniI18n.t('foo')).to eq nil
40
+ end
41
+
42
+ it "returns default if key does not exist" do
43
+ expect(MiniI18n.t('foo', default: 'bar')).to eq 'bar'
44
+ end
45
+
46
+ it "with interpolation" do
47
+ expect(MiniI18n.t('hello_interpolation')).to eq 'hello %{name}'
48
+ expect(MiniI18n.t('hello_interpolation', name: 'world')).to eq 'hello world'
49
+ end
50
+
51
+ it "fallbacks" do
52
+ expect(MiniI18n.t('fallback', locale: :es)).to eq ''
53
+
54
+ MiniI18n.fallbacks = true
55
+ expect(MiniI18n.t('fallback', locale: :es)).to eq 'fallback'
56
+ end
57
+ end
58
+
59
+ describe 'locale' do
60
+ it 'allows to change locale globally' do
61
+ MiniI18n.locale = :en
62
+ expect(MiniI18n.t(:hello)).to eq 'hello'
63
+
64
+ MiniI18n.locale = :es
65
+ expect(MiniI18n.t(:hello)).to eq 'hola'
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,6 @@
1
+ require "mini_i18n"
2
+
3
+ RSpec.configure do |config|
4
+ config.order = :rand
5
+ config.disable_monkey_patching!
6
+ end
metadata ADDED
@@ -0,0 +1,111 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mini_i18n
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - markets
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-07-17 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.16'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.16'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.7'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.7'
55
+ - !ruby/object:Gem::Dependency
56
+ name: byebug
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description:
70
+ email:
71
+ - srmarc.ai@gmail.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - lib/mini_i18n.rb
77
+ - lib/mini_i18n/utils.rb
78
+ - lib/mini_i18n/version.rb
79
+ - spec/fixtures/locales/en.yml
80
+ - spec/fixtures/locales/multiple.yml
81
+ - spec/mini_i18n_spec.rb
82
+ - spec/spec_helper.rb
83
+ homepage:
84
+ licenses:
85
+ - MIT
86
+ metadata: {}
87
+ post_install_message:
88
+ rdoc_options: []
89
+ require_paths:
90
+ - lib
91
+ required_ruby_version: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: '0'
96
+ required_rubygems_version: !ruby/object:Gem::Requirement
97
+ requirements:
98
+ - - ">="
99
+ - !ruby/object:Gem::Version
100
+ version: '0'
101
+ requirements: []
102
+ rubyforge_project:
103
+ rubygems_version: 2.6.13
104
+ signing_key:
105
+ specification_version: 4
106
+ summary: Minimalist I18n library
107
+ test_files:
108
+ - spec/fixtures/locales/en.yml
109
+ - spec/fixtures/locales/multiple.yml
110
+ - spec/mini_i18n_spec.rb
111
+ - spec/spec_helper.rb