mini_i18n 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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