i18n-hygiene 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 +7 -0
- data/lib/i18n/hygiene.rb +9 -0
- data/lib/i18n/hygiene/key_usage_checker.rb +54 -0
- data/lib/i18n/hygiene/keys_with_entities.rb +29 -0
- data/lib/i18n/hygiene/keys_with_matched_value.rb +52 -0
- data/lib/i18n/hygiene/keys_with_return_symbol.rb +21 -0
- data/lib/i18n/hygiene/keys_with_script_tags.rb +21 -0
- data/lib/i18n/hygiene/locale_translations.rb +74 -0
- data/lib/i18n/hygiene/railtie.rb +9 -0
- data/lib/i18n/hygiene/variable_checker.rb +80 -0
- data/lib/i18n/hygiene/wrapper.rb +41 -0
- data/lib/tasks/i18n_hygiene.rake +87 -0
- metadata +103 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: f906fef080e1dbaa668f50b353fc861f709f1ca1
|
4
|
+
data.tar.gz: c79a6e97927517a08ac025ac2d8570a481de6b74
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 854a7ec8e067f52e39dd77a45f649af2a9f036208c25db7e81b0a34a786bcc8fea2e986aad6d3f32c7cc678f918aa3297f69a0aea090d605c752d96e11a21bff
|
7
|
+
data.tar.gz: 50bc730b81a6fd89a9ea58547548f5148c96c8ed8118d780271edb07df8cd540fa8a4d4ff45b6adb3b4b7a10c5e32ce3c12da3f1c46fa7278db0754b82764548
|
data/lib/i18n/hygiene.rb
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
require 'i18n/hygiene/railtie' if defined?(Rails)
|
2
|
+
require 'i18n/hygiene/key_usage_checker'
|
3
|
+
require 'i18n/hygiene/keys_with_entities'
|
4
|
+
require 'i18n/hygiene/keys_with_matched_value'
|
5
|
+
require 'i18n/hygiene/keys_with_return_symbol'
|
6
|
+
require 'i18n/hygiene/keys_with_script_tags'
|
7
|
+
require 'i18n/hygiene/locale_translations'
|
8
|
+
require 'i18n/hygiene/variable_checker'
|
9
|
+
require 'i18n/hygiene/wrapper'
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module I18n
|
2
|
+
module Hygiene
|
3
|
+
# Checks the usage of i18n keys in the TC codebase.
|
4
|
+
#
|
5
|
+
# TODO: This class needs some work, I had to strip out a bunch of functionality around
|
6
|
+
# the dynamically used keys because it was all specific to TC.
|
7
|
+
#
|
8
|
+
# We need to add a way to configure the hygiene checks to "whitelist" certain dynamic
|
9
|
+
# keys and so on.
|
10
|
+
#
|
11
|
+
# The other issue is that we hard code the folders we scan for fully qualified keys
|
12
|
+
# which should also be configurable.
|
13
|
+
class KeyUsageChecker
|
14
|
+
|
15
|
+
attr_reader :key
|
16
|
+
|
17
|
+
def initialize(key)
|
18
|
+
@key = key
|
19
|
+
end
|
20
|
+
|
21
|
+
def used_in_codebase?
|
22
|
+
fully_qualified_key_used?
|
23
|
+
end
|
24
|
+
|
25
|
+
def fully_qualified_key_used?(given_key = key)
|
26
|
+
if pluralized_key_used?(given_key)
|
27
|
+
fully_qualified_key_used?(without_last_part)
|
28
|
+
else
|
29
|
+
%x<#{ag_or_ack} #{given_key} app lib | wc -l>.strip.to_i > 0
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def ag_or_ack
|
36
|
+
if %x<which ag | wc -l>.strip.to_i == 1
|
37
|
+
return "ag"
|
38
|
+
else
|
39
|
+
return "ack --type-add=js=.coffee"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def pluralized_key_used?(key)
|
44
|
+
[ "zero", "one", "other" ].include?(key.split(".").last)
|
45
|
+
end
|
46
|
+
|
47
|
+
def without_last_part
|
48
|
+
key.split(".")[0..-2].join(".")
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'enumerator'
|
2
|
+
|
3
|
+
module I18n
|
4
|
+
module Hygiene
|
5
|
+
# A collection of Strings that indicate the i18n keys in any locale that contain
|
6
|
+
# entities which are likely to be rendered incorrectly. Only keys ending in _html
|
7
|
+
# or _markdown may contain entities.
|
8
|
+
#
|
9
|
+
class KeysWithEntities
|
10
|
+
include Enumerable
|
11
|
+
|
12
|
+
ENTITY_REGEX = /&\w+;/
|
13
|
+
|
14
|
+
def initialize(i18nwrapper: nil)
|
15
|
+
@matcher = I18n::Hygiene::KeysWithMatchedValue.new(ENTITY_REGEX, i18nwrapper, reject_keys: reject_keys)
|
16
|
+
end
|
17
|
+
|
18
|
+
def each(&block)
|
19
|
+
@matcher.each(&block)
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def reject_keys
|
25
|
+
Proc.new { |key| key.end_with?("_html") || key.end_with?("_markdown") }
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module I18n
|
2
|
+
module Hygiene
|
3
|
+
# Checks to see if any i18n values match a given regex.
|
4
|
+
class KeysWithMatchedValue
|
5
|
+
include Enumerable
|
6
|
+
|
7
|
+
def initialize(regex, i18n_wrapper = nil, reject_keys: nil)
|
8
|
+
@regex = regex
|
9
|
+
@i18n = i18n_wrapper || I18n::Hygiene::Wrapper.new
|
10
|
+
@reject_keys = reject_keys
|
11
|
+
@matching_keys = load_matching_keys
|
12
|
+
end
|
13
|
+
|
14
|
+
def each(&block)
|
15
|
+
@matching_keys.each(&block)
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def load_matching_keys
|
21
|
+
locales.inject([]) do |results, locale|
|
22
|
+
results + matching_keys(locale).map { |key| "#{locale}: #{key}" }
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def matching_keys(locale)
|
27
|
+
keys_to_check(locale).select { |key| i18n.value(locale, key).to_s.match(regex) }
|
28
|
+
end
|
29
|
+
|
30
|
+
def regex
|
31
|
+
@regex
|
32
|
+
end
|
33
|
+
|
34
|
+
def keys_to_check(locale)
|
35
|
+
reject_keys ? i18n.keys_to_check(locale).reject(&reject_keys) : i18n.keys_to_check(locale)
|
36
|
+
end
|
37
|
+
|
38
|
+
def reject_keys
|
39
|
+
@reject_keys
|
40
|
+
end
|
41
|
+
|
42
|
+
def i18n
|
43
|
+
@i18n
|
44
|
+
end
|
45
|
+
|
46
|
+
def locales
|
47
|
+
i18n.locales
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'enumerator'
|
2
|
+
|
3
|
+
module I18n
|
4
|
+
module Hygiene
|
5
|
+
# Checks to see if any i18n values contain the U+23CE character.
|
6
|
+
# It has been included in PhraseApp translations but is unwanted.
|
7
|
+
class KeysWithReturnSymbol
|
8
|
+
include Enumerable
|
9
|
+
|
10
|
+
RETURN_SYMBOL_REGEX = /\u23ce/
|
11
|
+
|
12
|
+
def initialize(i18n_wrapper: nil)
|
13
|
+
@matcher = I18n::Hygiene::KeysWithMatchedValue.new(RETURN_SYMBOL_REGEX, i18n_wrapper)
|
14
|
+
end
|
15
|
+
|
16
|
+
def each(&block)
|
17
|
+
@matcher.each(&block)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'enumerator'
|
2
|
+
|
3
|
+
module I18n
|
4
|
+
module Hygiene
|
5
|
+
# Checks to see if any i18n values contain script tags.
|
6
|
+
# We should never allow script tags!
|
7
|
+
class KeysWithScriptTags
|
8
|
+
include Enumerable
|
9
|
+
|
10
|
+
SCRIPT_TAG_REGEX = /<script>.*<\/script>/
|
11
|
+
|
12
|
+
def initialize(i18n_wrapper: nil)
|
13
|
+
@matcher = I18n::Hygiene::KeysWithMatchedValue.new(SCRIPT_TAG_REGEX, i18n_wrapper)
|
14
|
+
end
|
15
|
+
|
16
|
+
def each(&block)
|
17
|
+
@matcher.each(&block)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module I18n
|
2
|
+
module Hygiene
|
3
|
+
# Wrap all translations for a single locale, with knowledge of the keys that
|
4
|
+
# aren't in our control. Can return the i18n keys that **are** in our control,
|
5
|
+
# and therefore are interesting for a variety of reasons.
|
6
|
+
class LocaleTranslations
|
7
|
+
# This is a default example key in the locale files that is not actually used.
|
8
|
+
EXAMPLE_KEY = "common.greeting"
|
9
|
+
|
10
|
+
# These are i18n keys provided by Rails. We cannot exclude them at the :helpers
|
11
|
+
# scope level because we do have some TC i18n keys scoped within :helpers.
|
12
|
+
|
13
|
+
# TODO: make this configurable
|
14
|
+
KEYS_TO_SKIP = [
|
15
|
+
"helpers.select.prompt",
|
16
|
+
"helpers.submit.create",
|
17
|
+
"helpers.submit.submit",
|
18
|
+
"helpers.submit.update"
|
19
|
+
]
|
20
|
+
|
21
|
+
def initialize(translations)
|
22
|
+
@translations = translations
|
23
|
+
end
|
24
|
+
|
25
|
+
def keys_to_check
|
26
|
+
fully_qualified_keys(translations_to_check).reject { |key|
|
27
|
+
KEYS_TO_SKIP.include?(key) || EXAMPLE_KEY == key
|
28
|
+
}.sort
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def translations_to_check
|
34
|
+
@translations.reject { |k, _v| non_tc_scopes.include? k }
|
35
|
+
end
|
36
|
+
|
37
|
+
def non_tc_scopes
|
38
|
+
scopes_from_rails + scopes_from_devise + scopes_from_kaminari + scopes_from_i18n_country_select + scopes_from_faker
|
39
|
+
end
|
40
|
+
|
41
|
+
def scopes_from_rails
|
42
|
+
[ :activerecord, :date, :datetime, :errors, :number, :support, :time ]
|
43
|
+
end
|
44
|
+
|
45
|
+
def scopes_from_devise
|
46
|
+
[ :devise ]
|
47
|
+
end
|
48
|
+
|
49
|
+
def scopes_from_kaminari
|
50
|
+
[ :views ]
|
51
|
+
end
|
52
|
+
|
53
|
+
def scopes_from_i18n_country_select
|
54
|
+
[ :countries ]
|
55
|
+
end
|
56
|
+
|
57
|
+
def scopes_from_faker
|
58
|
+
[ :faker ]
|
59
|
+
end
|
60
|
+
|
61
|
+
def fully_qualified_keys(hash)
|
62
|
+
hash.inject([]) do |accum, (key, value)|
|
63
|
+
if value.is_a?(Hash)
|
64
|
+
accum + fully_qualified_keys(value).map do |sub_keys|
|
65
|
+
"#{key}.#{sub_keys}"
|
66
|
+
end
|
67
|
+
else
|
68
|
+
accum + [key.to_s]
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module I18n
|
2
|
+
module Hygiene
|
3
|
+
# Checks for mismatching interpolation variables. For example, if the value for an i18n key
|
4
|
+
# as defined in :en contains an interpolation variable, the value for that key as defined
|
5
|
+
# in any other locale must have a matching variable name.
|
6
|
+
class VariableChecker
|
7
|
+
|
8
|
+
NON_ENGLISH_LOCALES_TO_CHECK = [ :fr_fr ]
|
9
|
+
|
10
|
+
def initialize(key, i18n_wrapper)
|
11
|
+
@key = key
|
12
|
+
@i18n_wrapper = i18n_wrapper
|
13
|
+
end
|
14
|
+
|
15
|
+
def mismatched_variables_found?
|
16
|
+
NON_ENGLISH_LOCALES_TO_CHECK.each do |locale|
|
17
|
+
if key_defined?(locale)
|
18
|
+
return true unless variables_match?(locale)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
false
|
22
|
+
end
|
23
|
+
|
24
|
+
def mismatch_details
|
25
|
+
if mismatched_variables_found?
|
26
|
+
details_array = []
|
27
|
+
NON_ENGLISH_LOCALES_TO_CHECK.each do |locale|
|
28
|
+
if key_defined?(locale)
|
29
|
+
details_array << mismatch_details_for_locale(locale) unless variables_match?(locale)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
return details_array.join("\n")
|
33
|
+
else
|
34
|
+
return "#{@key}: no missing interpolation variables found."
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def mismatch_details_for_locale(locale)
|
41
|
+
"#{@key} for locale #{locale} is missing interpolation variable(s): #{missing_variables(locale)}"
|
42
|
+
end
|
43
|
+
|
44
|
+
def missing_variables(locale)
|
45
|
+
variables(:en).reject { |v| variables(locale).include?(v) }.join(', ')
|
46
|
+
end
|
47
|
+
|
48
|
+
def key_defined?(locale)
|
49
|
+
@i18n_wrapper.key_found?(locale, @key)
|
50
|
+
end
|
51
|
+
|
52
|
+
def variables_match?(locale)
|
53
|
+
variables(locale) == variables(:en)
|
54
|
+
end
|
55
|
+
|
56
|
+
def variables(locale)
|
57
|
+
collect_variables(@i18n_wrapper.value(locale, @key))
|
58
|
+
end
|
59
|
+
|
60
|
+
def collect_variables(string)
|
61
|
+
return [] unless string.is_a?(String)
|
62
|
+
(rails_variables(string) + js_variables(string)).uniq.sort
|
63
|
+
end
|
64
|
+
|
65
|
+
def rails_variables(string)
|
66
|
+
string.scan(/%{\S+}/).map { |var_string| var_string.gsub(/[%{}]/, '').to_sym }
|
67
|
+
end
|
68
|
+
|
69
|
+
def js_variables(string)
|
70
|
+
without_markdown_italics(string.scan(/__\S+__/).map { |var_string| var_string.gsub("__", "").to_sym })
|
71
|
+
end
|
72
|
+
|
73
|
+
def without_markdown_italics(array)
|
74
|
+
@key.end_with?("_markdown") ? [] : array
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module I18n
|
2
|
+
module Hygiene
|
3
|
+
# Utility class for interacting with i18n definitions. This is not intended to be used
|
4
|
+
# in production code - it's focus is on making the i18n data easily enumerable and
|
5
|
+
# queryable.
|
6
|
+
class Wrapper
|
7
|
+
|
8
|
+
def keys_to_check(locale = :en)
|
9
|
+
I18n::Hygiene::LocaleTranslations.new(translations[locale]).keys_to_check
|
10
|
+
end
|
11
|
+
|
12
|
+
def locales
|
13
|
+
translations.keys
|
14
|
+
end
|
15
|
+
|
16
|
+
def key_found?(locale, key)
|
17
|
+
I18n.with_locale(locale) do
|
18
|
+
I18n.exists?(key)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def value(locale, key)
|
23
|
+
I18n.with_locale(locale) do
|
24
|
+
I18n.t(key)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def translations
|
31
|
+
load_translations unless @translations
|
32
|
+
@translations ||= ::I18n.backend.send(:translations)
|
33
|
+
end
|
34
|
+
|
35
|
+
def load_translations
|
36
|
+
::I18n.backend.send(:init_translations)
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
namespace :i18n do
|
2
|
+
namespace :hygiene do
|
3
|
+
|
4
|
+
desc 'run all the i18n hygiene checks'
|
5
|
+
task all: [:check_key_usage, :check_variables, :check_entities, :check_return_symbols, :check_script_tags]
|
6
|
+
|
7
|
+
desc "check usage of all EN keys"
|
8
|
+
task check_key_usage: :environment do
|
9
|
+
require 'parallel'
|
10
|
+
|
11
|
+
puts "Checking usage of EN keys..."
|
12
|
+
puts "(Please be patient while the codebase is searched for key usage)"
|
13
|
+
|
14
|
+
unused_keys = Parallel.map(I18n::Hygiene::Wrapper.new.keys_to_check) { |key|
|
15
|
+
key unless I18n::Hygiene::KeyUsageChecker.new(key).used_in_codebase?
|
16
|
+
}.compact
|
17
|
+
|
18
|
+
unused_keys.each do |key|
|
19
|
+
puts "#{key} is unused."
|
20
|
+
end
|
21
|
+
|
22
|
+
puts "Finished checking.\n\n"
|
23
|
+
|
24
|
+
exit(1) if unused_keys.any?
|
25
|
+
end
|
26
|
+
|
27
|
+
desc "check for mismatching interpolation variables"
|
28
|
+
task check_variables: :environment do
|
29
|
+
puts "Checking for mismatching interpolation variables..."
|
30
|
+
|
31
|
+
wrapper = I18n::Hygiene::Wrapper.new
|
32
|
+
|
33
|
+
mismatched_variables = wrapper.keys_to_check.select do |key|
|
34
|
+
checker = I18n::Hygiene::VariableChecker.new(key, wrapper)
|
35
|
+
checker.mismatch_details if checker.mismatched_variables_found?
|
36
|
+
end
|
37
|
+
|
38
|
+
mismatched_variables.each { |details| puts details }
|
39
|
+
|
40
|
+
puts "Finished checking.\n\n"
|
41
|
+
|
42
|
+
exit(1) if mismatched_variables.any?
|
43
|
+
end
|
44
|
+
|
45
|
+
desc "check for i18n phrases that contain entities"
|
46
|
+
task check_entities: :environment do
|
47
|
+
puts "Checking for phrases that contain entities but probably shouldn't..."
|
48
|
+
|
49
|
+
keys_with_entities = I18n::Hygiene::KeysWithEntities.new
|
50
|
+
|
51
|
+
keys_with_entities.each do |key|
|
52
|
+
puts "- #{key}"
|
53
|
+
end
|
54
|
+
|
55
|
+
puts "Finished checking.\n\n"
|
56
|
+
|
57
|
+
exit(1) if keys_with_entities.any?
|
58
|
+
end
|
59
|
+
|
60
|
+
desc "Check there are no values containing return symbols"
|
61
|
+
task check_return_symbols: :environment do
|
62
|
+
puts "Checking that no values contain return symbols i.e. U+23CE ..."
|
63
|
+
|
64
|
+
keys_with_return_symbols = I18n::Hygiene::KeysWithReturnSymbol.new
|
65
|
+
|
66
|
+
keys_with_return_symbols.each { |key| puts "- #{key}" }
|
67
|
+
|
68
|
+
puts "Finished checking.\n\n"
|
69
|
+
|
70
|
+
exit(1) if keys_with_return_symbols.any?
|
71
|
+
end
|
72
|
+
|
73
|
+
desc "Check there are no values containing scripts"
|
74
|
+
task check_script_tags: :environment do
|
75
|
+
puts "Checking that no values contain script tags ..."
|
76
|
+
|
77
|
+
keys_with_script_tags = I18n::Hygiene::KeysWithScriptTags.new
|
78
|
+
|
79
|
+
keys_with_script_tags.each { |key| puts " - #{key}" }
|
80
|
+
|
81
|
+
puts "Finished checking.\n\n"
|
82
|
+
|
83
|
+
exit(1) if keys_with_script_tags.any?
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
end
|
metadata
ADDED
@@ -0,0 +1,103 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: i18n-hygiene
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Nick Browne
|
8
|
+
- " Keith Pitty"
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2015-11-26 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: i18n
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - "~>"
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: '0.6'
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.6.9
|
24
|
+
type: :runtime
|
25
|
+
prerelease: false
|
26
|
+
version_requirements: !ruby/object:Gem::Requirement
|
27
|
+
requirements:
|
28
|
+
- - "~>"
|
29
|
+
- !ruby/object:Gem::Version
|
30
|
+
version: '0.6'
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 0.6.9
|
34
|
+
- !ruby/object:Gem::Dependency
|
35
|
+
name: parallel
|
36
|
+
requirement: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.3'
|
41
|
+
type: :runtime
|
42
|
+
prerelease: false
|
43
|
+
version_requirements: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.3'
|
48
|
+
- !ruby/object:Gem::Dependency
|
49
|
+
name: rspec
|
50
|
+
requirement: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.0'
|
55
|
+
type: :development
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '3.0'
|
62
|
+
description: Provides rake tasks to help maintain translations.
|
63
|
+
email: dev@theconversation.edu.au
|
64
|
+
executables: []
|
65
|
+
extensions: []
|
66
|
+
extra_rdoc_files: []
|
67
|
+
files:
|
68
|
+
- lib/i18n/hygiene.rb
|
69
|
+
- lib/i18n/hygiene/key_usage_checker.rb
|
70
|
+
- lib/i18n/hygiene/keys_with_entities.rb
|
71
|
+
- lib/i18n/hygiene/keys_with_matched_value.rb
|
72
|
+
- lib/i18n/hygiene/keys_with_return_symbol.rb
|
73
|
+
- lib/i18n/hygiene/keys_with_script_tags.rb
|
74
|
+
- lib/i18n/hygiene/locale_translations.rb
|
75
|
+
- lib/i18n/hygiene/railtie.rb
|
76
|
+
- lib/i18n/hygiene/variable_checker.rb
|
77
|
+
- lib/i18n/hygiene/wrapper.rb
|
78
|
+
- lib/tasks/i18n_hygiene.rake
|
79
|
+
homepage: https://github.com/conversation/i18n-hygiene
|
80
|
+
licenses:
|
81
|
+
- MIT
|
82
|
+
metadata: {}
|
83
|
+
post_install_message:
|
84
|
+
rdoc_options: []
|
85
|
+
require_paths:
|
86
|
+
- lib
|
87
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
88
|
+
requirements:
|
89
|
+
- - ">="
|
90
|
+
- !ruby/object:Gem::Version
|
91
|
+
version: '0'
|
92
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
requirements: []
|
98
|
+
rubyforge_project:
|
99
|
+
rubygems_version: 2.4.5.1
|
100
|
+
signing_key:
|
101
|
+
specification_version: 4
|
102
|
+
summary: Helps maintain translations.
|
103
|
+
test_files: []
|