i18n_multitenant 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: eb35d5985cf6d4869028f5370b636016011059be
4
+ data.tar.gz: b47174e2024be883a1a0b25a63c6678acb7af154
5
+ SHA512:
6
+ metadata.gz: 80ccc546b9f990086bbabcf9213d0ec2d0a47afed41f7092b4a8572e44a889658a7cc31f2a6d1cdcca9e6b27e6119f1cc63053b2547b3b8e6e5dcacf684054e3
7
+ data.tar.gz: 849ea28b7d3fb78006cddbff7e4f6f53aeb1da8f5d551dc1f2c925d7f03c4f7598fc930011132c1473897b79170a62a68a7506221641313531668f09ca23d9b8
@@ -0,0 +1,3 @@
1
+ ## I18nMultitenant 1.0.0 (2017-01-11) ##
2
+
3
+ * Initial Version.
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2017 Máximo Mussini
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,99 @@
1
+ # I18nMultitenant
2
+
3
+ This gem extend the standard i18n backend (I18n::Backend::Simple) to introduce {Conventions over configuration}[http://en.wikipedia.org/wiki/Convention_over_configuration] about 2 new types of locale files.
4
+
5
+ WARNING: Have to rethink parts of the implementation which seem to reimplement I18n::Backend::Fallbacks without this nice to have convention over configuration "algorithm".
6
+
7
+ So you can also write this with a little help of i18n's basic fallback module (at bootstrap process):
8
+
9
+ ```ruby
10
+ I18n::Backend::Simple.send(:include, I18n::Backend::Fallbacks)
11
+
12
+ I18n.fallbacks[:es] = [:es]
13
+ I18n.fallbacks[:tenant_name_es] = [:tenant_name_es, :es]
14
+ ```
15
+
16
+ This gem will just save you these lines through a convenient convention over configuration "algorithm".
17
+
18
+ ## Conventions
19
+
20
+ ### *_formal.yml
21
+
22
+ Given you want to offer your users the option to be addressed formally or informally through a {session locale switch}[https://github.com/Applicat/i18n_multitenant#backend-locale-switch]:
23
+
24
+ Then this is a {DRY}[http://en.wikipedia.org/wiki/Don%27t_repeat_yourself] solution for the workaround about having duplication of de locales in the de_formal namespace even though informal & formal translation are the same.
25
+
26
+ This locale file will own all translations from its base *.yml and lets you override them through the same translation keys (except of the deviant locale namespaces de and de_formal at the beginning).
27
+
28
+ ### #{locales_path}/tenants/your_tenant_name/**/your_tenant_name.yml
29
+
30
+ Given you want to have tenant specific locales through a {session locale switch}[https://github.com/Applicat/i18n_multitenant#backend-locale-switch]:
31
+
32
+ <b>Precondition:</b> Assure that you recursively add locale files to i18n's locale path e.g. through your Rails 3 application.rb:
33
+
34
+ config.i18n.load_path +# Dir[Rails.root.join('config', 'locales', '**', '*.{rb,yml}').to_s]
35
+
36
+ You may like to enable multi tenancy for your rails application by deploying the repository branch on multiple servers each with a different tenant-specific application constants file to load by a config system like {rails_config}[https://github.com/railsjedi/rails_config] at initialization.
37
+
38
+ This locale file owns all translations from its base *.yml and optional *_formal.yml under #{locales_path}/tenants/your-tenant-name/ (recurively) and lets you override them through the same translation keys (except of the deviant locale namespaces de and de_formal at the beginning).
39
+
40
+ ## Installation
41
+
42
+ Add this to your Gemfile and run the +bundle+ command.
43
+
44
+ gem "i18n_multitenant"
45
+
46
+ The gem (# engine) will automatically set the backend for your Rails application.
47
+
48
+ OPTIONAL: you have to manually set the i18n backend for your non-rails Ruby application:
49
+
50
+ I18n.backend # I18nMultitenant::Backend.new
51
+
52
+ ## Backend Locale Switch
53
+
54
+ Available since version 0.0.3.
55
+
56
+ <b>Initializer</b>
57
+
58
+ To initialize the global default locale based on current configuration.
59
+
60
+ Put this file for instance under config/initializer/multi_tenancy.rb
61
+
62
+ I18n.locale # I18n.backend.available_locale(
63
+ formal: Settings.address_formally, tenant: Settings.tenant.name
64
+ )
65
+
66
+ Settings is a constant for your settings brought by most popular rack app config system: https://github.com/railsjedi/rails_config
67
+
68
+ I18n.locale # I18n.backend.available_locale(formal: Settings.formal, tenant: Settings.tenant.name)
69
+
70
+ <b>Controller</b>
71
+
72
+ Dependency: https://github.com/iain/http_accept_language
73
+
74
+ class ApplicationController
75
+ AVAILABLE_LOCALES # %w{de en}
76
+
77
+ before_filter :set_locale
78
+
79
+ private
80
+
81
+ def set_locale
82
+ if user_signed_in?
83
+ # use of devise helper methods: user_signed_in?, current_user
84
+ I18n.locale # current_user.language # you have to add a language string column to your schema
85
+ else
86
+ locale # request.preferred_language_from AVAILABLE_LOCALES
87
+ locale ||# request.compatible_language_from AVAILABLE_LOCALES
88
+ locale ||# I18n.default_locale
89
+
90
+ unless Settings.tenant.name ## 'global'
91
+ locale # ("#{Settings.tenant.name.downcase.strip.tr(' ', '_')}_#{locale}").to_sym
92
+ end
93
+ end
94
+
95
+ I18n.locale # I18n.backend.available_locale(
96
+ base_locale: locale, formal: Settings.formal_address, tenant: Settings.tenant.name
97
+ )
98
+ end
99
+ end
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env rake
2
+ require 'rspec/core/rake_task'
3
+
4
+ $LOAD_PATH.unshift File.expand_path('../lib', __FILE__)
5
+ require 'i18n_multitenant/version'
6
+
7
+ name = 'i18n_multitenant'
8
+ version = I18nMultitenant::VERSION
9
+
10
+ task :gem => :build
11
+ task :build do
12
+ system "gem build #{name}.gemspec"
13
+ end
14
+
15
+ task :install => :build do
16
+ system "sudo gem install #{name}-#{version}.gem"
17
+ end
18
+
19
+ task :release => :build do
20
+ system "git tag -a v#{version} -m 'Tagging #{version}'"
21
+ system 'git push --tags'
22
+ system "gem push #{name}-#{version}.gem"
23
+ system "rm #{name}-#{version}.gem"
24
+ end
25
+
26
+ RSpec::Core::RakeTask.new(:spec)
27
+ task :default => :spec
@@ -0,0 +1,3 @@
1
+ require 'i18n_multitenant/version'
2
+ require 'i18n_multitenant/backend'
3
+ require 'i18n_multitenant/railtie' if defined?(Rails::Railtie)
@@ -0,0 +1,134 @@
1
+ require 'i18n'
2
+
3
+ class I18nMultitenant::Backend < I18n::Backend::Simple
4
+ FORMAL_FILENAME_PATTERN = /_formal\.[a-zA-Z]+$/
5
+ FORMAL_LOCALE_PATTERN = /_formal$/
6
+
7
+ TENANT_FILENAME_PATTERN = /tenants/
8
+ TENANT_LOCALE_PATTERN = /tenants$/
9
+
10
+ attr_accessor :filenames
11
+
12
+ # Accepts a list of paths to translation files. Loads translations from
13
+ # plain Ruby (*.rb) or YAML files (*.yml). See #load_rb and #load_yml
14
+ # for details.
15
+ def load_translations(*filenames)
16
+ filenames = I18n.load_path if filenames.empty?
17
+
18
+ @filenames = filenames.flatten
19
+
20
+ @filenames.each { |filename| load_file(filename) }
21
+ end
22
+
23
+ def available_locale(options = {})
24
+ options.assert_valid_keys(:base_locale, :formal, :tenant) if options.respond_to? :assert_valid_keys
25
+
26
+ base_locale = options[:base_locale] || I18n.default_locale
27
+ formal = options[:formal] || false
28
+ tenant = (options[:tenant] || '').downcase.strip.tr(' ', '_')
29
+
30
+ deepest_available_locale = nil
31
+
32
+ # take last / deepest available locale of possible combinations
33
+ variant_index = -1
34
+
35
+ [
36
+ [
37
+ (formal && tenant),
38
+ [tenant, base_locale, 'formal']
39
+ ],
40
+ [
41
+ formal && tenant && available_locales.include?([tenant, base_locale].join('_').to_sym) &&
42
+ available_locales.include?([base_locale, 'formal'].join('_').to_sym),
43
+ [tenant, base_locale, 'formal']
44
+ ],
45
+ [tenant, [tenant, base_locale]],
46
+ [formal, [base_locale, 'formal']],
47
+ [true, [base_locale]],
48
+ ].each do |variant|
49
+ variant_index += 1
50
+
51
+ next unless variant[0]
52
+
53
+ if available_locales.include?(variant[1].join('_').to_sym) || (variant_index == 1 && [tenant, base_locale, 'formal'] == variant[1])
54
+ deepest_available_locale = variant[1].join('_').to_sym
55
+ end
56
+
57
+ break if deepest_available_locale
58
+ end
59
+
60
+ deepest_available_locale || I18n.default_locale
61
+ end
62
+
63
+ protected
64
+
65
+ # Looks up a translation from the translations hash. Returns nil if
66
+ # eiher key is nil, or locale, scope or key do not exist as a key in the
67
+ # nested translations hash. Splits keys or scopes containing dots
68
+ # into multiple keys, i.e. <tt>currency.format</tt> is regarded the same as
69
+ # <tt>%w(currency format)</tt>.
70
+ def lookup(locale, key, scope = [], options = {})
71
+ init_translations unless initialized?
72
+
73
+ # only formal address: [:de, :de_formal]
74
+ # only multi tenancy: [:de, :tenant_name_de]
75
+ # formal address & multi tenancy: [:de, :tenant_name_de, :de_formal, :tenant_name_de_formal]
76
+
77
+ locales = []
78
+
79
+ base_locale = locale.to_s.gsub(FORMAL_LOCALE_PATTERN, '')
80
+
81
+ tenant = tenant_from_locale?(locale)
82
+ base_locale.gsub!(/^#{tenant}_/, '') if tenant
83
+
84
+ locales << base_locale.to_sym
85
+
86
+ if locale.to_s.match(FORMAL_LOCALE_PATTERN) && tenant && locale.to_s.match(/^#{tenant}_/)
87
+ locales << locale.to_s.gsub(FORMAL_LOCALE_PATTERN, '').to_sym
88
+ locales << locale.to_s.gsub(/^#{tenant}_/, '').to_sym
89
+ end
90
+
91
+ locales << locale unless locales.include?(locale)
92
+
93
+ entry, last_entry = nil, nil
94
+
95
+ locales.each do |locale|
96
+ keys = I18n.normalize_keys(locale, key, scope, options[:separator])
97
+
98
+ entry = keys.inject(translations) do |result, _key|
99
+ _key = _key.to_sym
100
+
101
+ unless result.is_a?(Hash) && result.has_key?(_key)
102
+ nil
103
+ else
104
+ result = result[_key]
105
+ result = resolve(locale, _key, result, options.merge(:scope => nil)) if result.is_a?(Symbol)
106
+ result
107
+ end
108
+ end
109
+
110
+ if entry.nil?
111
+ entry = last_entry
112
+ else
113
+ last_entry = entry
114
+ end
115
+ end
116
+
117
+ entry
118
+ end
119
+
120
+ private
121
+
122
+ def tenant_from_locale?(locale)
123
+ tenant = locale.to_s.gsub(FORMAL_LOCALE_PATTERN, '').split('_')
124
+
125
+ if tenant.length > 2
126
+ tenant.pop # pop languages like de
127
+ tenant = tenant.join('_')
128
+ else
129
+ tenant = nil
130
+ end
131
+
132
+ tenant && @filenames.select{|f| f.match("/tenants/#{tenant}/")}.any? ? tenant : nil
133
+ end
134
+ end
@@ -0,0 +1,6 @@
1
+ class I18nMultitenant::Railtie < ::Rails::Railtie
2
+ config.before_initialize do |app|
3
+ I18n.config.enforce_available_locales = false
4
+ I18n.backend = I18nMultitenant::Backend.new
5
+ end
6
+ end
@@ -0,0 +1,3 @@
1
+ module I18nMultitenant
2
+ VERSION = '0.0.0'
3
+ end
@@ -0,0 +1,4 @@
1
+ de:
2
+ formal_available: 'Du'
3
+ formal_unavailable: 'Du'
4
+ de_formal_formal_available: 'Du'
@@ -0,0 +1,3 @@
1
+ de_formal:
2
+ formal_available: 'Sie'
3
+ de_formal_formal_available: 'Sie'
@@ -0,0 +1,4 @@
1
+ de:
2
+ devise:
3
+ example: 'Dein Beispiel'
4
+ informal_example: 'Dein anderes Beispiel'
@@ -0,0 +1,4 @@
1
+ de_formal:
2
+ devise:
3
+ example: Ihr Beispiel
4
+ examples: Ihre Beispiele
@@ -0,0 +1,2 @@
1
+ en:
2
+ example: 'Dummy'
@@ -0,0 +1,2 @@
1
+ another_tenant_name_fr_formal:
2
+ formal_available: 'jamais vous'
@@ -0,0 +1,3 @@
1
+ your_tenant_name_de_formal:
2
+ devise:
3
+ example: Ihr formelles Beispiel
@@ -0,0 +1,3 @@
1
+ your_tenant_name_de:
2
+ formal_available: 'Du auch'
3
+ formal_unavailable_again: 'Du auch wieder'
@@ -0,0 +1,2 @@
1
+ your_tenant_name_de_formal:
2
+ formal_available: 'Sie auch'
@@ -0,0 +1,2 @@
1
+ your_tenant_name_en:
2
+ example: 'Dummy change'
@@ -0,0 +1,204 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe I18nMultitenant::Backend do
4
+ before :all do
5
+ I18n.config.enforce_available_locales = false
6
+ I18n.default_locale = :de
7
+ I18n.locale = I18n.default_locale
8
+ end
9
+
10
+ describe '#lookup' do
11
+ include_context :all_locale_file_constellations
12
+
13
+ before :all do
14
+ I18n.backend = I18nMultitenant::Backend.new
15
+ end
16
+
17
+ context 'default' do
18
+ context 'formal translation available' do
19
+ context 'returns the translation' do
20
+ Given { I18n.locale = :de }
21
+ Then { I18n.t('formal_available') == 'Du' }
22
+ Then { I18n.t('de_formal_formal_available') == 'Du' }
23
+ end
24
+
25
+ context 'returns the formal translation' do
26
+ Given { I18n.locale = :de_formal }
27
+ Then { I18n.t('formal_available') == 'Sie' }
28
+ Then { I18n.t('de_formal_formal_available') == 'Sie' }
29
+ end
30
+ end
31
+
32
+ context 'formal translation unavailable' do
33
+ context 'inerits the informal locales from :de' do
34
+ Given { I18n.locale = :de_formal }
35
+ Then { I18n.t('formal_unavailable') == 'Du' }
36
+ end
37
+ end
38
+ end
39
+
40
+ context 'tenant-specific' do
41
+ context 'formal translation available' do
42
+ context 'returns the translation' do
43
+ Given { I18n.locale = :your_tenant_name_de }
44
+ Then { I18n.t('formal_available') == 'Du auch' }
45
+ Then { I18n.t('de_formal_formal_available') == 'Du' }
46
+ end
47
+
48
+ context 'returns the formal translation' do
49
+ Given { I18n.locale = :your_tenant_name_de_formal }
50
+ Then { I18n.t('formal_available') == 'Sie auch' }
51
+ Then { I18n.t('de_formal_formal_available') == 'Sie' }
52
+ end
53
+ end
54
+
55
+ context 'formal translation unavailable' do
56
+ context 'inerits the informal locales from :de and :your_tenant_name_de' do
57
+ Given { I18n.locale = :your_tenant_name_de_formal }
58
+ Then { I18n.t('formal_unavailable') == 'Du' }
59
+ Then { I18n.t('formal_unavailable_again') == 'Du auch wieder' }
60
+ end
61
+ end
62
+
63
+ context 'formal translation available for locale without base locale' do
64
+ context 'inits the locale without inheritation of unavailable base locale' do
65
+ Given { I18n.locale = :another_tenant_name_fr_formal }
66
+ Then { I18n.t('formal_available') == 'jamais vous' }
67
+ end
68
+ end
69
+ end
70
+
71
+ context 'locale files with more than 1 dot' do
72
+ context 'principally works' do
73
+ Given { I18n.locale = :de }
74
+ Then { I18n.t('devise.example') == 'Dein Beispiel' }
75
+ end
76
+
77
+ context 'principally works' do
78
+ Given { I18n.locale = :de_formal }
79
+ Then { I18n.t('devise.example') == 'Ihr Beispiel' }
80
+ end
81
+
82
+ context 'principally works tenant' do
83
+ Given { I18n.locale = :your_tenant_name_de_formal }
84
+ Then { I18n.t('devise.informal_example') == 'Dein anderes Beispiel' } # devise.de.yml
85
+ Then { I18n.t('devise.examples') == 'Ihre Beispiele' } # devise.de_formal.yml
86
+ Then { I18n.t('devise.example') == 'Ihr formelles Beispiel' } # tenants/your_tenant_name/devise.your_tenant_name_de_formal.yml
87
+ end
88
+ end
89
+ end
90
+
91
+ describe '.available_locale' do
92
+ context 'any locale' do
93
+ before :all do
94
+ I18n.load_path = [
95
+ File.expand_path('../../../fixtures/de.yml', __FILE__),
96
+ File.expand_path('../../../fixtures/en.yml', __FILE__)
97
+ ]
98
+ end
99
+
100
+ # .available_locale any locale principally works
101
+ it 'principally works' do
102
+ I18n.backend = I18nMultitenant::Backend.new
103
+
104
+ [
105
+ [{}, :de],
106
+ [{base_locale: :en}, :en],
107
+ [{base_locale: :unavailable}, :de],
108
+ [{tenant: 'Your Tenant Name'}, :de],
109
+ [{formal: true, tenant: 'Your Tenant Name'}, :de],
110
+ [{formal: true, tenant: 'Unavailable Tenant Name'}, :de]
111
+ ].each do |variant|
112
+ actual = I18n.backend.available_locale(variant.first)
113
+ expect(actual).to(
114
+ be(variant.last),
115
+ "input #{variant.first.inspect} should result in the output: #{variant.last.inspect} but got #{actual.inspect}"
116
+ )
117
+ end
118
+ end
119
+ end
120
+
121
+ context 'any formal locale' do
122
+ before :all do
123
+ I18n.load_path = [
124
+ File.expand_path('../../../fixtures/de.yml', __FILE__),
125
+ File.expand_path('../../../fixtures/de_formal.yml', __FILE__)
126
+ ]
127
+ end
128
+
129
+ it 'principally works' do
130
+ I18n.backend = I18nMultitenant::Backend.new
131
+
132
+ [
133
+ [{formal: true}, :de_formal],
134
+ [{formal: true, tenant: 'Your Tenant Name'}, :de_formal]
135
+ ].each do |variant|
136
+ actual = I18n.backend.available_locale(variant.first)
137
+ expect(actual).to(
138
+ be(variant.last),
139
+ "input #{variant.first.inspect} should result in the output: #{variant.last.inspect} but got #{actual.inspect}"
140
+ )
141
+ end
142
+ end
143
+ end
144
+
145
+ context 'any formal locale plus tenant specific locale' do
146
+ before :all do
147
+ I18n.load_path = [
148
+ File.expand_path('../../../fixtures/de.yml', __FILE__),
149
+ File.expand_path('../../../fixtures/de_formal.yml', __FILE__),
150
+ File.expand_path('../../../fixtures/tenants/your_tenant_name/your_tenant_name_de.yml', __FILE__),
151
+ File.expand_path('../../../fixtures/tenants/your_tenant_name/your_tenant_name_en.yml', __FILE__)
152
+ ]
153
+ end
154
+
155
+ it 'principally works' do
156
+ I18n.backend = I18nMultitenant::Backend.new
157
+
158
+ [
159
+ [{formal: true}, :de_formal],
160
+ # should be :your_tenant_name_de_formal even though there is no :your_tenant_name_de_formal file
161
+ # but the base file :de_formal to inherit from
162
+ [{formal: true, tenant: 'Your Tenant Name'}, :your_tenant_name_de_formal],
163
+ [{base_locale: :en, formal: true, tenant: 'Your Tenant Name'}, :your_tenant_name_en]
164
+ ].each do |variant|
165
+ actual = I18n.backend.available_locale(variant.first)
166
+ expect(actual).to(
167
+ be(variant.last),
168
+ "input #{variant.first.inspect} should result in the output: #{variant.last.inspect} but got #{actual.inspect}"
169
+ )
170
+ end
171
+ end
172
+ end
173
+
174
+ context 'any formal tenant-specific locale' do
175
+ include_context :all_locale_file_constellations
176
+
177
+ it 'principally works' do
178
+ I18n.backend = I18nMultitenant::Backend.new
179
+ end
180
+ end
181
+
182
+ context 'tenant has special locale without an equivalent base locale' do
183
+ before :all do
184
+ I18n.load_path = [
185
+ File.expand_path('../../../fixtures/tenants/your_tenant_name/your_tenant_name_de_formal.yml', __FILE__)
186
+ ]
187
+ end
188
+
189
+ it 'principally works' do
190
+ I18n.backend = I18nMultitenant::Backend.new
191
+
192
+ [
193
+ [{base_locale: :de, formal: true, tenant: 'Your Tenant Name'}, :your_tenant_name_de_formal]
194
+ ].each do |variant|
195
+ actual = I18n.backend.available_locale(variant.first)
196
+ expect(actual).to(
197
+ be(variant.last),
198
+ "input #{variant.first.inspect} should result in the output: #{variant.last.inspect} but got #{actual.inspect}"
199
+ )
200
+ end
201
+ end
202
+ end
203
+ end
204
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+ if ENV['CODECLIMATE_REPO_TOKEN']
3
+ require 'codeclimate-test-reporter'
4
+ CodeClimate::TestReporter.start
5
+ end
6
+
7
+ require 'rspec/given'
8
+ require 'pry'
9
+ require 'i18n_multitenant'
10
+
11
+ RSpec.configure do |config|
12
+ config.raise_errors_for_deprecations!
13
+ config.expose_dsl_globally = false
14
+ end
15
+
16
+ # Load Support files
17
+ Dir['./spec/support/**/*.rb'].each do |f|
18
+ require f
19
+ end
@@ -0,0 +1,14 @@
1
+ RSpec.shared_context :all_locale_file_constellations do
2
+ before :all do
3
+ I18n.load_path = [
4
+ File.expand_path('../../../fixtures/de.yml', __FILE__),
5
+ File.expand_path('../../../fixtures/de_formal.yml', __FILE__),
6
+ File.expand_path('../../../fixtures/tenants/your_tenant_name/your_tenant_name_de.yml', __FILE__),
7
+ File.expand_path('../../../fixtures/tenants/your_tenant_name/your_tenant_name_de_formal.yml', __FILE__),
8
+ File.expand_path('../../../fixtures/tenants/another_tenant_name/another_tenant_name_fr_formal.yml', __FILE__),
9
+ File.expand_path('../../../fixtures/devise.de.yml', __FILE__),
10
+ File.expand_path('../../../fixtures/devise.de_formal.yml', __FILE__),
11
+ File.expand_path('../../../fixtures/tenants/your_tenant_name/devise.your_tenant_name_de_formal.yml', __FILE__),
12
+ ]
13
+ end
14
+ end
metadata ADDED
@@ -0,0 +1,94 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: i18n_multitenant
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Máximo Mussini
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-01-11 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: i18n
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ description: I18nMultitenant allows you to specify translations that are tenant-specific,
28
+ falling back to the base locale.
29
+ email:
30
+ - maximomussini@gmail.com
31
+ executables: []
32
+ extensions: []
33
+ extra_rdoc_files: []
34
+ files:
35
+ - CHANGELOG.md
36
+ - LICENSE.txt
37
+ - README.md
38
+ - Rakefile
39
+ - lib/i18n_multitenant.rb
40
+ - lib/i18n_multitenant/backend.rb
41
+ - lib/i18n_multitenant/railtie.rb
42
+ - lib/i18n_multitenant/version.rb
43
+ - spec/fixtures/de.yml
44
+ - spec/fixtures/de_formal.yml
45
+ - spec/fixtures/devise.de.yml
46
+ - spec/fixtures/devise.de_formal.yml
47
+ - spec/fixtures/en.yml
48
+ - spec/fixtures/tenants/another_tenant_name/another_tenant_name_fr_formal.yml
49
+ - spec/fixtures/tenants/your_tenant_name/devise.your_tenant_name_de_formal.yml
50
+ - spec/fixtures/tenants/your_tenant_name/your_tenant_name_de.yml
51
+ - spec/fixtures/tenants/your_tenant_name/your_tenant_name_de_formal.yml
52
+ - spec/fixtures/tenants/your_tenant_name/your_tenant_name_en.yml
53
+ - spec/lib/i18n_multitenant/backend_spec.rb
54
+ - spec/spec_helper.rb
55
+ - spec/support/shared_contexts/all_locale_file_constellations.rb
56
+ homepage: https://github.com/ElMassimo/i18n_multitenant
57
+ licenses:
58
+ - MIT
59
+ metadata: {}
60
+ post_install_message:
61
+ rdoc_options:
62
+ - "--charset=UTF-8"
63
+ require_paths:
64
+ - lib
65
+ required_ruby_version: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: 2.0.0
70
+ required_rubygems_version: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ requirements: []
76
+ rubyforge_project:
77
+ rubygems_version: 2.5.1
78
+ signing_key:
79
+ specification_version: 4
80
+ summary: Translation for multi-tenant applications.
81
+ test_files:
82
+ - spec/fixtures/de.yml
83
+ - spec/fixtures/de_formal.yml
84
+ - spec/fixtures/devise.de.yml
85
+ - spec/fixtures/devise.de_formal.yml
86
+ - spec/fixtures/en.yml
87
+ - spec/fixtures/tenants/another_tenant_name/another_tenant_name_fr_formal.yml
88
+ - spec/fixtures/tenants/your_tenant_name/devise.your_tenant_name_de_formal.yml
89
+ - spec/fixtures/tenants/your_tenant_name/your_tenant_name_de.yml
90
+ - spec/fixtures/tenants/your_tenant_name/your_tenant_name_de_formal.yml
91
+ - spec/fixtures/tenants/your_tenant_name/your_tenant_name_en.yml
92
+ - spec/lib/i18n_multitenant/backend_spec.rb
93
+ - spec/spec_helper.rb
94
+ - spec/support/shared_contexts/all_locale_file_constellations.rb