i18n-hygiene 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|