couch_i18n 0.2.0 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- data/app/assets/javascripts/couch_i18n/application.js +2 -1
- data/app/assets/javascripts/couch_i18n/structure.js +1 -0
- data/app/assets/stylesheets/couch_i18n/application.css +2 -2
- data/app/assets/stylesheets/couch_i18n/bootstrap_and_override.css.less +5 -0
- data/app/assets/stylesheets/couch_i18n/structure.css.scss +15 -10
- data/app/controllers/couch_i18n/application_controller.rb +3 -1
- data/app/models/couch_i18n/translation.rb +4 -4
- data/app/models/couch_i18n/translation.rb~ +77 -0
- data/app/views/couch_i18n/translations/_form.html.haml +14 -11
- data/app/views/couch_i18n/translations/edit.html.haml +1 -1
- data/app/views/couch_i18n/translations/index.html.haml +39 -23
- data/app/views/layouts/couch_i18n/application.html.haml +21 -2
- data/config/locales/couch_i18n.en.yml +10 -3
- metadata +4 -2
@@ -3,5 +3,5 @@
|
|
3
3
|
* and any sub-directories. You're free to add application-wide styles to this file and they'll appear at
|
4
4
|
* the top of the compiled file, but it's generally better to create a new file per style scope.
|
5
5
|
*= require_self
|
6
|
-
*=
|
7
|
-
*/
|
6
|
+
*= require_directory .
|
7
|
+
*/
|
@@ -1,16 +1,13 @@
|
|
1
1
|
html, body{
|
2
|
-
margin: 0;
|
3
|
-
padding: 0;
|
4
2
|
}
|
5
3
|
body{
|
6
|
-
background-color: #ddf;
|
7
4
|
}
|
8
5
|
h1, h2, h3, h4, h5, h6{
|
9
|
-
margin: 0;
|
10
|
-
padding: 0;
|
11
6
|
}
|
12
7
|
h1{
|
13
|
-
|
8
|
+
}
|
9
|
+
form{
|
10
|
+
margin-bottom: 0; /* bootstrap fix */
|
14
11
|
}
|
15
12
|
#page-wrapper{
|
16
13
|
width: 922px;
|
@@ -34,9 +31,6 @@ h1{
|
|
34
31
|
}
|
35
32
|
}
|
36
33
|
}
|
37
|
-
tr.even{
|
38
|
-
background-color: #ddf;
|
39
|
-
}
|
40
34
|
#page-links{
|
41
35
|
margin-top: 8px;
|
42
36
|
margin-bottom: 8px;
|
@@ -49,7 +43,9 @@ tr.even{
|
|
49
43
|
}
|
50
44
|
}
|
51
45
|
}
|
52
|
-
|
46
|
+
.untranslated-label{
|
47
|
+
display: inline;
|
48
|
+
}
|
53
49
|
.offset-navigation-block{
|
54
50
|
border-style: double;
|
55
51
|
border-color: #444;
|
@@ -77,3 +73,12 @@ tr.even{
|
|
77
73
|
.clearing{
|
78
74
|
clear: both;
|
79
75
|
}
|
76
|
+
|
77
|
+
.pagination{
|
78
|
+
ul{
|
79
|
+
list-style: none;
|
80
|
+
li{
|
81
|
+
float: left;
|
82
|
+
}
|
83
|
+
}
|
84
|
+
}
|
@@ -6,7 +6,9 @@ module CouchI18n
|
|
6
6
|
private
|
7
7
|
|
8
8
|
def authorize_user
|
9
|
-
if respond_to?(:
|
9
|
+
if respond_to?(:authorize_couch_i18n)
|
10
|
+
authorize_couch_i18n
|
11
|
+
elsif respond_to?(:current_user) && current_user.present? && current_user.respond_to?(:is_admin) && !current_user.is_admin.present?
|
10
12
|
redirect_to '/', :alert => I18n.t('couch_i18n.general.not_authorized')
|
11
13
|
end
|
12
14
|
end
|
@@ -18,7 +18,7 @@ module CouchI18n
|
|
18
18
|
if(doc.ruby_class && doc.ruby_class == 'CouchI18n::Translation') {
|
19
19
|
emit(doc.key.split('.').slice(0, -1), 1);
|
20
20
|
}
|
21
|
-
}|, type: :raw, reduce_function:
|
21
|
+
}|, type: :raw, reduce_function: '_sum'
|
22
22
|
|
23
23
|
view :untranslated_view, key: :key, conditions: "!doc['translated']"
|
24
24
|
view :by_value, key: :value
|
@@ -69,9 +69,9 @@ module CouchI18n
|
|
69
69
|
|
70
70
|
# Expire I18n when record is update
|
71
71
|
def reload_i18n
|
72
|
-
Rails.cache.write(key, value)
|
73
|
-
I18n.reload!
|
74
|
-
I18n.cache_store.clear if I18n.respond_to?(:cache_store) && I18n.cache_store.respond_to?(:clear)
|
72
|
+
Rails.cache.write("couch_i18n-#{key}", value)
|
73
|
+
#I18n.reload!
|
74
|
+
#I18n.cache_store.clear if I18n.respond_to?(:cache_store) && I18n.cache_store.respond_to?(:clear)
|
75
75
|
end
|
76
76
|
end
|
77
77
|
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module CouchI18n
|
2
|
+
class Translation
|
3
|
+
include SimplyStored::Couch
|
4
|
+
per_page_method :limit_value
|
5
|
+
|
6
|
+
property :key
|
7
|
+
property :value
|
8
|
+
property :translated, type: :boolean, default: true
|
9
|
+
|
10
|
+
validates_uniqueness_of :key
|
11
|
+
|
12
|
+
after_save :reload_i18n
|
13
|
+
|
14
|
+
view :all_documents, :key => :key
|
15
|
+
view :by_key, :key => :key
|
16
|
+
|
17
|
+
view :with_key_array, map_function: %|function(doc){
|
18
|
+
if(doc.ruby_class && doc.ruby_class == 'CouchI18n::Translation') {
|
19
|
+
emit(doc.key.split('.').slice(0, -1), 1);
|
20
|
+
}
|
21
|
+
}|, type: :raw, reduce_function: '_sum'
|
22
|
+
|
23
|
+
view :untranslated_view, key: :key, conditions: "!doc['translated']"
|
24
|
+
view :by_value, key: :value
|
25
|
+
view :by_key_part, type: :custom, map_function: %|function(doc){
|
26
|
+
if(doc.ruby_class && doc.ruby_class == 'CouchI18n::Translation') {
|
27
|
+
var parts = doc.key.split('.');
|
28
|
+
for(var i = 0; i < parts.length; i++){
|
29
|
+
emit(parts[i], 1);
|
30
|
+
}
|
31
|
+
}
|
32
|
+
}|, reduce_function: '_count'
|
33
|
+
|
34
|
+
def self.get_keys_by_level(level = 0, options = {})
|
35
|
+
data = database.view(with_key_array(options.merge(:group_level => level.succ)))["rows"]
|
36
|
+
# data = data.select{|h| h["key"].size > level } # Only select ones that have a deeper nesting
|
37
|
+
data.map{|h| h['key'][level].try(:to_sym)}.compact
|
38
|
+
end
|
39
|
+
|
40
|
+
# Shorthand for selecting all stored with a given offset
|
41
|
+
def self.with_offset(offset, options = {})
|
42
|
+
CouchI18n::Translation.find_all_by_key("#{offset}.".."#{offset}.ZZZZZZZZZ", options)
|
43
|
+
end
|
44
|
+
|
45
|
+
# Find all records having the term part in their key
|
46
|
+
# nl.action.one
|
47
|
+
# en.action.two
|
48
|
+
# en.activemodel.plural.models.user
|
49
|
+
# and using
|
50
|
+
# find_all_by_part('action')
|
51
|
+
# will return the first two since they have action as key part
|
52
|
+
def self.find_all_by_key_part(part, options = {})
|
53
|
+
total_entries = database.view(by_key_part(key: part, reduce: true))
|
54
|
+
with_pagination_options options.merge(total_entries: total_entries) do |options|
|
55
|
+
database.view(by_key_part(options.merge(key: part, reduce: false, include_docs: true)))
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.untranslated(options = {})
|
60
|
+
total_entries = database.view(untranslated_view(options.select{|k,v| [:key, :keys, :startkey, :endkey].include?(k)}.merge(reduce: true)))
|
61
|
+
with_pagination_options options.merge(total_entries: total_entries) do |options|
|
62
|
+
database.view(untranslated_view(options))
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def self.untranslated_with_offset(offset, options = {})
|
67
|
+
CouchI18n::Translation.untranslated(options.merge(key: "#{offset}.".."#{offset}.ZZZZZZZZZ"))
|
68
|
+
end
|
69
|
+
|
70
|
+
# Expire I18n when record is update
|
71
|
+
def reload_i18n
|
72
|
+
Rails.cache.write(key, value)
|
73
|
+
I18n.reload!
|
74
|
+
I18n.cache_store.clear if I18n.respond_to?(:cache_store) && I18n.cache_store.respond_to?(:clear)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -1,13 +1,16 @@
|
|
1
|
-
= form_for @translation do |f|
|
1
|
+
= form_for @translation, html: {class: 'form-horizontal'} do |f|
|
2
2
|
= render 'error_messages', :target => @translation
|
3
|
-
.
|
4
|
-
= f.label :key
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
= f.
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
3
|
+
.control-group
|
4
|
+
= f.label :key, class: 'control-label'
|
5
|
+
.controls
|
6
|
+
= f.text_field :key, :size => 70, class: 'input-xxlarge'
|
7
|
+
.control-group
|
8
|
+
= f.label :value, class: 'control-label'
|
9
|
+
.controls
|
10
|
+
= f.text_field :value, :size => 70, class: 'input-xxlarge'
|
11
|
+
.control-group
|
12
|
+
= label_tag :is_json, t('couch_i18n.general.is_json'), class: 'control-label'
|
13
|
+
.controls
|
14
|
+
= check_box_tag :is_json, 1, f.object.value.to_s =~ /^\{|^\[/
|
15
|
+
.form-actions
|
13
16
|
= f.submit @submit || update_button_text
|
@@ -1,4 +1,4 @@
|
|
1
|
-
- title t("couch_i18n.action
|
1
|
+
- title t("couch_i18n.action.edit.title")
|
2
2
|
= render 'form'
|
3
3
|
- content_for :page_links do
|
4
4
|
= link_to link_to_index_content(:translations), couch_i18n.translations_path(:offset => params[:offset] || @translation.key.to_s.sub(/\.[\w\s-]+$/, ''))
|
@@ -2,26 +2,42 @@
|
|
2
2
|
- title params[:offset]
|
3
3
|
- else
|
4
4
|
- title t("couch_i18n.action.index.title")
|
5
|
-
|
6
|
-
|
7
|
-
.
|
5
|
+
- content_for :navbar do
|
6
|
+
%a.btn.btn-warning{data: {toggle: "modal"}, href: ".import-form"}= t('couch_i18n.import.label')
|
7
|
+
%a.btn.btn-success{data: {toggle: "modal"}, href: ".export-form"}= t('couch_i18n.export.label')
|
8
|
+
.pull-right
|
9
|
+
= link_to t('couch_i18n.action.destroy.offset_link'), couch_i18n.destroy_offset_translations_path(:offset => params[:offset]), :method => :delete, :confirm => (defined?(:are_you_sure) ? are_you_sure : t('couch_i18n.general.are_you_sure')), class: [:btn, 'btn-danger']
|
10
|
+
|
11
|
+
.modal.hide.import-form
|
8
12
|
= form_tag({:action => :import}, :multipart => true) do
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
.
|
13
|
+
.modal-header
|
14
|
+
%h3= t('couch_i18n.import.label')
|
15
|
+
.modal-body
|
16
|
+
%p= t('couch_i18n.import.description')
|
17
|
+
= file_field_tag :importfile
|
18
|
+
.modal-footer
|
19
|
+
%a.btn{data: {dismiss: :modal}, href: '#'}= t('couch_i18n.general.close')
|
20
|
+
= submit_tag I18n.t('couch_i18n.import.button')
|
21
|
+
.modal.hide.export-form
|
13
22
|
= form_tag :action => :export do
|
14
23
|
= hidden_field_tag :offset, params[:offset]
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
24
|
+
.modal-header
|
25
|
+
- if params[:offset].present?
|
26
|
+
%h3= t('couch_i18n.export.from_offset', offset: params[:offset])
|
27
|
+
- else
|
28
|
+
%h3= t('couch_i18n.export.label')
|
29
|
+
.modal-body
|
30
|
+
= select_tag :exportformat, options_for_select(%w[yml csv json], params[:exportformat])
|
31
|
+
= check_box_tag :untranslated
|
32
|
+
= label_tag :untranslated, t('couch_i18n.export.untranslated'), class: 'untranslated-label'
|
33
|
+
.modal-footer
|
34
|
+
%a.btn{data: {dismiss: :modal}, href: '#'}= t('couch_i18n.general.close')
|
35
|
+
= submit_tag I18n.t('couch_i18n.export.execute')
|
20
36
|
.offset-navigation-block.block
|
21
|
-
.
|
37
|
+
.btn-toolbar
|
22
38
|
- for offset in @available_higher_offsets
|
23
|
-
|
24
|
-
|
39
|
+
.btn-group
|
40
|
+
= link_to offset[:name], {:offset => offset[:offset], untranslated: params[:untranslated]}, class: :btn
|
25
41
|
.offset-navigation-form
|
26
42
|
= form_tag({}, :method => :get )do
|
27
43
|
- if params[:offset].present?
|
@@ -31,15 +47,15 @@
|
|
31
47
|
%input{:type => :submit, :name => :commit, :value => I18n.t('couch_i18n.general.go_to_offset')}
|
32
48
|
%input{:type => :submit, :name => :partfinder, :value => I18n.t('couch_i18n.general.find_part')}
|
33
49
|
%input{:type => :submit, :name => :valuefinder, :value => I18n.t('couch_i18n.general.find_value')}
|
34
|
-
= check_box_tag :untranslated, 1, untranslated
|
35
|
-
= label_tag :
|
36
|
-
.
|
50
|
+
= check_box_tag :untranslated, 1, untranslated?, id: :untranslated_listing
|
51
|
+
= label_tag :untranslated_listing, I18n.t('couch_i18n.general.untranslated_label'), class: 'untranslated-label'
|
52
|
+
.btn-toolbar
|
37
53
|
- for offset in @available_deeper_offsets
|
38
|
-
|
39
|
-
|
54
|
+
.btn-group
|
55
|
+
= link_to(offset[:name], {:offset => offset[:offset], untranslated: params[:untranslated]}, class: :btn)
|
40
56
|
- if @translations.any?
|
41
57
|
= paginate @translations, :right => 3, :left => 3
|
42
|
-
%table.
|
58
|
+
%table.table.table-striped
|
43
59
|
%thead
|
44
60
|
%tr
|
45
61
|
%th= CouchI18n::Translation.human_attribute_name(:key)
|
@@ -57,8 +73,8 @@
|
|
57
73
|
= link_to translation.key[(params[:offset].try(:size) || 0)..-1].sub(/^\./, ''), couch_i18n.edit_translation_path(translation)
|
58
74
|
%td= link_to translation.value, couch_i18n.edit_translation_path(translation)
|
59
75
|
%td.boolean= boolean_show(translation.translated)
|
60
|
-
%td.action.edit= link_to link_to_edit_content(translation), couch_i18n.edit_translation_path(translation)
|
61
|
-
%td.action.destroy= link_to link_to_destroy_content(translation),couch_i18n.translation_path(translation), :confirm => are_you_sure, :method => :delete
|
76
|
+
%td.action.edit= link_to link_to_edit_content(translation), couch_i18n.edit_translation_path(translation), class: [:btn]
|
77
|
+
%td.action.destroy= link_to link_to_destroy_content(translation),couch_i18n.translation_path(translation), :confirm => are_you_sure, :method => :delete, class: [:btn, 'btn-danger']
|
62
78
|
- else
|
63
79
|
%h3= t("couch_i18n.general.none_found")
|
64
80
|
|
@@ -2,12 +2,31 @@
|
|
2
2
|
%html
|
3
3
|
%head
|
4
4
|
%title= defined?(site_title) ? site_title : I18n.t('couch_i18n.general.site_title')
|
5
|
-
|
5
|
+
/[if lt IE 9]
|
6
|
+
<script src="http://html5shim.googlecode.com/svn/trunk/html5.js" type="text/javascript"></script>
|
7
|
+
= csrf_meta_tags
|
6
8
|
= stylesheet_link_tag 'couch_i18n/application'
|
7
9
|
= javascript_include_tag 'couch_i18n/application'
|
10
|
+
%meta{:name => "viewport", :content => "width=device-width, initial-scale=1.0"}
|
8
11
|
= yield :head
|
9
12
|
%body
|
10
|
-
|
13
|
+
.navbar.navbar-fixed-top
|
14
|
+
.navbar-inner
|
15
|
+
.container
|
16
|
+
%a.btn.btn-navbar{data: {toggle: "collapse", target: ".nav-collapse"}}
|
17
|
+
%span.icon-bar
|
18
|
+
%span.icon-bar
|
19
|
+
%span.icon-bar
|
20
|
+
%a.brand{href: couch_i18n.root_path}= yield :title
|
21
|
+
-#.nav-collapse
|
22
|
+
%ul.nav
|
23
|
+
%li= link_to 'Clear', couch_i18n.root_path
|
24
|
+
= yield :navbar
|
25
|
+
.container
|
26
|
+
= render 'alerts'
|
27
|
+
= yield
|
28
|
+
|
29
|
+
-#page-wrapper
|
11
30
|
#page-header
|
12
31
|
%h1= yield :title
|
13
32
|
#page-content
|
@@ -4,11 +4,11 @@ en:
|
|
4
4
|
action:
|
5
5
|
edit:
|
6
6
|
title: Edit translation
|
7
|
+
label: Edit
|
7
8
|
destroy:
|
8
9
|
label: Delete
|
9
10
|
offset_link: Delete all from offset
|
10
|
-
|
11
|
-
label: Edit
|
11
|
+
successful: '%{model} is successfully removed'
|
12
12
|
index:
|
13
13
|
label: Translations
|
14
14
|
title: Translations
|
@@ -16,10 +16,14 @@ en:
|
|
16
16
|
label: New
|
17
17
|
update:
|
18
18
|
button_text: Update
|
19
|
+
successful: '%{model} is successfully updated'
|
20
|
+
create:
|
21
|
+
successful: '%{model} is successfully created'
|
19
22
|
export:
|
20
23
|
execute: Execute
|
21
24
|
untranslated: Untranslated
|
22
25
|
label: Export
|
26
|
+
from_offset: 'Export from offset: "%{offset}"'
|
23
27
|
general:
|
24
28
|
are_you_sure: 'Are you sure?'
|
25
29
|
boolean_false: 'no'
|
@@ -30,10 +34,13 @@ en:
|
|
30
34
|
find_value: Find value
|
31
35
|
none_found: No translations found
|
32
36
|
site_title: CouchI18n translations
|
33
|
-
|
37
|
+
untranslated_label: Untranslated
|
38
|
+
close: Close
|
39
|
+
is_json: 'Is JSON?'
|
34
40
|
import:
|
35
41
|
button: Import
|
36
42
|
label: Import
|
43
|
+
description: If you import keys, existing keys will be overwritten
|
37
44
|
activemodel:
|
38
45
|
models:
|
39
46
|
couch_i18n:
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: couch_i18n
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-09-21 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activemodel
|
@@ -62,11 +62,13 @@ files:
|
|
62
62
|
- app/assets/javascripts/couch_i18n/structure.js
|
63
63
|
- app/assets/stylesheets/couch_i18n/alerts.css.scss
|
64
64
|
- app/assets/stylesheets/couch_i18n/application.css
|
65
|
+
- app/assets/stylesheets/couch_i18n/bootstrap_and_override.css.less
|
65
66
|
- app/assets/stylesheets/couch_i18n/structure.css.scss
|
66
67
|
- app/controllers/couch_i18n/application_controller.rb
|
67
68
|
- app/controllers/couch_i18n/translations_controller.rb
|
68
69
|
- app/helpers/couch_i18n/application_helper.rb
|
69
70
|
- app/models/couch_i18n/translation.rb
|
71
|
+
- app/models/couch_i18n/translation.rb~
|
70
72
|
- app/views/couch_i18n/application/_alerts.html.haml
|
71
73
|
- app/views/couch_i18n/application/_error_messages.html.haml
|
72
74
|
- app/views/couch_i18n/translations/_form.html.haml
|