i18n-tasks 0.3.6 → 0.3.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGES.md +5 -0
- data/README.md +13 -8
- data/bin/i18n-tasks +13 -9
- data/i18n-tasks.gemspec +2 -7
- data/lib/i18n/tasks.rb +1 -12
- data/lib/i18n/tasks/base_task.rb +6 -9
- data/lib/i18n/tasks/commands.rb +14 -15
- data/lib/i18n/tasks/commands_base.rb +2 -2
- data/lib/i18n/tasks/configuration.rb +20 -7
- data/lib/i18n/tasks/data.rb +78 -0
- data/lib/i18n/tasks/data/file_formats.rb +41 -0
- data/lib/i18n/tasks/data/file_system.rb +2 -3
- data/lib/i18n/tasks/data/file_system_base.rb +90 -0
- data/lib/i18n/tasks/data/locale_tree.rb +85 -0
- data/lib/i18n/tasks/data/router.rb +47 -0
- data/lib/i18n/tasks/key.rb +3 -0
- data/lib/i18n/tasks/key_group.rb +1 -0
- data/lib/i18n/tasks/logging.rb +4 -0
- data/lib/i18n/tasks/missing_keys.rb +18 -14
- data/lib/i18n/tasks/reports/terminal.rb +1 -1
- data/lib/i18n/tasks/scanners/base_scanner.rb +38 -36
- data/lib/i18n/tasks/scanners/pattern_scanner.rb +2 -2
- data/lib/i18n/tasks/unused_keys.rb +11 -8
- data/lib/i18n/tasks/used_keys.rb +15 -6
- data/lib/i18n/tasks/version.rb +1 -1
- data/spec/file_system_data_spec.rb +2 -2
- data/spec/google_translate_spec.rb +1 -1
- data/spec/pattern_scanner_spec.rb +2 -2
- data/spec/relative_keys_spec.rb +3 -3
- data/spec/used_keys_spec.rb +4 -6
- metadata +39 -42
- data/lib/i18n/tasks/data/storage/file_storage.rb +0 -127
- data/lib/i18n/tasks/data_traversal.rb +0 -51
- data/lib/i18n/tasks/translation_data.rb +0 -60
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f92285f463714c33d1c83515dcd2aaf6767e4663
|
4
|
+
data.tar.gz: b82019313500a6dc1a2122b56d0bc118086071a3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1cd49cb9ec3101e8ef38c75f5cace26f4dcf2afc613a89b15ea9741ec0ab420203d04039aefe79a5996cdef5736f2eb74b2503e076e2fd29cd7e05c6fda5258a
|
7
|
+
data.tar.gz: 4fec3b2eb4ad06d80429b653ede00d06522f4710ebdcdb21341d5723d2b696812086caeab0415abc8965878fd0d1d058f3346da293725b535c2a7900da36d9ec
|
data/CHANGES.md
CHANGED
data/README.md
CHANGED
@@ -2,13 +2,14 @@
|
|
2
2
|
|
3
3
|
i18n-tasks finds and manages missing and unused translations in your application.
|
4
4
|
|
5
|
-
The
|
5
|
+
The default approach to locale data management with gems such as [i18n][i18n-gem] is flawed.
|
6
6
|
If you use a key that does not exist, this will only blow up at runtime. Keys left over from removed code accumulate
|
7
|
-
in the resource files
|
7
|
+
in the resource files and introduce unnecessary overhead on the translators. Translation files can quickly turn to disarray.
|
8
8
|
|
9
|
-
i18n-tasks improves this by using static analysis. It scans calls such as `I18n.t('some.key')` and
|
10
|
-
|
11
|
-
|
9
|
+
i18n-tasks improves this by using static analysis. It scans calls such as `I18n.t('some.key')` and provides reports on key usage, missing, and unused keys.
|
10
|
+
It can also can pre-fill missing keys, including from Google Translate, and it can remove unused keys as well.
|
11
|
+
|
12
|
+
i18n-tasks can be used with any project using [i18n][i18n-gem] (default in Rails), or similar, even if it isn't ruby.
|
12
13
|
|
13
14
|
<img width="534" height="288" src="https://raw.github.com/glebm/i18n-tasks/master/doc/img/i18n-tasks.png">
|
14
15
|
|
@@ -16,9 +17,12 @@ and can also remove unused keys.
|
|
16
17
|
|
17
18
|
Add to Gemfile:
|
18
19
|
|
19
|
-
|
20
|
-
|
21
|
-
|
20
|
+
```ruby
|
21
|
+
gem 'i18n-tasks', '~> 0.3.7'
|
22
|
+
```
|
23
|
+
|
24
|
+
i18n-tasks does not load or execute any of the application's code but performs static-only analysic.
|
25
|
+
This means you can install the gem and run it on a project without adding it to Gemfile.
|
22
26
|
|
23
27
|
## Usage
|
24
28
|
|
@@ -295,4 +299,5 @@ This was originally developed for [Zuigo](http://zuigo.com/), a platform to orga
|
|
295
299
|
[badge-code-climate]: https://codeclimate.com/github/glebm/i18n-tasks.png
|
296
300
|
[badge-flattr]: https://api.flattr.com/button/flattr-badge-large.png
|
297
301
|
[flattr]: https://flattr.com/submit/auto?user_id=glebm&url=https%3A%2F%2Fgithub.com%2Fglebm%2Fi18n-tasks
|
302
|
+
[i18n-gem]: https://github.com/svenfuchs/i18n "svenfuchs/i18n on Github"
|
298
303
|
[screenshot-find]: https://raw.github.com/glebm/i18n-tasks/master/doc/img/i18n-usages.png "i18n-tasks find output screenshot"
|
data/bin/i18n-tasks
CHANGED
@@ -24,16 +24,20 @@ end
|
|
24
24
|
if command
|
25
25
|
cmd = ::I18n::Tasks::Commands.new
|
26
26
|
meth = command[0]
|
27
|
-
opts = command[1].to_hash.reject{ |k, v| v.nil? }
|
27
|
+
opts = command[1].to_hash.reject { |k, v| v.nil? }
|
28
28
|
args = command[2]
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
29
|
+
begin
|
30
|
+
if opts.empty? && args.empty?
|
31
|
+
cmd.log_verbose "run #{meth.tr('_', '-')} without arguments"
|
32
|
+
cmd.send meth
|
33
|
+
else
|
34
|
+
opts = opts.merge(arguments: args) unless args.empty?
|
35
|
+
cmd.log_verbose "run #{meth.tr('_', '-')} with #{opts.map { |k, v| "#{k}=#{v}" } * ' '}"
|
36
|
+
cmd.send meth, opts
|
37
|
+
end
|
38
|
+
rescue Errno::EPIPE
|
39
|
+
# ignore Errno::EPIPE which is throw when pipe breaks, e.g.:
|
40
|
+
# i18n-tasks missing | head
|
37
41
|
end
|
38
42
|
else
|
39
43
|
STDERR.puts Term::ANSIColor.red "Command unknown: #{ARGV[0]}" if ARGV[0]
|
data/i18n-tasks.gemspec
CHANGED
@@ -12,13 +12,8 @@ Gem::Specification.new do |s|
|
|
12
12
|
s.description = %q{
|
13
13
|
i18n-tasks finds and manages missing and unused translations in your application.
|
14
14
|
|
15
|
-
|
16
|
-
|
17
|
-
in the resource files, introducing unnecessary overhead on the translators. Translation files can quickly turn to disarray.
|
18
|
-
|
19
|
-
i18n-tasks improves this by using static analysis. It scans calls such as `I18n.t('some.key')` and uses this information to
|
20
|
-
provide reports on key usage, missing and unused keys, and can prefill missing keys, including from Google Translate,
|
21
|
-
and can also remove unused keys.
|
15
|
+
It scans calls such as `I18n.t('some.key')` and provides reports on key usage, missing, and unused keys.
|
16
|
+
It can also can pre-fill missing keys, including from Google Translate, and it can remove unused keys as well.
|
22
17
|
}
|
23
18
|
s.homepage = 'https://github.com/glebm/i18n-tasks'
|
24
19
|
if s.respond_to?(:metadata=)
|
data/lib/i18n/tasks.rb
CHANGED
@@ -13,17 +13,6 @@ require 'i18n/tasks/base_task'
|
|
13
13
|
|
14
14
|
module I18n
|
15
15
|
module Tasks
|
16
|
-
|
17
|
-
config/i18n-tasks.yml config/i18n-tasks.yml.erb
|
18
|
-
i18n-tasks.yml i18n-tasks.yml.erb
|
19
|
-
)
|
20
|
-
class << self
|
21
|
-
def config
|
22
|
-
file = CONFIG_FILES.detect { |f| File.exists?(f) }
|
23
|
-
file = YAML.load(Erubis::Eruby.new(File.read(file)).result) if file
|
24
|
-
HashWithIndifferentAccess.new.merge(file.presence || {})
|
25
|
-
end
|
26
|
-
include ::I18n::Tasks::Logging
|
27
|
-
end
|
16
|
+
|
28
17
|
end
|
29
18
|
end
|
data/lib/i18n/tasks/base_task.rb
CHANGED
@@ -1,33 +1,30 @@
|
|
1
1
|
# coding: utf-8
|
2
|
-
require 'i18n/tasks/configuration'
|
3
2
|
require 'i18n/tasks/key_pattern_matching'
|
4
|
-
require 'i18n/tasks/
|
3
|
+
require 'i18n/tasks/logging'
|
5
4
|
require 'i18n/tasks/plural_keys'
|
6
5
|
require 'i18n/tasks/used_keys'
|
7
|
-
require 'i18n/tasks/translation_data'
|
8
6
|
require 'i18n/tasks/ignore_keys'
|
9
7
|
require 'i18n/tasks/missing_keys'
|
10
8
|
require 'i18n/tasks/unused_keys'
|
11
9
|
require 'i18n/tasks/google_translation'
|
12
10
|
require 'i18n/tasks/fill_tasks'
|
13
|
-
require 'i18n/tasks/
|
11
|
+
require 'i18n/tasks/data'
|
12
|
+
require 'i18n/tasks/configuration'
|
14
13
|
|
15
14
|
module I18n
|
16
15
|
module Tasks
|
17
16
|
class BaseTask
|
18
|
-
include Configuration
|
19
17
|
include KeyPatternMatching
|
20
|
-
include IgnoreKeys
|
21
|
-
include DataTraversal
|
22
|
-
include RelativeKeys
|
23
18
|
include PluralKeys
|
24
19
|
include UsedKeys
|
20
|
+
include IgnoreKeys
|
25
21
|
include MissingKeys
|
26
22
|
include UnusedKeys
|
27
|
-
include TranslationData
|
28
23
|
include FillTasks
|
29
24
|
include GoogleTranslation
|
30
25
|
include Logging
|
26
|
+
include Configuration
|
27
|
+
include Data
|
31
28
|
|
32
29
|
def initialize(config = {})
|
33
30
|
self.config = config || {}
|
data/lib/i18n/tasks/commands.rb
CHANGED
@@ -14,7 +14,7 @@ module I18n::Tasks
|
|
14
14
|
on '-t', :types, 'Filter by type (types: missing_from_base, eq_base, missing_from_locale)', as: Array, delimiter: /[+:,]/, argument: true, optional: false
|
15
15
|
end
|
16
16
|
cmd :missing do |opt = {}|
|
17
|
-
|
17
|
+
parse_locales! opt
|
18
18
|
terminal_report.missing_keys i18n_task.missing_keys(opt)
|
19
19
|
end
|
20
20
|
|
@@ -30,7 +30,7 @@ module I18n::Tasks
|
|
30
30
|
end
|
31
31
|
cmd :translate_missing do |opt = {}|
|
32
32
|
opt[:from] = base_locale if opt[:from].blank? || opt[:from] == 'base'
|
33
|
-
|
33
|
+
parse_locales! opt
|
34
34
|
i18n_task.fill_missing_google_translate opt
|
35
35
|
end
|
36
36
|
|
@@ -40,9 +40,8 @@ module I18n::Tasks
|
|
40
40
|
on '-p', :placeholder, 'Value for empty keys (default: base value or key.humanize)', argument: true, optional: false
|
41
41
|
end
|
42
42
|
cmd :add_missing do |opt = {}|
|
43
|
-
|
44
|
-
opt[:value] ||= opt.delete(:placeholder)
|
45
|
-
opt[:value] ||= proc { |key, locale|
|
43
|
+
parse_locales! opt
|
44
|
+
opt[:value] ||= opt.delete(:placeholder) || proc { |key, locale|
|
46
45
|
# default to base value or key.humanize
|
47
46
|
locale == base_locale && t(locale, base_locale) || key.split('.').last.to_s.humanize
|
48
47
|
}
|
@@ -55,11 +54,7 @@ module I18n::Tasks
|
|
55
54
|
end
|
56
55
|
cmd :find do |opt = {}|
|
57
56
|
opt[:filter] ||= opt.delete(:pattern) || opt[:arguments].try(:first)
|
58
|
-
|
59
|
-
used_keys = i18n_task.scanner.with_key_filter(filter) {
|
60
|
-
i18n_task.used_keys true
|
61
|
-
}
|
62
|
-
terminal_report.used_keys used_keys
|
57
|
+
terminal_report.used_keys i18n_task.used_keys(key_filter: opt[:filter].presence, src_locations: true)
|
63
58
|
end
|
64
59
|
|
65
60
|
desc 'normalize translation data: sort and move to the right files'
|
@@ -67,7 +62,8 @@ module I18n::Tasks
|
|
67
62
|
on '-l', :locales=, 'Locales to normalize (default: all)', on_locale_opt
|
68
63
|
end
|
69
64
|
cmd :normalize do |opt = {}|
|
70
|
-
|
65
|
+
parse_locales! opt
|
66
|
+
i18n_task.normalize_store! opt[:locales]
|
71
67
|
end
|
72
68
|
|
73
69
|
desc 'remove unused keys'
|
@@ -75,14 +71,14 @@ module I18n::Tasks
|
|
75
71
|
on '-l', :locales=, 'Locales to remove unused keys from (default: all)', on_locale_opt
|
76
72
|
end
|
77
73
|
cmd :remove_unused do |opt = {}|
|
78
|
-
|
74
|
+
parse_locales!(opt)
|
79
75
|
unused_keys = i18n_task.unused_keys
|
80
76
|
if unused_keys.present?
|
81
77
|
terminal_report.unused_keys(unused_keys)
|
82
78
|
unless ENV['CONFIRM']
|
83
|
-
exit 1 unless agree(red "All these translations will be removed in #{bold locales * ', '}#{red '.'} " + yellow('Continue? (yes/no)') + ' ')
|
79
|
+
exit 1 unless agree(red "All these translations will be removed in #{bold opt[:locales] * ', '}#{red '.'} " + yellow('Continue? (yes/no)') + ' ')
|
84
80
|
end
|
85
|
-
i18n_task.remove_unused!(locales)
|
81
|
+
i18n_task.remove_unused!(opt[:locales])
|
86
82
|
$stderr.puts "Removed #{unused_keys.size} keys"
|
87
83
|
else
|
88
84
|
$stderr.puts bold green 'No unused keys to remove'
|
@@ -91,7 +87,10 @@ module I18n::Tasks
|
|
91
87
|
|
92
88
|
desc 'display i18n-tasks configuration'
|
93
89
|
cmd :config do
|
94
|
-
|
90
|
+
cfg = i18n_task.config_for_inspect.to_yaml
|
91
|
+
cfg.sub! /\A---\n/, ''
|
92
|
+
cfg.gsub! /^([^\s-].+?)$/, Term::ANSIColor.cyan(Term::ANSIColor.bold('\1'))
|
93
|
+
puts cfg
|
95
94
|
end
|
96
95
|
|
97
96
|
desc 'save missing and unused translations to an Excel file'
|
@@ -18,8 +18,8 @@ module I18n::Tasks
|
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
21
|
-
def
|
22
|
-
locales_opt(opt[:arguments].presence || opt[:locales]).tap do |locales|
|
21
|
+
def parse_locales!(opt)
|
22
|
+
opt[:locales] = locales_opt(opt[:arguments].presence || opt[:locales]).tap do |locales|
|
23
23
|
log_verbose "locales for the command are #{locales.inspect}"
|
24
24
|
end
|
25
25
|
end
|
@@ -5,8 +5,18 @@ module I18n::Tasks::Configuration
|
|
5
5
|
@config || (self.config = {})
|
6
6
|
end
|
7
7
|
|
8
|
+
CONFIG_FILES = %w(
|
9
|
+
config/i18n-tasks.yml config/i18n-tasks.yml.erb
|
10
|
+
i18n-tasks.yml i18n-tasks.yml.erb
|
11
|
+
)
|
12
|
+
def file_config
|
13
|
+
file = CONFIG_FILES.detect { |f| File.exists?(f) }
|
14
|
+
file = YAML.load(Erubis::Eruby.new(File.read(file)).result) if file
|
15
|
+
{}.with_indifferent_access.merge(file.presence || {})
|
16
|
+
end
|
17
|
+
|
8
18
|
def config=(conf)
|
9
|
-
@config =
|
19
|
+
@config = file_config.deep_merge(conf)
|
10
20
|
@config_sections = {}
|
11
21
|
@config
|
12
22
|
end
|
@@ -15,12 +25,10 @@ module I18n::Tasks::Configuration
|
|
15
25
|
# @return [{adapter: String, options: Hash}]
|
16
26
|
def data_config
|
17
27
|
@config_sections[:data] ||= begin
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
end
|
23
|
-
{adapter: adapter, options: conf.except(:adapter, :class)}
|
28
|
+
{
|
29
|
+
adapter: data.class.name,
|
30
|
+
config: data.config
|
31
|
+
}
|
24
32
|
end
|
25
33
|
end
|
26
34
|
|
@@ -65,6 +73,11 @@ module I18n::Tasks::Configuration
|
|
65
73
|
end
|
66
74
|
end
|
67
75
|
|
76
|
+
def non_base_locales(from = nil)
|
77
|
+
from ||= self.locales
|
78
|
+
Array(from) - [base_locale]
|
79
|
+
end
|
80
|
+
|
68
81
|
# @return [String] default i18n locale
|
69
82
|
def base_locale
|
70
83
|
@config_sections[:base_locale] ||= (config[:base_locale] || 'en').to_s
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'i18n/tasks/data/file_system'
|
2
|
+
|
3
|
+
module I18n::Tasks::Data
|
4
|
+
# I18n data provider
|
5
|
+
# @see I18n::Tasks::Data::FileSystem
|
6
|
+
def data
|
7
|
+
@data ||= begin
|
8
|
+
conf = (config[:data] || {}).with_indifferent_access
|
9
|
+
adapter = (conf[:adapter].presence || conf[:class].presence || :file_system).to_s
|
10
|
+
if adapter !~ /[A-Z]/
|
11
|
+
adapter = "I18n::Tasks::Data::#{adapter.camelize}"
|
12
|
+
end
|
13
|
+
adapter.constantize.new(conf.except(:adapter, :class))
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def t(key, locale = base_locale)
|
18
|
+
data.t(key, locale)
|
19
|
+
end
|
20
|
+
|
21
|
+
def t_proc(locale = base_locale)
|
22
|
+
@t_proc ||= {}
|
23
|
+
@t_proc[locale] ||= proc { |key| t(key, locale) }
|
24
|
+
end
|
25
|
+
|
26
|
+
# whether the value for key exists in locale (defaults: base_locale)
|
27
|
+
def key_value?(key, locale = base_locale)
|
28
|
+
t(key, locale).present?
|
29
|
+
end
|
30
|
+
|
31
|
+
# write to store, normalizing all data
|
32
|
+
def normalize_store!(from = nil)
|
33
|
+
from = self.locales unless from
|
34
|
+
Array(from).each do |target_locale|
|
35
|
+
# the store itself handles normalization
|
36
|
+
data[target_locale] = data[target_locale]
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# if :locales option present, call update_locale_data for each locale
|
41
|
+
# otherwise, call update_locale_data for :locale option or base locale
|
42
|
+
# @option opts [Array] :locales
|
43
|
+
# @option opts [String] :locale
|
44
|
+
def update_data(opts = {})
|
45
|
+
if opts.key?(:locales)
|
46
|
+
locales = (Array(opts[:locales]).presence || self.locales).map(&:to_s)
|
47
|
+
# make sure base_locale always comes first if present
|
48
|
+
locales = [base_locale] + (locales - [base_locale]) if locales.include?(base_locale)
|
49
|
+
opts = opts.except(:locales)
|
50
|
+
locales.each { |locale| update_locale_data(locale, opts.merge(locale: locale)) }
|
51
|
+
else
|
52
|
+
update_locale_data(opts[:locale] || base_locale, opts)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# @param locale
|
57
|
+
# @option opts [Array|Proc] :keys keys to update, if proc call with locale
|
58
|
+
# @option opts [String|Proc] value, if proc call with each key
|
59
|
+
# @option opts [String|Proc] values, if proc call with all the keys
|
60
|
+
def update_locale_data(locale, opts = {})
|
61
|
+
keys = opts[:keys]
|
62
|
+
keys = keys.call(locale) if keys.respond_to?(:call)
|
63
|
+
return if keys.empty?
|
64
|
+
|
65
|
+
values = opts[:values]
|
66
|
+
values = values.call(keys, locale) if values.respond_to?(:call)
|
67
|
+
values ||= begin
|
68
|
+
value = opts[:value] or raise 'pass value or values'
|
69
|
+
if value.respond_to?(:call)
|
70
|
+
keys.map { |key| value.call(key, locale) }
|
71
|
+
else
|
72
|
+
[value] * keys.size
|
73
|
+
end
|
74
|
+
end
|
75
|
+
data[locale] += keys.map(&:to_s).zip(values)
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module I18n
|
2
|
+
module Tasks
|
3
|
+
module Data
|
4
|
+
module FileFormats
|
5
|
+
def self.included(base)
|
6
|
+
base.extend ClassMethods
|
7
|
+
end
|
8
|
+
|
9
|
+
delegate :adapter_for, to: :class
|
10
|
+
|
11
|
+
protected
|
12
|
+
|
13
|
+
def load_file(file)
|
14
|
+
adapter_for(file).parse(
|
15
|
+
::File.read(file)
|
16
|
+
)
|
17
|
+
end
|
18
|
+
|
19
|
+
def write_tree(path, tree)
|
20
|
+
::File.open(path, 'w') { |f|
|
21
|
+
f.write(adapter_for(path).dump(tree.to_hash))
|
22
|
+
}
|
23
|
+
end
|
24
|
+
|
25
|
+
module ClassMethods
|
26
|
+
# @param pattern [String] File.fnmatch pattern
|
27
|
+
# @param adapter [responds to parse(string)->hash and dump(hash)->string]
|
28
|
+
def register_adapter(pattern, adapter)
|
29
|
+
(@fn_patterns ||= {})[pattern] = adapter
|
30
|
+
end
|
31
|
+
|
32
|
+
def adapter_for(path)
|
33
|
+
@fn_patterns.detect { |pattern, adapter|
|
34
|
+
::File.fnmatch(pattern, path)
|
35
|
+
}[1] or raise "Adapter not found for #{path}. Registered adapters: #{@fn_patterns.inspect}"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -1,11 +1,10 @@
|
|
1
|
-
require 'i18n/tasks/data/
|
1
|
+
require 'i18n/tasks/data/file_system_base'
|
2
2
|
require 'i18n/tasks/data/adapter/json_adapter'
|
3
3
|
require 'i18n/tasks/data/adapter/yaml_adapter'
|
4
4
|
|
5
5
|
module I18n::Tasks
|
6
6
|
module Data
|
7
|
-
class FileSystem
|
8
|
-
include Storage::FileStorage
|
7
|
+
class FileSystem < FileSystemBase
|
9
8
|
register_adapter '*.yml', Adapter::YamlAdapter
|
10
9
|
register_adapter '*.json', Adapter::JsonAdapter
|
11
10
|
end
|