kakimasu 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.coveralls.yml +1 -0
- data/.gitignore +12 -0
- data/.rspec +2 -0
- data/.rubocop.yml +31 -0
- data/.travis.yml +8 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +135 -0
- data/Rakefile +6 -0
- data/app/controllers/kakimasu/home_controller.rb +18 -0
- data/app/controllers/kakimasu/keys_controller.rb +89 -0
- data/app/controllers/kakimasu/translations_controller.rb +37 -0
- data/app/helpers/counting_helper.rb +11 -0
- data/app/helpers/formatting_helper.rb +6 -0
- data/app/helpers/grouping_helper.rb +11 -0
- data/app/helpers/pagination_helper.rb +15 -0
- data/app/helpers/search_key_helper.rb +66 -0
- data/app/helpers/search_translations_helper.rb +101 -0
- data/app/models/translation.rb +2 -0
- data/app/policies/translation_policy.rb +9 -0
- data/app/views/kakimasu/home/index.html.erb +35 -0
- data/app/views/kakimasu/keys/create.js.erb +1 -0
- data/app/views/kakimasu/keys/index.html.erb +183 -0
- data/app/views/kakimasu/shared/_navbar.html.erb +15 -0
- data/app/views/kakimasu/translations/create.js.erb +1 -0
- data/app/views/kakimasu/translations/index.html.erb +168 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/config/initializers/i18n.rb +58 -0
- data/config/initializers/i18n_backend.rb +5 -0
- data/config/locales/en.yml +34 -0
- data/config/routes.rb +10 -0
- data/kakimasu.gemspec +49 -0
- data/lib/generators/kakimasu/backup_generator.rb +101 -0
- data/lib/generators/kakimasu/policy_generator.rb +18 -0
- data/lib/generators/kakimasu/restore_backup_generator.rb +89 -0
- data/lib/generators/kakimasu/views_generator.rb +22 -0
- data/lib/kakimasu.rb +11 -0
- data/lib/kakimasu/engine.rb +3 -0
- data/lib/kakimasu/version.rb +3 -0
- data/vendor/assets/javascripts/components/activation_button.coffee +10 -0
- data/vendor/assets/javascripts/components/modal.coffee +48 -0
- data/vendor/assets/javascripts/components/translate.coffee +93 -0
- data/vendor/assets/javascripts/components/translation_key_table.coffee +5 -0
- data/vendor/assets/javascripts/components/translation_navigation.coffee +13 -0
- data/vendor/assets/javascripts/components/translation_panel_table.coffee +5 -0
- data/vendor/assets/javascripts/components/translation_percent_chart.coffee +39 -0
- data/vendor/assets/javascripts/components/translation_popover.coffee +90 -0
- data/vendor/assets/javascripts/jquery/jquery.circliful.min.js +1 -0
- data/vendor/assets/javascripts/kakimasu.coffee +18 -0
- data/vendor/assets/stylesheets/circliful.scss +38 -0
- data/vendor/assets/stylesheets/components/_homepage.scss +17 -0
- data/vendor/assets/stylesheets/components/_key_management.scss +53 -0
- data/vendor/assets/stylesheets/components/_navbar.scss +52 -0
- data/vendor/assets/stylesheets/components/_translate_modal.scss +36 -0
- data/vendor/assets/stylesheets/components/_translation_panel.scss +31 -0
- data/vendor/assets/stylesheets/components/_translation_popover.scss +31 -0
- data/vendor/assets/stylesheets/font-awesome/HELP-US-OUT.txt +7 -0
- data/vendor/assets/stylesheets/font-awesome/css/font-awesome.css +2337 -0
- data/vendor/assets/stylesheets/font-awesome/css/font-awesome.min.css +4 -0
- data/vendor/assets/stylesheets/font-awesome/fonts/FontAwesome.otf +0 -0
- data/vendor/assets/stylesheets/font-awesome/fonts/fontawesome-webfont.eot +0 -0
- data/vendor/assets/stylesheets/font-awesome/fonts/fontawesome-webfont.svg +2671 -0
- data/vendor/assets/stylesheets/font-awesome/fonts/fontawesome-webfont.ttf +0 -0
- data/vendor/assets/stylesheets/font-awesome/fonts/fontawesome-webfont.woff +0 -0
- data/vendor/assets/stylesheets/font-awesome/fonts/fontawesome-webfont.woff2 +0 -0
- data/vendor/assets/stylesheets/font-awesome/less/animated.less +34 -0
- data/vendor/assets/stylesheets/font-awesome/less/bordered-pulled.less +25 -0
- data/vendor/assets/stylesheets/font-awesome/less/core.less +12 -0
- data/vendor/assets/stylesheets/font-awesome/less/fixed-width.less +6 -0
- data/vendor/assets/stylesheets/font-awesome/less/font-awesome.less +18 -0
- data/vendor/assets/stylesheets/font-awesome/less/icons.less +789 -0
- data/vendor/assets/stylesheets/font-awesome/less/larger.less +13 -0
- data/vendor/assets/stylesheets/font-awesome/less/list.less +19 -0
- data/vendor/assets/stylesheets/font-awesome/less/mixins.less +60 -0
- data/vendor/assets/stylesheets/font-awesome/less/path.less +15 -0
- data/vendor/assets/stylesheets/font-awesome/less/rotated-flipped.less +20 -0
- data/vendor/assets/stylesheets/font-awesome/less/screen-reader.less +5 -0
- data/vendor/assets/stylesheets/font-awesome/less/stacked.less +20 -0
- data/vendor/assets/stylesheets/font-awesome/less/variables.less +800 -0
- data/vendor/assets/stylesheets/font-awesome/scss/_animated.scss +34 -0
- data/vendor/assets/stylesheets/font-awesome/scss/_bordered-pulled.scss +25 -0
- data/vendor/assets/stylesheets/font-awesome/scss/_core.scss +12 -0
- data/vendor/assets/stylesheets/font-awesome/scss/_fixed-width.scss +6 -0
- data/vendor/assets/stylesheets/font-awesome/scss/_icons.scss +789 -0
- data/vendor/assets/stylesheets/font-awesome/scss/_larger.scss +13 -0
- data/vendor/assets/stylesheets/font-awesome/scss/_list.scss +19 -0
- data/vendor/assets/stylesheets/font-awesome/scss/_mixins.scss +60 -0
- data/vendor/assets/stylesheets/font-awesome/scss/_path.scss +15 -0
- data/vendor/assets/stylesheets/font-awesome/scss/_rotated-flipped.scss +20 -0
- data/vendor/assets/stylesheets/font-awesome/scss/_screen-reader.scss +5 -0
- data/vendor/assets/stylesheets/font-awesome/scss/_stacked.scss +20 -0
- data/vendor/assets/stylesheets/font-awesome/scss/_variables.scss +800 -0
- data/vendor/assets/stylesheets/font-awesome/scss/font-awesome.scss +18 -0
- data/vendor/assets/stylesheets/kakimasu.scss +35 -0
- metadata +364 -0
@@ -0,0 +1,11 @@
|
|
1
|
+
module CountingHelper
|
2
|
+
# Counts how much keys there is in key array
|
3
|
+
def countKeys(array)
|
4
|
+
array.flatten.count - array.count
|
5
|
+
end
|
6
|
+
|
7
|
+
# Gets translation percentage
|
8
|
+
def translationPercentage(all_keys, missing_translations)
|
9
|
+
((1 - ( missing_translations.to_f / all_keys )) * 100).round(2)
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module GroupingHelper
|
2
|
+
# Groups all translations by language in array
|
3
|
+
def group_by_language(array)
|
4
|
+
array.group_by { |el| el.partition('.').first }
|
5
|
+
end
|
6
|
+
|
7
|
+
# Gets all paths from keys array
|
8
|
+
def get_translation_key_paths(array)
|
9
|
+
array.map { |el| el.last }
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# Sets translation key for lazy lookup or unsets it.
|
2
|
+
module SearchKeyHelper
|
3
|
+
def lazy_lookup_key(key, path)
|
4
|
+
path = 'app/views/' + path
|
5
|
+
file = File.read(path)
|
6
|
+
|
7
|
+
matches = Array.new #All places where this key is used in given file
|
8
|
+
locations = Array.new #Indexes which determines where to make changes
|
9
|
+
file_length_differential = 0 #File length difference because substitutions will change file size.
|
10
|
+
|
11
|
+
# Finds all places where given translation key is used
|
12
|
+
file.scan(/[=|\s][t][\s]*[(]?[\s]*['|:]#{key}/) do |c|
|
13
|
+
matches.push [c, $~.offset(0)[0]]
|
14
|
+
end
|
15
|
+
|
16
|
+
matches.each do |array|
|
17
|
+
if array.first.match /[=|\s][t][\s]*[(]?[\s]*[:]\w*/ # if translation written with : not '' then its special case
|
18
|
+
# Key with ':key' is sustituted with "'.key'"
|
19
|
+
index = array.first.index(/:#{key}/)
|
20
|
+
file.slice!(array.last + index + file_length_differential, (":#{key}").length)
|
21
|
+
file.insert(array.last + index + file_length_differential, "'.#{key}'")
|
22
|
+
file_length_differential += ("'.#{key}'").length - (":#{key}").length
|
23
|
+
elsif key[0] != '.'
|
24
|
+
index = array.first.index(key)
|
25
|
+
locations.push array.last + index + file_length_differential
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# Insert '.' just before key for lazy lookup
|
30
|
+
locations.each_with_index do |location, index|
|
31
|
+
file.insert(location + index, '.')
|
32
|
+
end
|
33
|
+
|
34
|
+
File.write(path, file)
|
35
|
+
end
|
36
|
+
|
37
|
+
def remove_lazy_lookup(key, path)
|
38
|
+
path = 'app/views/' + path
|
39
|
+
file = File.read(path)
|
40
|
+
|
41
|
+
# Get rid of prefix of has lazy lookup prefix
|
42
|
+
if key.include? '.'
|
43
|
+
key = key.split('.').last
|
44
|
+
key.prepend '.'
|
45
|
+
end
|
46
|
+
|
47
|
+
matches = Array.new # All places where given key is used in file
|
48
|
+
locations = Array.new #Indexes which determintes where to make changes
|
49
|
+
|
50
|
+
key.slice! 0 if key[0] == '.'
|
51
|
+
file.scan(/[=|\s][t][\s]*[(]?[\s]*['][.]#{key}/) do |c|
|
52
|
+
matches.push [c, $~.offset(0)[0]]
|
53
|
+
end
|
54
|
+
|
55
|
+
matches.each do |array|
|
56
|
+
index = array.first.index('.' + key)
|
57
|
+
locations.push array.last + index
|
58
|
+
end
|
59
|
+
|
60
|
+
locations.each_with_index do |location, index|
|
61
|
+
file.slice!(location - index) # Removes '.' from match
|
62
|
+
end
|
63
|
+
|
64
|
+
File.write(path, file)
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
module SearchTranslationsHelper
|
2
|
+
# Method to get prefix for lazy lookup
|
3
|
+
def prefix(path)
|
4
|
+
prefix = path.split('/')
|
5
|
+
prefix[-1] = prefix.last.split('.').first
|
6
|
+
prefix = prefix.join('.')
|
7
|
+
end
|
8
|
+
|
9
|
+
# Method returns if key has missing translation in one of locales
|
10
|
+
def missing_translations?(key)
|
11
|
+
missing_translation = false
|
12
|
+
I18n.available_locales.each do |locale|
|
13
|
+
if !I18n.exists?(key, locale)
|
14
|
+
missing_translation = true # If in one of locales key has no translation, method returns true
|
15
|
+
end
|
16
|
+
end
|
17
|
+
missing_translation
|
18
|
+
end
|
19
|
+
|
20
|
+
# Method searches used translations keys in a file
|
21
|
+
def find_keys(file, path)
|
22
|
+
array = file.scan(/[=|\s][t][\s]*[(]?[\s]*['|:]([.]*\w*)/).uniq
|
23
|
+
keys = Array.new
|
24
|
+
|
25
|
+
# If key has '.' in front of it, it should be completed as lazy lookup key.
|
26
|
+
array.each_with_index do |key, index|
|
27
|
+
if key.first[0] == '.'
|
28
|
+
array[index] = key.first.insert(0, prefix(path))
|
29
|
+
end
|
30
|
+
end
|
31
|
+
array
|
32
|
+
end
|
33
|
+
|
34
|
+
# Method returns array of keys with missing translations from given array
|
35
|
+
def find_missing_translations_keys(array)
|
36
|
+
missing_translations_keys = []
|
37
|
+
|
38
|
+
array.each do |key|
|
39
|
+
missing_translations_keys.push key if missing_translations?(key)
|
40
|
+
end
|
41
|
+
|
42
|
+
missing_translations_keys
|
43
|
+
end
|
44
|
+
|
45
|
+
# Method searches used active record human attribute name keys in given file
|
46
|
+
def find_attribute_keys(file)
|
47
|
+
array = file.scan(/(\w*).human_attribute_name[(][:](\w*)/).uniq
|
48
|
+
keys = []
|
49
|
+
# Keys are transformed into correct active record attribute keys form
|
50
|
+
array.each do |arr|
|
51
|
+
arr = 'activerecord.' + 'attributes.' + arr.first.downcase + '.' + arr.last
|
52
|
+
keys.push arr
|
53
|
+
end
|
54
|
+
keys
|
55
|
+
end
|
56
|
+
|
57
|
+
# Method searches used Model name keys in given file
|
58
|
+
def find_model_name_keys(file)
|
59
|
+
array = file.scan(/(\w*).model_name.human/).uniq
|
60
|
+
keys = []
|
61
|
+
# Keys are transformed into correct active record model name keys form
|
62
|
+
array.each do |arr|
|
63
|
+
arr = 'activerecord.models.' + arr.first.downcase
|
64
|
+
keys.push arr
|
65
|
+
end
|
66
|
+
keys
|
67
|
+
end
|
68
|
+
|
69
|
+
# Method returns array with requested translation keys
|
70
|
+
def search_for_translations(category)
|
71
|
+
keys = []
|
72
|
+
|
73
|
+
Dir.glob("app/views/**/*").each do |path|
|
74
|
+
if File.file?(path)
|
75
|
+
file = File.read(path)
|
76
|
+
case category
|
77
|
+
when 'active_record_attribute_translations'
|
78
|
+
keys.push find_attribute_keys(file)
|
79
|
+
when 'active_record_model_translations'
|
80
|
+
keys.push find_model_name_keys(file)
|
81
|
+
when 'all_translation_keys'
|
82
|
+
path.slice! "app/views/"
|
83
|
+
keys.push find_keys(file, path).push path
|
84
|
+
when 'missing_translations'
|
85
|
+
path.slice! "app/views/"
|
86
|
+
# push in array only those keys which have missing translations
|
87
|
+
keys.push find_missing_translations_keys(find_keys(file, path)).push path
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
case category
|
93
|
+
when 'active_record_attribute_translations'
|
94
|
+
keys.flatten.uniq
|
95
|
+
when 'active_record_model_translations'
|
96
|
+
keys.flatten.uniq
|
97
|
+
else
|
98
|
+
keys
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
<%= render 'kakimasu/shared/navbar' %>
|
2
|
+
|
3
|
+
<div class="container">
|
4
|
+
<div class="row">
|
5
|
+
<div class="col-md-4">
|
6
|
+
<h1 class="kakimasu-greetings"> Hello, user! </h1>
|
7
|
+
|
8
|
+
<% if params[:show_translation_key] == 'true' %>
|
9
|
+
<%= link_to t('deactivate_translation_mode'), { show_translation_key: false }, class: 'btn btn-primary' %>
|
10
|
+
<% else %>
|
11
|
+
<%= link_to t('activate_translation_mode'), { show_translation_key: true }, id: 'activate_translation_mode_button', class: 'btn btn-primary' %>
|
12
|
+
<% end %>
|
13
|
+
</div>
|
14
|
+
|
15
|
+
<div class="col-md-8" data-component="TranslationPercentChart">
|
16
|
+
<div class="translation-diagram">
|
17
|
+
<div id="translation-percentage-circle"></div>
|
18
|
+
<table>
|
19
|
+
<tr>
|
20
|
+
<th><%= t('total_translation_keys') %>:</th>
|
21
|
+
<td><%= @all_keys_count %></td>
|
22
|
+
</tr>
|
23
|
+
<tr>
|
24
|
+
<th><%= t('total_keys_with_missing_translation') %>:</th>
|
25
|
+
<td><%= @missing_translation_keys_count %></td>
|
26
|
+
</tr>
|
27
|
+
<tr class="translation-percentage" data-value="<%= @percentage %>">
|
28
|
+
<th><%= t('translation_percentage') %>:</th>
|
29
|
+
<td><%= @percentage %> %</td>
|
30
|
+
</tr>
|
31
|
+
</table>
|
32
|
+
</div>
|
33
|
+
</div>
|
34
|
+
</div>
|
35
|
+
</div>
|
@@ -0,0 +1 @@
|
|
1
|
+
window.location.reload()
|
@@ -0,0 +1,183 @@
|
|
1
|
+
<%= render 'kakimasu/shared/navbar' %>
|
2
|
+
|
3
|
+
<div data-component="TranslationModal">
|
4
|
+
<h1 class="margin-left-15"><%= t('translation_keys') %></h1>
|
5
|
+
<!-- Category list -->
|
6
|
+
<div>
|
7
|
+
<div class="col-md-3 translation-key-categories">
|
8
|
+
<h3><%=t('categories')%></h3>
|
9
|
+
<ul class="list-group">
|
10
|
+
<% @categories.each do |category| %>
|
11
|
+
<% if @category == category %>
|
12
|
+
<li class="list-group-item active"><%= link_to t(category), keys_category: category %></li>
|
13
|
+
<% else %>
|
14
|
+
<li class="list-group-item"><%= link_to t(category), keys_category: category %></li>
|
15
|
+
<% end %>
|
16
|
+
<% end %>
|
17
|
+
</ul>
|
18
|
+
</div>
|
19
|
+
|
20
|
+
<div class="col-md-9 translation-key-table">
|
21
|
+
<h3><%=t(@category)%></h3>
|
22
|
+
<!-- Translation keys table -->
|
23
|
+
<%-# Check if there are keys to show in tables -%>
|
24
|
+
<% if @category == 'missing_translations' && @keys.count == 0 %>
|
25
|
+
<h3><%= t('no_keys_with_missing_translations') %></h3>
|
26
|
+
<% elsif @category == 'all_translation_keys' && @keys.count == 0 %>
|
27
|
+
<h3><%= t('no_translation_keys_found') %></h3>
|
28
|
+
<% else %>
|
29
|
+
<table class="table" data-component="TranslationKeyTable">
|
30
|
+
<thead>
|
31
|
+
<tr>
|
32
|
+
<th><%= t('key') %></th>
|
33
|
+
<% I18n.available_locales.each do |locale| %>
|
34
|
+
<th><%= locale.upcase %></th>
|
35
|
+
<% end %>
|
36
|
+
<% if @category == 'missing_translations' || @category == 'all_translation_keys' %>
|
37
|
+
<th><%= t('path') %></th>
|
38
|
+
<% end %>
|
39
|
+
<th></th>
|
40
|
+
</tr>
|
41
|
+
</thead>
|
42
|
+
|
43
|
+
<tbody>
|
44
|
+
<%-# Iteration counter for pagination realisation -%>
|
45
|
+
<% key_nr = 0 %>
|
46
|
+
<% if @category == 'missing_translations' || @category == 'all_translation_keys' %>
|
47
|
+
<% @keys.each do |array| %>
|
48
|
+
<% path = array.pop %>
|
49
|
+
<% array = array.flatten %>
|
50
|
+
<% array.each do |key| %>
|
51
|
+
<%-# Checks if this key is in this page-%>
|
52
|
+
<% if get_page_size * (params[:page].to_i - 1) <= key_nr && key_nr < get_page_size * params[:page].to_i %>
|
53
|
+
<tr>
|
54
|
+
<td><%= key %></td>
|
55
|
+
<% translations = [] %>
|
56
|
+
<% I18n.available_locales.each do |locale| %>
|
57
|
+
<% if !I18n.exists?(key, locale) %>
|
58
|
+
<td class="missing_translation_cell"><%= key %></td>
|
59
|
+
<% else %>
|
60
|
+
<td><%= t(key, locale: locale) %></td>
|
61
|
+
<% end %>
|
62
|
+
<% translations.push t(key, locale: locale) %>
|
63
|
+
<% end %>
|
64
|
+
<td><i><%= path %></i></td>
|
65
|
+
<td class="text-center">
|
66
|
+
<%= content_tag 'button', class: 'translate-key-button', data: {toggle: 'modal', target: '#translateModal', key: "#{key}", translations: translations, locales: I18n.available_locales, path: path, unique:
|
67
|
+
(key.include? '.') } do %>
|
68
|
+
<i class="fa fa-pencil" aria-hidden="true"></i>
|
69
|
+
<% end %>
|
70
|
+
</td>
|
71
|
+
</tr>
|
72
|
+
<% end %>
|
73
|
+
<% key_nr += 1 %>
|
74
|
+
<% end %>
|
75
|
+
<% end %>
|
76
|
+
|
77
|
+
<% else %>
|
78
|
+
<% @keys.each do |key| %>
|
79
|
+
<% if get_page_size * (params[:page].to_i - 1) <= key_nr && key_nr < get_page_size * params[:page].to_i %>
|
80
|
+
<tr>
|
81
|
+
<td><%= key %></td>
|
82
|
+
<% translations = [] %>
|
83
|
+
<% I18n.available_locales.each do |locale| %>
|
84
|
+
<td><%= t(key, locale: locale) %></td>
|
85
|
+
<% translations.push t(key, locale: locale) %>
|
86
|
+
<% end %>
|
87
|
+
<td class="text-center">
|
88
|
+
<%= content_tag 'button', class: 'translate-key-button', data: {toggle: 'modal', target: '#translateModal', key: "#{key}", translations: translations, locales: I18n.available_locales} do %>
|
89
|
+
<i class="fa fa-pencil" aria-hidden="true"></i>
|
90
|
+
<% end %>
|
91
|
+
</td>
|
92
|
+
</tr>
|
93
|
+
<% end %>
|
94
|
+
<% key_nr += 1 %>
|
95
|
+
<% end %>
|
96
|
+
<% end %>
|
97
|
+
</tbody>
|
98
|
+
</table>
|
99
|
+
<% end %>
|
100
|
+
|
101
|
+
<!-- Pagination -->
|
102
|
+
<div class="text-center">
|
103
|
+
<% if total_pages(@keys.flatten) > 1 %>
|
104
|
+
<ul class="pagination">
|
105
|
+
<li>
|
106
|
+
<% if params[:page].to_i > 1 %>
|
107
|
+
<%= link_to '«'.html_safe, page: params[:page].to_i - 1, keys_category: @category %>
|
108
|
+
<% end %>
|
109
|
+
</li>
|
110
|
+
<% for i in 1..total_pages(@keys.flatten) %>
|
111
|
+
<% if params[:page].to_i == i %>
|
112
|
+
<li class="active"><%= link_to i, page: i, keys_category: @category %></li>
|
113
|
+
<% else %>
|
114
|
+
<li><%= link_to i, page: i, keys_category: @category %></li>
|
115
|
+
<% end %>
|
116
|
+
<% end %>
|
117
|
+
<li>
|
118
|
+
<% unless params[:page].to_i == total_pages(@keys.flatten) %>
|
119
|
+
<%= link_to '»'.html_safe, page: params[:page].to_i + 1, keys_category: @category %>
|
120
|
+
<% end %>
|
121
|
+
</li>
|
122
|
+
</ul>
|
123
|
+
<% end %>
|
124
|
+
</div>
|
125
|
+
</div>
|
126
|
+
</div>
|
127
|
+
</div>
|
128
|
+
|
129
|
+
<!-- Modal -->
|
130
|
+
<div class="modal fade" id="translateModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
|
131
|
+
<div class="modal-dialog" role="document">
|
132
|
+
<div class="modal-content">
|
133
|
+
<div class="modal-header">
|
134
|
+
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
|
135
|
+
<p class="text-left translation-key"></p>
|
136
|
+
<p class="text-left translation-key-path"></p>
|
137
|
+
</div>
|
138
|
+
<div class="modal-body">
|
139
|
+
<%= form_tag kakimasu_keys_path(keys_category: @category), id: 'translation-modal-form', remote: true do %>
|
140
|
+
<p>
|
141
|
+
<%= hidden_field_tag :key %>
|
142
|
+
</p>
|
143
|
+
<p>
|
144
|
+
<%= hidden_field_tag :path %>
|
145
|
+
</p>
|
146
|
+
<% I18n.available_locales.each_with_index do |locale, index| %>
|
147
|
+
<div class="form-group">
|
148
|
+
<div class="row">
|
149
|
+
<div class="col-xs-1">
|
150
|
+
<%= label_tag locale %>
|
151
|
+
</div>
|
152
|
+
<div class="col-xs-7 translation-input">
|
153
|
+
<%= text_area_tag locale, nil, class: "form-control" %>
|
154
|
+
</div>
|
155
|
+
<div class="col-xs-4">
|
156
|
+
<div class="suggested-translation-link">
|
157
|
+
<a href='<%="#modal-translation-#{index}"%>' data-toggle="collapse"><%=t('suggested_translations')%></a>
|
158
|
+
<div id='<%="modal-translation-#{index}"%>' class="collapse suggested-translation">
|
159
|
+
<p></p>
|
160
|
+
</div>
|
161
|
+
</div>
|
162
|
+
</div>
|
163
|
+
</div>
|
164
|
+
</div>
|
165
|
+
<% end %>
|
166
|
+
<% if @category == 'missing_translations' || @category == 'all_translation_keys' %>
|
167
|
+
<div class="row">
|
168
|
+
<div class="col-xs-4 col-xs-offset-1">
|
169
|
+
<div id='lazy-lookup-checkbox'></div>
|
170
|
+
</div>
|
171
|
+
</div>
|
172
|
+
<% end %>
|
173
|
+
<p class="text-right">
|
174
|
+
<%= button_tag(class: "btn btn-primary") do%>
|
175
|
+
<% t('save') %>
|
176
|
+
<% end %>
|
177
|
+
</p>
|
178
|
+
<% end %>
|
179
|
+
</div>
|
180
|
+
</div>
|
181
|
+
</div>
|
182
|
+
</div>
|
183
|
+
</div>
|