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,18 @@
|
|
1
|
+
module Kakimasu
|
2
|
+
module Generators
|
3
|
+
class PolicyGenerator < Rails::Generators::Base
|
4
|
+
puts "Generating Policy for you ..."
|
5
|
+
# Sets root for more compact file copying
|
6
|
+
source_root File.expand_path("../../../../app/policies", __FILE__)
|
7
|
+
|
8
|
+
# Copy policies for ability to edit them
|
9
|
+
def copy_policies
|
10
|
+
copy_file 'translation_policy.rb', 'app/policies/translations_policy.rb'
|
11
|
+
puts ''
|
12
|
+
puts '***********************************'
|
13
|
+
puts 'Policies was successfully generated!' # Success message
|
14
|
+
puts '***********************************'
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
module Kakimasu
|
2
|
+
module Generators
|
3
|
+
class RestoreBackupGenerator < Rails::Generators::Base
|
4
|
+
backup_file = '.kakimasu_backup.yml'
|
5
|
+
|
6
|
+
# Checks if there is backup file
|
7
|
+
unless File.file?(backup_file)
|
8
|
+
puts '**************************'
|
9
|
+
puts "Backup file can't be found"
|
10
|
+
puts '**************************'
|
11
|
+
|
12
|
+
else
|
13
|
+
# Reads content of backup file
|
14
|
+
backup_file_content = File.read(backup_file)
|
15
|
+
|
16
|
+
locale = nil # Used to store locale for a temporary time
|
17
|
+
key_parts = [] # Used to store parts of the 'lazy lookup' key, to at the end join them in one key
|
18
|
+
lazy_lookup = false # Determines if key is lazy lookup
|
19
|
+
|
20
|
+
# Read backup file by lines
|
21
|
+
backup_file_content.each_line do |line|
|
22
|
+
|
23
|
+
# Every line with translation starts with spaces
|
24
|
+
if line.start_with?(' ')
|
25
|
+
# Gets level of the key and gets translation
|
26
|
+
|
27
|
+
# Check if it is first level key
|
28
|
+
if line.match /^\s\s[\w]+[:]\s["][^"]+["]/
|
29
|
+
# Get translation key and translation from the line
|
30
|
+
translation_key = line.scan(/^\s\s([\w]+)[:]\s["][^"]+["]/).first.first
|
31
|
+
translation = line.scan(/^\s\s[\w]+[:]\s["]([^"]+)["]/).first.first
|
32
|
+
|
33
|
+
# empty 'lazy lookup' key parts array because this means that lazy lookup key is done even if there was no translation (That means it has no translation)
|
34
|
+
key_parts = []
|
35
|
+
lazy_lookup = false
|
36
|
+
|
37
|
+
# If its not first level translation, then it means that this is 'lazy lookup' translation
|
38
|
+
else
|
39
|
+
lazy_lookup = true
|
40
|
+
|
41
|
+
# If line has no translation, just key, then it is part of 'lazy lookup' key
|
42
|
+
if line.match /\w+[:]$/
|
43
|
+
key_parts.push line.scan(/(\w+)[:]$/).first.first # Gets 'lazy lookup' key part from the line and pushes it into array
|
44
|
+
|
45
|
+
# If key has translation then it is last part of 'lazy lookup' key
|
46
|
+
elsif line.match /\w+[:]\s["]([^"]+)["]/
|
47
|
+
# Gets 'lazy lookup' keys last part and gets translation
|
48
|
+
key_parts.push line.scan(/(\w+)[:]\s["][^"]+["]/).first.first
|
49
|
+
translation = line.scan(/\w+[:]\s["]([^"]+)["]/).first.first
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# lines with no spaces in start is just for locales or blank lines
|
54
|
+
else
|
55
|
+
# If line is not meant as blank line, then it's locale and function gets locale from it
|
56
|
+
locale = line.partition(':').first unless line.start_with?("\n")
|
57
|
+
end
|
58
|
+
|
59
|
+
# If 'lazy lookup' key then save it as 'lazy lookup' key otherwise save it like not 'lazy lookup key'
|
60
|
+
if lazy_lookup && translation
|
61
|
+
# Form 'lazy lookup' key
|
62
|
+
translation_key = key_parts.join('.')
|
63
|
+
|
64
|
+
# Store translation
|
65
|
+
I18n.backend.store_translations(locale, {translation_key => translation}, escape: false)
|
66
|
+
|
67
|
+
# Set back variables
|
68
|
+
key_parts = []
|
69
|
+
translation = nil
|
70
|
+
translation_key = nil
|
71
|
+
|
72
|
+
elsif translation_key && translation
|
73
|
+
# Store translation
|
74
|
+
I18n.backend.store_translations(locale, {translation_key => translation}, escape: false)
|
75
|
+
|
76
|
+
# Set back variables
|
77
|
+
translation = nil
|
78
|
+
translation_key = nil
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
# Message about successfull translation restore from backup file
|
83
|
+
puts '***********************************'
|
84
|
+
puts 'Translations successfully restored!'
|
85
|
+
puts '***********************************'
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Kakimasu
|
2
|
+
module Generators
|
3
|
+
class ViewsGenerator < Rails::Generators::Base
|
4
|
+
puts "Creating views for you ..."
|
5
|
+
# Sets root for more compact file copying
|
6
|
+
source_root File.expand_path("../../../../app/views/kakimasu", __FILE__)
|
7
|
+
|
8
|
+
# Copy all views to project folder for ability to edit them
|
9
|
+
def copy_views
|
10
|
+
copy_file "home/index.html.erb", "app/views/kakimasu/home/index.html.erb"
|
11
|
+
copy_file "keys/index.html.erb", "app/views/kakimasu/keys/index.html.erb"
|
12
|
+
copy_file "translations/index.html.erb", "app/views/kakimasu/translations/index.html.erb"
|
13
|
+
copy_file "translations/edit.html.erb", "app/views/kakimasu/translations/edit.html.erb"
|
14
|
+
copy_file "shared/_navbar.html.erb", "app/views/kakimasu/shared/_navbar.html.erb"
|
15
|
+
puts ''
|
16
|
+
puts '***********************************'
|
17
|
+
puts 'Views was successfully generated!' # Success message
|
18
|
+
puts '***********************************'
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/lib/kakimasu.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'kakimasu/version'
|
2
|
+
require 'kakimasu/engine'
|
3
|
+
|
4
|
+
module Kakimasu
|
5
|
+
# Turn of 'translation mode' mechanism
|
6
|
+
def set_show_translation_key
|
7
|
+
Thread.current[:show_translation_key] = nil
|
8
|
+
return unless current_user.try(:admin?)
|
9
|
+
Thread.current[:show_translation_key] = (params[:show_translation_key] == 'true').presence
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
class Kakimasu.TranslationModal
|
2
|
+
constructor: (el) ->
|
3
|
+
@$el = $(el)
|
4
|
+
@delegateEvents()
|
5
|
+
|
6
|
+
delegateEvents: ->
|
7
|
+
@$el.on 'click', '.translate-key-button', $.proxy(@fillModal, @)
|
8
|
+
|
9
|
+
fillModal: (e) ->
|
10
|
+
$chosenKey = $(e.currentTarget)
|
11
|
+
$('#translation-modal-form #key').val($chosenKey.data('key'))
|
12
|
+
$('#translation-modal-form #path').val($chosenKey.data('path'))
|
13
|
+
|
14
|
+
$('.translation-key').text $chosenKey.data('key')
|
15
|
+
$('.translation-key-path').text "( #{$chosenKey.data('path')} )"
|
16
|
+
|
17
|
+
html = ''
|
18
|
+
html += '<p id="lazy-lookup-checkbox-tag">'
|
19
|
+
html += '<label for="Unique">Unique</label>'
|
20
|
+
html += '<input type="checkbox" name="lazy_lookup" id="lazy_lookup" value="1"'
|
21
|
+
if $chosenKey.data('unique')
|
22
|
+
html += 'checked="checked"'
|
23
|
+
html += '>'
|
24
|
+
html += '</p>'
|
25
|
+
$('#lazy-lookup-checkbox-tag').remove()
|
26
|
+
$('#translation-modal-form #lazy-lookup-checkbox').append html
|
27
|
+
|
28
|
+
translations = $chosenKey.data('translations')
|
29
|
+
locales = $chosenKey.data('locales')
|
30
|
+
|
31
|
+
for l, index in locales
|
32
|
+
translation = translations[index]
|
33
|
+
translation = translation.replace /\u0026#39;/g, "'"
|
34
|
+
$("#translation-modal-form ##{l}").val('')
|
35
|
+
if translation
|
36
|
+
unless translation.match /<span.*<\/span>/
|
37
|
+
$("#translation-modal-form ##{l}").val(translation)
|
38
|
+
$("#translation-modal-form ##{l}").attr('name', l)
|
39
|
+
$("#translation-modal-form ##{l}").attr('value', translation)
|
40
|
+
else
|
41
|
+
if translation.match /<span class='(translation-with-key).*<\/span>/
|
42
|
+
match = /<span.*>(.*)<\/span>/i.exec translation
|
43
|
+
$("#translation-modal-form ##{l}").val(match[1])
|
44
|
+
$("#translation-modal-form ##{l}").attr('name', l)
|
45
|
+
$("#translation-modal-form ##{l}").attr('value', match[1])
|
46
|
+
|
47
|
+
# Closes collapse element if it is open
|
48
|
+
$('.collapse').removeClass('in')
|
@@ -0,0 +1,93 @@
|
|
1
|
+
$(document).on 'click', '.suggested-translation-link', () ->
|
2
|
+
form = $(this).parent().parent().parent().parent() # Get form
|
3
|
+
|
4
|
+
# Get target language, and also check if there is textare or just input
|
5
|
+
if $(this).parent().parent().children('.translation-input').children('input').attr('name')
|
6
|
+
targetLanguage = $(this).parent().parent().children('.translation-input').children('input').attr('name')
|
7
|
+
else
|
8
|
+
targetLanguage = $(this).parent().parent().children('.translation-input').children('textarea').attr('name')
|
9
|
+
|
10
|
+
numberOfLanguages = form.children('.form-group').length # Get number of all languages
|
11
|
+
|
12
|
+
# Will be used if there is no translation for the key in other languages but there is translation for the key in this language
|
13
|
+
hasTranslation = false
|
14
|
+
|
15
|
+
# Get source language and translatable string (first language with translation which is not target language)
|
16
|
+
for i in [0...numberOfLanguages]
|
17
|
+
formGroup = form.children('.form-group').eq(i)
|
18
|
+
# Determines if there ir textarea or input field
|
19
|
+
if formGroup.children().eq(0).children('.translation-input').children('textarea').val()
|
20
|
+
value = formGroup.children().eq(0).children('.translation-input').children('textarea').val()
|
21
|
+
language = formGroup.children().eq(0).children('.translation-input').children('textarea').attr('name')
|
22
|
+
else
|
23
|
+
value = formGroup.children().eq(0).children('.translation-input').children('input').val()
|
24
|
+
language = formGroup.children().eq(0).children('.translation-input').children('input').attr('name')
|
25
|
+
|
26
|
+
# If there is translation for key in language that is not target language then it will be translatable string
|
27
|
+
if value && language != targetLanguage
|
28
|
+
sourceLanguage = language
|
29
|
+
translatableString = value
|
30
|
+
break
|
31
|
+
# In case if there is no other language with translation and this language has translation then this will be displayed translation
|
32
|
+
if value && language == targetLanguage
|
33
|
+
hasTranslation = true
|
34
|
+
result = value
|
35
|
+
|
36
|
+
# Alert user if there is nothing to get translation from
|
37
|
+
alert 'There is no word to translate. Please fill at least one translation.' unless translatableString || hasTranslation
|
38
|
+
|
39
|
+
# Check for internet connection, if there is no connection then alert user
|
40
|
+
unless navigator.onLine
|
41
|
+
alert 'Unable to connect google translate service. Please make sure that you are connected to the internet!'
|
42
|
+
else
|
43
|
+
if translatableString
|
44
|
+
# Regular expression for searching punctuation marks
|
45
|
+
regex = /[^\.!\?]+[\.!\?]+/g
|
46
|
+
|
47
|
+
# If translatable string includes many sentences then every sentence should be translated independently
|
48
|
+
if regex.test(translatableString)
|
49
|
+
sentences = translatableString.match( regex )
|
50
|
+
|
51
|
+
# Array for translation storage
|
52
|
+
translation = []
|
53
|
+
|
54
|
+
# Translate every sentence independently
|
55
|
+
for sentence in sentences
|
56
|
+
# Google translate API url
|
57
|
+
url = "https://translate.googleapis.com/translate_a/single?client=gtx"
|
58
|
+
url += "&sl=" + sourceLanguage
|
59
|
+
url += "&tl=" + targetLanguage
|
60
|
+
url += "&dt=t&q=" + encodeURI(sentence)
|
61
|
+
|
62
|
+
# HTTP GET request for translation
|
63
|
+
xmlHttp = new XMLHttpRequest()
|
64
|
+
xmlHttp.open( "GET", url, false )
|
65
|
+
xmlHttp.send( null )
|
66
|
+
|
67
|
+
# Parse API response to JSON
|
68
|
+
response = JSON.parse(xmlHttp.responseText)
|
69
|
+
|
70
|
+
# Get suggested translation
|
71
|
+
translation.push response[0][0][0]
|
72
|
+
|
73
|
+
result = translation.join(' ')
|
74
|
+
|
75
|
+
# If translatable string is just one sentence then it can be translated directly
|
76
|
+
else
|
77
|
+
# Google translate API url
|
78
|
+
url = "https://translate.googleapis.com/translate_a/single?client=gtx"
|
79
|
+
url += "&sl=" + sourceLanguage
|
80
|
+
url += "&tl=" + targetLanguage
|
81
|
+
url += "&dt=t&q=" + encodeURI(translatableString)
|
82
|
+
|
83
|
+
# HTTP GET request for translation
|
84
|
+
xmlHttp = new XMLHttpRequest()
|
85
|
+
xmlHttp.open( "GET", url, false )
|
86
|
+
xmlHttp.send( null )
|
87
|
+
|
88
|
+
# Get translation
|
89
|
+
response = JSON.parse(xmlHttp.responseText)
|
90
|
+
result = response[0][0][0]
|
91
|
+
|
92
|
+
# Show suggested translation to user
|
93
|
+
$(this).children('.suggested-translation').children('p').text result
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class Kakimasu.TranslationNavigation
|
2
|
+
constructor: (el) ->
|
3
|
+
@$el = $(el)
|
4
|
+
@delegateEvents()
|
5
|
+
|
6
|
+
delegateEvents: ->
|
7
|
+
@$el.on 'click', 'li', $.proxy(@changeActiveListItem, @)
|
8
|
+
|
9
|
+
changeActiveListItem: (e) ->
|
10
|
+
$chosenItem = $(e.currentTarget)
|
11
|
+
|
12
|
+
$('.kakimasu-navigation .active').removeClass('active')
|
13
|
+
$chosenItem.addClass('active')
|
@@ -0,0 +1,39 @@
|
|
1
|
+
class Kakimasu.TranslationPercentChart
|
2
|
+
constructor: (el) ->
|
3
|
+
# Get translation percentage from the view
|
4
|
+
percentage = $('.translation-percentage').data('value')
|
5
|
+
|
6
|
+
# Set chart and text color
|
7
|
+
if percentage <= 25
|
8
|
+
chartColor = '#8B0000'
|
9
|
+
textColor = '#4D0000'
|
10
|
+
else if percentage <= 50 && percentage > 25
|
11
|
+
chartColor = '#FF0000'
|
12
|
+
textColor = '#B30000'
|
13
|
+
else if percentage <=75 && percentage > 50
|
14
|
+
chartColor = '#FFA500'
|
15
|
+
textColor = '#B37400'
|
16
|
+
else if percentage <= 90 && percentage > 75
|
17
|
+
chartColor = '#808000'
|
18
|
+
textColor = '#808000'
|
19
|
+
else if percentage <= 99 && percentage > 90
|
20
|
+
chartColor = '#6B8E23'
|
21
|
+
textColor = '#3D5214'
|
22
|
+
else
|
23
|
+
chartColor = '#008000'
|
24
|
+
textColor = '#003300'
|
25
|
+
|
26
|
+
# translation percentage circle diagram
|
27
|
+
$('#translation-percentage-circle').circliful
|
28
|
+
animation: 1
|
29
|
+
animationStep: 2
|
30
|
+
start: 2
|
31
|
+
showPercent: 1
|
32
|
+
percent: percentage
|
33
|
+
backgroundColor: '#666666'
|
34
|
+
foregroundColor: chartColor
|
35
|
+
fontColor: textColor
|
36
|
+
multiPercentage: 1
|
37
|
+
foregroundBorderWidth: 15
|
38
|
+
backgroundBorderWidth: 1
|
39
|
+
percentageY: 105
|
@@ -0,0 +1,90 @@
|
|
1
|
+
class Kakimasu.TranslationPopover
|
2
|
+
constructor: (el) ->
|
3
|
+
@$el = $(el)
|
4
|
+
@delegateEvents()
|
5
|
+
|
6
|
+
delegateEvents: ->
|
7
|
+
@$el.on 'mouseenter', $.proxy(@showPopover, @)
|
8
|
+
|
9
|
+
showPopover: (e) ->
|
10
|
+
$translation = $(e.currentTarget)
|
11
|
+
|
12
|
+
token = $('meta[name="csrf-token"]').attr('content')
|
13
|
+
url_params = window.location.search
|
14
|
+
key = $translation.data('content')
|
15
|
+
translations = $translation.data('translations')
|
16
|
+
|
17
|
+
#determine available locales
|
18
|
+
locales = $translation.data('locales')
|
19
|
+
locales = locales.split /\W+/
|
20
|
+
locales.shift()
|
21
|
+
locales.pop()
|
22
|
+
|
23
|
+
html = '<div class="popover translation-popover">'
|
24
|
+
html += '<div class="close">'
|
25
|
+
html += '<p>×</p>'
|
26
|
+
html += '</div>'
|
27
|
+
html += '<form action="/kakimasu/translations'
|
28
|
+
html += url_params
|
29
|
+
html += '" data-remote="true" method="post">'
|
30
|
+
html += '<input type="hidden" name="authenticity_token" '
|
31
|
+
html += 'value='
|
32
|
+
html += token
|
33
|
+
html += '>'
|
34
|
+
html += '<input type="hidden" name="key" id="translation-key" value='
|
35
|
+
html += key
|
36
|
+
html += '>'
|
37
|
+
html += '<div class="translation-key">'
|
38
|
+
html += key
|
39
|
+
html += '</div>'
|
40
|
+
for l, index in locales
|
41
|
+
html += '<div class="form-group">'
|
42
|
+
html += '<div class="row">'
|
43
|
+
html += '<div class="col-xs-2">'
|
44
|
+
html += "<label for='locale'>#{l}</label>"
|
45
|
+
html += '</div>'
|
46
|
+
html += '<div class="col-xs-10 translation-input">'
|
47
|
+
field_value = translations[index].replace /"/g, '"'
|
48
|
+
field_value = '"' + field_value + '"'
|
49
|
+
html += "<input class='form-control' type='text' name='#{l}' id='value' value=#{field_value} >"
|
50
|
+
html += '</div>'
|
51
|
+
html += '<div class="col-xs-10 col-xs-offset-2">'
|
52
|
+
html += "<div class='suggested-translation-link'>"
|
53
|
+
html += "<a href='#popover-translation-#{index}' data-toggle='collapse'>"
|
54
|
+
html += 'suggested translations'
|
55
|
+
html += '</a>'
|
56
|
+
html += "<div id='popover-translation-#{index}' class='collapse suggested-translation'>"
|
57
|
+
html += '<p></p>'
|
58
|
+
html += '</div>'
|
59
|
+
html += '</div>'
|
60
|
+
html += '</div>'
|
61
|
+
html += '</div>'
|
62
|
+
html += '</div>'
|
63
|
+
if $translation.data('unique')
|
64
|
+
html += '<p>'
|
65
|
+
html += '<label for="Unique">Unique</label>'
|
66
|
+
html += '<input type="checkbox" name="lazy_lookup" id="lazy_lookup" value="1"'
|
67
|
+
html += 'checked="checked"'
|
68
|
+
html += 'disabled'
|
69
|
+
html += '>'
|
70
|
+
html += '</p>'
|
71
|
+
html += '<p class="text-right">'
|
72
|
+
html += '<input type="submit" name="commit" value="Save" class="btn btn-primary">'
|
73
|
+
html += '</p>'
|
74
|
+
html += '</form>'
|
75
|
+
html += '</div>'
|
76
|
+
|
77
|
+
$translation.popover
|
78
|
+
container: 'body'
|
79
|
+
template: html
|
80
|
+
|
81
|
+
$('.popover').remove()
|
82
|
+
$('.translation-with-key').css 'background-color', '#FFCCCC'
|
83
|
+
$('.translation_missing').css 'background-color', '#FF6666'
|
84
|
+
$translation.popover('show')
|
85
|
+
$translation.css 'background-color', '#990000'
|
86
|
+
|
87
|
+
$('.close').on 'click', ->
|
88
|
+
$(this).closest('.popover').hide()
|
89
|
+
$('.translation-with-key').css 'background-color', '#FFCCCC'
|
90
|
+
$('.translation_missing').css 'background-color', '#FF6666'
|