couch_i18n 0.2.1 → 0.3.1
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/README.rdoc +1 -2
- data/app/assets/javascripts/couch_i18n/application.js.coffee +8 -0
- data/app/assets/stylesheets/couch_i18n/application.sass +4 -0
- data/app/assets/stylesheets/couch_i18n/components/_buttons.sass +11 -0
- data/app/assets/stylesheets/couch_i18n/components/_forms.sass +45 -0
- data/app/assets/stylesheets/couch_i18n/components/_offset_navigation.sass +19 -0
- data/app/assets/stylesheets/couch_i18n/foundation_and_overrides.scss +1447 -0
- data/app/assets/stylesheets/couch_i18n/{structure.css.scss → structure.scss} +0 -24
- data/app/controllers/couch_i18n/application_controller.rb +16 -4
- data/app/controllers/couch_i18n/translations_controller.rb +37 -33
- data/app/models/couch_i18n/translation.rb +133 -26
- data/app/views/couch_i18n/application/_error_messages.html.slim +6 -0
- data/app/views/couch_i18n/translations/_form.html.slim +15 -0
- data/app/views/couch_i18n/translations/edit.html.slim +2 -0
- data/app/views/couch_i18n/translations/index.html.slim +91 -0
- data/app/views/couch_i18n/translations/new.html.slim +2 -0
- data/app/views/kaminari/couch_i18n/_first_page.html.erb +3 -0
- data/app/views/kaminari/couch_i18n/_first_page.html.slim +2 -0
- data/app/views/kaminari/couch_i18n/_gap.html.erb +3 -0
- data/app/views/kaminari/couch_i18n/_gap.html.slim +2 -0
- data/app/views/kaminari/couch_i18n/_last_page.html.erb +3 -0
- data/app/views/kaminari/couch_i18n/_last_page.html.slim +2 -0
- data/app/views/kaminari/couch_i18n/_next_page.html.erb +3 -0
- data/app/views/kaminari/couch_i18n/_next_page.html.slim +2 -0
- data/app/views/kaminari/couch_i18n/_page.html.erb +3 -0
- data/app/views/kaminari/couch_i18n/_page.html.slim +2 -0
- data/app/views/kaminari/couch_i18n/_paginator.html.erb +17 -0
- data/app/views/kaminari/couch_i18n/_paginator.html.slim +12 -0
- data/app/views/kaminari/couch_i18n/_prev_page.html.erb +3 -0
- data/app/views/kaminari/couch_i18n/_prev_page.html.slim +2 -0
- data/app/views/layouts/couch_i18n/application.html.slim +28 -0
- data/config/initializers/assets.rb +1 -0
- data/config/locales/couch_i18n.en.yml +9 -2
- data/config/routes.rb +2 -1
- data/lib/couch_i18n/active_model_errors.rb +2 -2
- data/lib/couch_i18n/backend.rb +1 -5
- data/lib/couch_i18n/engine.rb +12 -0
- data/lib/couch_i18n/store.rb +24 -12
- data/lib/couch_i18n/version.rb +3 -0
- data/lib/couch_i18n.rb +30 -9
- metadata +51 -42
- data/app/assets/javascripts/couch_i18n/application.js +0 -10
- data/app/assets/stylesheets/couch_i18n/application.css +0 -7
- data/app/assets/stylesheets/couch_i18n/bootstrap_and_override.css.less +0 -5
- data/app/views/couch_i18n/application/_error_messages.html.haml +0 -6
- data/app/views/couch_i18n/translations/_form.html.haml +0 -16
- data/app/views/couch_i18n/translations/edit.html.haml +0 -4
- data/app/views/couch_i18n/translations/index.html.haml +0 -82
- data/app/views/couch_i18n/translations/new.html.haml +0 -4
- data/app/views/layouts/couch_i18n/application.html.haml +0 -35
- /data/app/assets/stylesheets/couch_i18n/{alerts.css.scss → alerts.scss} +0 -0
- /data/app/views/couch_i18n/application/{_alerts.html.haml → _alerts.html.slim} +0 -0
@@ -46,30 +46,6 @@ form{
|
|
46
46
|
.untranslated-label{
|
47
47
|
display: inline;
|
48
48
|
}
|
49
|
-
.offset-navigation-block{
|
50
|
-
border-style: double;
|
51
|
-
border-color: #444;
|
52
|
-
border-left-width: 0;
|
53
|
-
border-right-width: 0;
|
54
|
-
padding: 5px 0;
|
55
|
-
margin-top: 5px;
|
56
|
-
.offset-navigation-deeper, .offset-navigation-higher{
|
57
|
-
a{
|
58
|
-
float: left;
|
59
|
-
margin-right: 5px;
|
60
|
-
margin-top: 5px;
|
61
|
-
padding: 4px;
|
62
|
-
border: 1px solid #aaa;
|
63
|
-
&:hover {
|
64
|
-
background-color: #ddd;
|
65
|
-
border-color: black;
|
66
|
-
}
|
67
|
-
}
|
68
|
-
}
|
69
|
-
.offset-navigation-form{
|
70
|
-
margin-top: 5px;
|
71
|
-
}
|
72
|
-
}
|
73
49
|
.clearing{
|
74
50
|
clear: both;
|
75
51
|
}
|
@@ -1,14 +1,26 @@
|
|
1
1
|
module CouchI18n
|
2
|
-
class ApplicationController <
|
3
|
-
|
4
|
-
layout
|
2
|
+
class ApplicationController < ::ApplicationController
|
3
|
+
before_action :authorize_user
|
4
|
+
layout :couch_i18n_layout
|
5
5
|
|
6
6
|
private
|
7
7
|
|
8
|
+
def cmtool_user
|
9
|
+
main_app.cmtool_user
|
10
|
+
end
|
11
|
+
|
12
|
+
def couch_i18n_layout
|
13
|
+
defined?(Cmtool) ? 'cmtool/application' : 'couch_i18n/application'
|
14
|
+
# Does not integrate well with cmtool layout at the moment (2012-12-17)
|
15
|
+
'couch_i18n/application'
|
16
|
+
end
|
17
|
+
|
8
18
|
def authorize_user
|
9
19
|
if respond_to?(:authorize_couch_i18n)
|
10
20
|
authorize_couch_i18n
|
11
|
-
elsif
|
21
|
+
elsif defined?(Cmtool)
|
22
|
+
authorize_cmtool
|
23
|
+
elsif respond_to?(:current_user) && current_user.respond_to?(:is_admin) && !current_user.is_admin.present?
|
12
24
|
redirect_to '/', :alert => I18n.t('couch_i18n.general.not_authorized')
|
13
25
|
end
|
14
26
|
end
|
@@ -5,52 +5,51 @@ module CouchI18n
|
|
5
5
|
@available_deeper_offsets = []
|
6
6
|
per_page = params[:per_page].presence.try(:to_i) || 30
|
7
7
|
if params[:partfinder].present?
|
8
|
-
|
8
|
+
if untranslated?
|
9
|
+
@translations = CouchI18n::Translation.find_all_untranslated_by_key_part(params[:offset], page: params[:page], per_page: per_page)
|
10
|
+
else
|
11
|
+
@translations = CouchI18n::Translation.find_all_by_key_part(params[:offset], page: params[:page], per_page: per_page)
|
12
|
+
end
|
9
13
|
elsif params[:valuefinder].present?
|
10
|
-
|
14
|
+
if untranslated?
|
15
|
+
@translations = CouchI18n::Translation.find_all_untranslated_by_value(params[:offset], page: params[:page], per_page: per_page)
|
16
|
+
else
|
17
|
+
@translations = CouchI18n::Translation.find_all_by_value(params[:offset], page: params[:page], per_page: per_page)
|
18
|
+
end
|
11
19
|
else
|
12
20
|
if params[:offset].present?
|
13
|
-
@levels = params[:offset].split('.')
|
14
|
-
# Add higher levels. Do not add the last level, since it is the current one => 0..-2
|
15
|
-
@levels[0..-2].each_with_index do |level_name, i|
|
16
|
-
@available_higher_offsets << {
|
17
|
-
:name => level_name,
|
18
|
-
:offset => @levels[0..i].join('.')
|
19
|
-
}
|
20
|
-
end
|
21
21
|
if untranslated?
|
22
22
|
@translations = CouchI18n::Translation.untranslated_with_offset(params[:offset], :page => params[:page], :per_page => per_page)
|
23
23
|
else
|
24
24
|
@translations = CouchI18n::Translation.with_offset(params[:offset], :page => params[:page], :per_page => per_page)
|
25
25
|
end
|
26
|
-
@available_deeper_offsets = CouchI18n::Translation.get_keys_by_level(@levels.size, :startkey => @levels, :endkey => @levels + [{}]).
|
27
|
-
map{|dl| {:name => dl, :offset => [params[:offset], dl].join('.')}}
|
28
26
|
else
|
29
27
|
if untranslated?
|
30
28
|
@translations = CouchI18n::Translation.untranslated(:page => params[:page], :per_page => per_page)
|
31
29
|
else
|
32
30
|
@translations = CouchI18n::Translation.all(:page => params[:page], :per_page => per_page)
|
33
31
|
end
|
34
|
-
@available_deeper_offsets = CouchI18n::Translation.get_keys_by_level(0).map{|dl| {:name => dl, :offset => dl}}
|
35
32
|
end
|
33
|
+
@available_higher_offsets = CouchI18n::Translation.higher_keys_for_offset(params[:offset])
|
34
|
+
@available_deeper_offsets = CouchI18n::Translation.deeper_keys_for_offset(params[:offset])
|
36
35
|
end
|
37
36
|
end
|
38
37
|
|
39
38
|
def show
|
40
|
-
|
39
|
+
redirect_to action: :edit
|
41
40
|
end
|
42
41
|
|
43
42
|
def new
|
44
|
-
@translation = CouchI18n::Translation.new :
|
43
|
+
@translation = CouchI18n::Translation.new translation_key: params[:offset]
|
45
44
|
end
|
46
45
|
|
47
46
|
def create
|
48
|
-
@translation = CouchI18n::Translation.new
|
47
|
+
@translation = CouchI18n::Translation.new translation_params
|
49
48
|
if @translation.value.present? && params[:is_json].present?
|
50
49
|
@translation.value = JSON.parse(@translation.value)
|
51
50
|
end
|
52
51
|
if @translation.save
|
53
|
-
redirect_to({:action => :index, :offset => @translation.
|
52
|
+
redirect_to({:action => :index, :offset => @translation.translation_key.to_s.sub(/\.[\w\s-]+$/, '')}, :notice => I18n.t('couch_i18n.action.create.successful', :model => CouchI18n::Translation.model_name.human))
|
54
53
|
else
|
55
54
|
render :action => :new
|
56
55
|
end
|
@@ -65,11 +64,12 @@ module CouchI18n
|
|
65
64
|
def update
|
66
65
|
@translation = CouchI18n::Translation.find(params[:id])
|
67
66
|
@translation.translated = true
|
68
|
-
|
69
|
-
|
67
|
+
tparams = translation_params
|
68
|
+
if tparams["value"].present? && params[:is_json].present?
|
69
|
+
tparams["value"] = JSON.parse(tparams["value"])
|
70
70
|
end
|
71
|
-
if @translation.update_attributes(
|
72
|
-
redirect_to({:action => :index, :offset => @translation.
|
71
|
+
if @translation.update_attributes(tparams)
|
72
|
+
redirect_to({:action => :index, :offset => @translation.translation_key.to_s.sub(/\.[\w\s-]+$/, '')}, :notice => I18n.t('couch_i18n.action.update.successful', :model => CouchI18n::Translation.model_name.human))
|
73
73
|
else
|
74
74
|
render :action => :edit
|
75
75
|
end
|
@@ -80,7 +80,7 @@ module CouchI18n
|
|
80
80
|
if @translation.destroy
|
81
81
|
flash[:notice] = I18n.t('couch_i18n.action.destroy.successful', :model => CouchI18n::Translation.model_name.human)
|
82
82
|
end
|
83
|
-
redirect_to({:action => :index, :offset => @translation.
|
83
|
+
redirect_to({:action => :index, :offset => @translation.translation_key.to_s.sub(/\.\w+$/, '')})
|
84
84
|
end
|
85
85
|
|
86
86
|
# POST /couch_i18n/translations/export
|
@@ -103,12 +103,12 @@ module CouchI18n
|
|
103
103
|
if params[:exportformat] == 'csv'
|
104
104
|
response.headers['Content-Type'] = 'text/csv'
|
105
105
|
response.headers['Content-Disposition'] = %{attachment; filename="#{base_filename}.csv"}
|
106
|
-
render :text => @translations.map{|s| [s.
|
106
|
+
render :text => @translations.map{|s| [s.translation_key, s.translation_value.to_json].join(',')}.join("\n")
|
107
107
|
elsif params[:exportformat] == 'json'
|
108
108
|
response.headers['Content-Type'] = 'application/json'
|
109
109
|
response.headers['Content-Disposition'] = %{attachment; filename="#{base_filename}.json"}
|
110
110
|
# render :text => CouchI18n.indent_keys(@translations).to_json # for indented json
|
111
|
-
render :json => @translations.map{|s| {s.
|
111
|
+
render :json => @translations.map{|s| {s.translation_key => s.translation_value}}.to_json
|
112
112
|
else #yaml
|
113
113
|
response.headers['Content-Type'] = 'application/x-yaml'
|
114
114
|
response.headers['Content-Disposition'] = %{attachment; filename="#{base_filename}.yml"}
|
@@ -119,28 +119,28 @@ module CouchI18n
|
|
119
119
|
# POST /couch_i18n/translations/import
|
120
120
|
# Import yml files
|
121
121
|
def import
|
122
|
-
redirect_to({:action => :index, :offset => params[:offset]}, :alert => I18n.t('couch_i18n.
|
122
|
+
redirect_to({:action => :index, :offset => params[:offset]}, :alert => I18n.t('couch_i18n.import.no_file_given')) and return unless params[:importfile].present?
|
123
123
|
filename = params[:importfile].original_filename
|
124
124
|
extension = filename.sub(/.*\./, '')
|
125
125
|
if extension == 'yml'
|
126
126
|
hash = YAML.load_file(params[:importfile].tempfile.path) rescue nil
|
127
|
-
redirect_to({:action => :index, :offset => params[:offset]}, :alert => I18n.t('couch_i18n.
|
127
|
+
redirect_to({:action => :index, :offset => params[:offset]}, :alert => I18n.t('couch_i18n.import.cannot_parse')) and return unless hash
|
128
128
|
CouchI18n.traverse_flatten_keys(hash).each do |key, value|
|
129
|
-
existing = CouchI18n::Translation.
|
129
|
+
existing = CouchI18n::Translation.find_by_translation_key(key)
|
130
130
|
if existing
|
131
|
-
if existing.
|
132
|
-
existing.
|
131
|
+
if existing.translation_value != value || !existing.translated?
|
132
|
+
existing.translation_value = value
|
133
133
|
existing.translated = true
|
134
134
|
existing.save
|
135
135
|
end
|
136
136
|
else
|
137
|
-
CouchI18n::Translation.create :
|
137
|
+
CouchI18n::Translation.create translation_key: key, translation_value: value
|
138
138
|
end
|
139
139
|
end
|
140
140
|
else
|
141
|
-
redirect_to({:action => :index, :offset => params[:offset]}, :alert => I18n.t('couch_i18n.
|
141
|
+
redirect_to({:action => :index, :offset => params[:offset]}, :alert => I18n.t('couch_i18n.import.extension_not_valid', :extension => extension)) and return
|
142
142
|
end
|
143
|
-
redirect_to({:action => :index, :offset => params[:offset]}, :notice => I18n.t('couch_i18n.
|
143
|
+
redirect_to({:action => :index, :offset => params[:offset]}, :notice => I18n.t('couch_i18n.import.notice', :filename => filename))
|
144
144
|
end
|
145
145
|
|
146
146
|
# Very dangarous action, please handle this with care, large removals are supported!
|
@@ -152,7 +152,7 @@ module CouchI18n
|
|
152
152
|
@translations = CouchI18n::Translation.all
|
153
153
|
end
|
154
154
|
@translations.map(&:destroy)
|
155
|
-
redirect_to({:action => :index}, :notice => I18n.t('couch_i18n.
|
155
|
+
redirect_to({:action => :index}, :notice => I18n.t('couch_i18n.general.offset_deleted_notice', :count => @translations.size, :offset => params[:offset]))
|
156
156
|
end
|
157
157
|
|
158
158
|
private
|
@@ -161,5 +161,9 @@ module CouchI18n
|
|
161
161
|
params[:untranslated].presence
|
162
162
|
end
|
163
163
|
helper_method :untranslated?
|
164
|
+
|
165
|
+
def translation_params
|
166
|
+
params.require(:translation).permit(:translation_key, :translation_value, :translated)
|
167
|
+
end
|
164
168
|
end
|
165
169
|
end
|
@@ -3,43 +3,86 @@ module CouchI18n
|
|
3
3
|
include SimplyStored::Couch
|
4
4
|
per_page_method :limit_value
|
5
5
|
|
6
|
-
property :
|
7
|
-
property :value
|
6
|
+
property :translation_value
|
8
7
|
property :translated, type: :boolean, default: true
|
9
8
|
|
10
|
-
|
9
|
+
def translation_key
|
10
|
+
id.present? ? id[3..-1] : nil
|
11
|
+
end
|
11
12
|
|
12
|
-
|
13
|
+
def key
|
14
|
+
translation_key
|
15
|
+
end
|
13
16
|
|
14
|
-
view :all_documents, :
|
15
|
-
|
17
|
+
view :all_documents, map_function: %|function(doc){
|
18
|
+
if(doc.ruby_class && doc.ruby_class == 'CouchI18n::Translation') {
|
19
|
+
emit(doc._id.substr(3), 1);
|
20
|
+
}
|
21
|
+
}|, type: :custom, reduce_function: '_sum'
|
22
|
+
#view :by_key, :key => :key
|
16
23
|
|
17
24
|
view :with_key_array, map_function: %|function(doc){
|
18
25
|
if(doc.ruby_class && doc.ruby_class == 'CouchI18n::Translation') {
|
19
|
-
emit(doc.
|
26
|
+
emit(doc._id.substr(3).split('.').slice(0, -1), 1);
|
20
27
|
}
|
21
28
|
}|, type: :raw, reduce_function: '_sum'
|
22
29
|
|
23
|
-
view :untranslated_view,
|
24
|
-
|
25
|
-
|
30
|
+
view :untranslated_view, map_function: %|function(doc){
|
31
|
+
if(doc.ruby_class && doc.ruby_class == 'CouchI18n::Translation' && !doc.translated) {
|
32
|
+
emit(doc._id.substr(3), 1);
|
33
|
+
}
|
34
|
+
}|, type: :custom, reduce_function: '_sum'
|
35
|
+
view :by_translation_value, key: :translation_value
|
36
|
+
view :untranslated_by_translation_value, key: :translation_value, conditions: "!doc['translated']"
|
37
|
+
view :by_translation_key_part, type: :custom, map_function: %|function(doc){
|
26
38
|
if(doc.ruby_class && doc.ruby_class == 'CouchI18n::Translation') {
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
}
|
39
|
+
doc._id.substr(3).split('.').forEach(function(key_part){
|
40
|
+
emit(key_part, 1)
|
41
|
+
})
|
31
42
|
}
|
32
43
|
}|, reduce_function: '_count'
|
33
44
|
|
34
|
-
|
35
|
-
|
45
|
+
view :untranslated_by_translation_key_part, type: :custom, map_function: %|function(doc){
|
46
|
+
if(doc.ruby_class && doc.ruby_class == 'CouchI18n::Translation' && !doc.translated) {
|
47
|
+
doc._id.substr(3).split('.').forEach(function(key_part){
|
48
|
+
emit(key_part, 1)
|
49
|
+
})
|
50
|
+
}
|
51
|
+
}|, reduce_function: '_count'
|
52
|
+
|
53
|
+
def self.get_translation_keys_by_level(level = 0, options = {})
|
54
|
+
data = database.view(with_key_array(options.merge(group_level: level.succ)))["rows"]
|
36
55
|
# data = data.select{|h| h["key"].size > level } # Only select ones that have a deeper nesting
|
37
56
|
data.map{|h| h['key'][level].try(:to_sym)}.compact
|
38
57
|
end
|
39
58
|
|
59
|
+
def translation_key=(val)
|
60
|
+
self.id = "t::#{val}"
|
61
|
+
end
|
62
|
+
|
40
63
|
# Shorthand for selecting all stored with a given offset
|
41
64
|
def self.with_offset(offset, options = {})
|
42
|
-
|
65
|
+
key = "#{offset}.".."#{offset}.ZZZZZZZZZ"
|
66
|
+
total_entries = database.view(all_documents(key: key, reduce: true))
|
67
|
+
with_pagination_options options.merge(total_entries: total_entries) do |options|
|
68
|
+
database.view(all_documents(options.merge(key: key, reduce: false, include_docs: true)))
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def self.all(options = {})
|
73
|
+
total_entries = database.view(all_documents(reduce: true))
|
74
|
+
with_pagination_options options.merge(total_entries: total_entries) do |options|
|
75
|
+
database.view(all_documents(options.merge(reduce: false, include_docs: true)))
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def self.find_by_translation_key(key)
|
80
|
+
begin
|
81
|
+
find("t::#{key}")
|
82
|
+
rescue SimplyStored::RecordNotFound
|
83
|
+
CouchI18n.handle_missing_key(key)
|
84
|
+
nil
|
85
|
+
end
|
43
86
|
end
|
44
87
|
|
45
88
|
# Find all records having the term part in their key
|
@@ -50,16 +93,59 @@ module CouchI18n
|
|
50
93
|
# find_all_by_part('action')
|
51
94
|
# will return the first two since they have action as key part
|
52
95
|
def self.find_all_by_key_part(part, options = {})
|
53
|
-
total_entries = database.view(
|
96
|
+
total_entries = database.view(by_translation_key_part(key: part, reduce: true))
|
54
97
|
with_pagination_options options.merge(total_entries: total_entries) do |options|
|
55
|
-
database.view(
|
98
|
+
database.view(by_translation_key_part(options.merge(key: part, reduce: false, include_docs: true)))
|
56
99
|
end
|
57
100
|
end
|
58
101
|
|
102
|
+
# Find all untranslated records having the term part in their key
|
103
|
+
# nl.action.one
|
104
|
+
# en.action.two
|
105
|
+
# en.activemodel.plural.models.user
|
106
|
+
# and using
|
107
|
+
# find_all_by_part('action')
|
108
|
+
# will return the first two since they have action as key part
|
109
|
+
def self.find_all_untranslated_by_key_part(part, options = {})
|
110
|
+
total_entries = database.view(untranslated_by_translation_key_part(key: part, reduce: true))
|
111
|
+
with_pagination_options options.merge(total_entries: total_entries) do |options|
|
112
|
+
database.view(untranslated_by_translation_key_part(options.merge(key: part, reduce: false, include_docs: true)))
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
# Find all untranslated records having the term part as value
|
117
|
+
# nl.action.one: 'Value', translated: true
|
118
|
+
# en.action.two: 'Value', translated: false
|
119
|
+
# en.activemodel.plural.models.user: 'Other Value', translated: false
|
120
|
+
# and using
|
121
|
+
# find_all_untranslated_by_value('Value')
|
122
|
+
# will return en.action.two
|
123
|
+
def self.find_all_untranslated_by_value(part, options = {})
|
124
|
+
total_entries = database.view(untranslated_by_translation_value(key: part, reduce: true))
|
125
|
+
with_pagination_options options.merge(total_entries: total_entries) do |options|
|
126
|
+
database.view(untranslated_by_translation_value(options.merge(key: part, reduce: false, include_docs: true)))
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
# Find all untranslated records having the term part as value
|
131
|
+
# nl.action.one: 'Value', translated: true
|
132
|
+
# en.action.two: 'Value', translated: false
|
133
|
+
# en.activemodel.plural.models.user: 'Other Value', translated: false
|
134
|
+
# and using
|
135
|
+
# find_all_untranslated_by_value('Value')
|
136
|
+
# will return en.action.two
|
137
|
+
def self.find_all_by_value(part, options = {})
|
138
|
+
total_entries = database.view(by_translation_value(key: part, reduce: true))
|
139
|
+
with_pagination_options options.merge(total_entries: total_entries) do |options|
|
140
|
+
database.view(by_translation_value(options.merge(key: part, reduce: false, include_docs: true)))
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
|
59
145
|
def self.untranslated(options = {})
|
60
|
-
total_entries = database.view(untranslated_view(options.
|
146
|
+
total_entries = database.view(untranslated_view(options.slice(:key, :keys, :startkey, :endkey).merge(reduce: true)))
|
61
147
|
with_pagination_options options.merge(total_entries: total_entries) do |options|
|
62
|
-
database.view(untranslated_view(options))
|
148
|
+
database.view(untranslated_view(options.merge(reduce: false, include_docs: true)))
|
63
149
|
end
|
64
150
|
end
|
65
151
|
|
@@ -67,11 +153,32 @@ module CouchI18n
|
|
67
153
|
CouchI18n::Translation.untranslated(options.merge(key: "#{offset}.".."#{offset}.ZZZZZZZZZ"))
|
68
154
|
end
|
69
155
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
156
|
+
def self.get_keys_by_level(level = 0, options = {})
|
157
|
+
data = database.view(with_key_array(options.merge(group_level: level.succ)))["rows"]
|
158
|
+
# data = data.select{|h| h["key"].size > level } # Only select ones that have a deeper nesting
|
159
|
+
data.map{|h| h['key'][level].try(:to_sym)}.compact
|
160
|
+
end
|
161
|
+
|
162
|
+
def self.deeper_keys_for_offset( offset )
|
163
|
+
return get_keys_by_level(0).map{|dl| {:name => dl, :offset => dl}} unless offset.present?
|
164
|
+
levels = offset.split('.')
|
165
|
+
get_keys_by_level(levels.size, :startkey => levels, :endkey => levels + [{}]).
|
166
|
+
map{|dl| {:name => dl, :offset => [offset, dl].join('.')}}
|
167
|
+
end
|
168
|
+
|
169
|
+
def self.higher_keys_for_offset( offset )
|
170
|
+
return [] unless offset.present?
|
171
|
+
higher_keys = []
|
172
|
+
levels = offset.split('.')
|
173
|
+
return [] unless levels.size > 1
|
174
|
+
# Add higher levels. Do not add the last level, since it is the current one => 0..-2
|
175
|
+
levels[0..-2].each_with_index do |level_name, i|
|
176
|
+
higher_keys<< {
|
177
|
+
:name => level_name,
|
178
|
+
:offset => levels[0..i].join('.')
|
179
|
+
}
|
180
|
+
end
|
181
|
+
higher_keys
|
75
182
|
end
|
76
183
|
end
|
77
184
|
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
= form_for @translation, html: {class: 'form-horizontal'} do |f|
|
2
|
+
= hidden_field_tag 'offset', params[:offset]
|
3
|
+
= render 'error_messages', :target => @translation
|
4
|
+
.form-row
|
5
|
+
.form-label= f.label :translation_key, class: 'control-label'
|
6
|
+
.form-field.full= f.text_field :translation_key, :size => 70, class: 'input-xxlarge'
|
7
|
+
.form-row
|
8
|
+
.form-label= f.label :translation_value, class: 'control-label'
|
9
|
+
.form-field.full= f.text_field :translation_value, :size => 70, class: 'input-xxlarge'
|
10
|
+
.form-row
|
11
|
+
.form-label= label_tag :is_json, t('couch_i18n.general.is_json'), class: 'control-label'
|
12
|
+
.form-field= check_box_tag :is_json, 1, f.object.translation_value.to_s =~ /^\{|^\[/
|
13
|
+
.form-row: .form-actions
|
14
|
+
= link_to link_to_index_content(:translations), couch_i18n.translations_path(:offset => params[:offset] || @translation.key.to_s.sub(/\.[\w\s-]+$/, '')), class: 'secondary button'
|
15
|
+
= f.submit local_assigns[:submit] || update_button_text, class: 'button'
|
@@ -0,0 +1,91 @@
|
|
1
|
+
- if params[:offset].present?
|
2
|
+
- title params[:offset]
|
3
|
+
- else
|
4
|
+
- title t("couch_i18n.action.index.title")
|
5
|
+
.row.top-buttons: .small-12.columns
|
6
|
+
a.import-button data-reveal-id="import-modal" href="#" = t('couch_i18n.import.label')
|
7
|
+
a.export-button data-reveal-id="export-modal" href="#" = t('couch_i18n.export.label')
|
8
|
+
= link_to t('couch_i18n.action.destroy.offset_link'), couch_i18n.destroy_offset_translations_path(offset: params[:offset]), method: :delete, data: {confirm: (defined?(:are_you_sure) ? are_you_sure : t('couch_i18n.general.are_you_sure'))}, class: 'delete-all-from-offset-button'
|
9
|
+
|
10
|
+
#import-modal.reveal-modal data-reveal=true
|
11
|
+
a.close-reveal-modal ×
|
12
|
+
= form_tag({action: :import}, multipart: true) do
|
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
|
+
= submit_tag I18n.t('couch_i18n.import.button'), class: 'warning button'
|
20
|
+
#export-modal.reveal-modal data-reveal=true
|
21
|
+
a.close-reveal-modal ×
|
22
|
+
= form_tag action: :export do
|
23
|
+
= hidden_field_tag :offset, params[:offset]
|
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
|
+
.row.modal-body
|
30
|
+
.small-6.columns= select_tag :exportformat, options_for_select(%w[yml csv json], params[:exportformat])
|
31
|
+
.small-6.columns
|
32
|
+
= check_box_tag :untranslated
|
33
|
+
= label_tag :untranslated, t('couch_i18n.export.untranslated'), class: 'untranslated-label'
|
34
|
+
.modal-footer
|
35
|
+
= submit_tag I18n.t('couch_i18n.export.execute'), class: 'success button'
|
36
|
+
.offset-navigation-block.block
|
37
|
+
.row
|
38
|
+
.small-12.columns
|
39
|
+
ul.button-group
|
40
|
+
- for offset in @available_higher_offsets
|
41
|
+
li= link_to offset[:name], {offset: offset[:offset], untranslated: params[:untranslated]}, class: 'secondary tiny button'
|
42
|
+
= form_tag({}, method: :get )do
|
43
|
+
.row
|
44
|
+
.small-5.columns
|
45
|
+
.row.collapse
|
46
|
+
.small-2.columns
|
47
|
+
- if params[:offset].present?
|
48
|
+
= link_to 'x' || I18n.t('couch_i18n.general.go_to_zero_offset'), {offset: nil}, class: 'prefix button'
|
49
|
+
.small-10.columns= text_field_tag :offset, params[:offset], size: 60
|
50
|
+
.small-4.columns
|
51
|
+
ul.button-group
|
52
|
+
li: input.tiny.button type="submit" name="commit" value=I18n.t('couch_i18n.general.go_to_offset')
|
53
|
+
li: input.tiny.button type="submit" name="partfinder" value=I18n.t('couch_i18n.general.find_part')
|
54
|
+
li: input.tiny.button type="submit" name="valuefinder" value=I18n.t('couch_i18n.general.find_value')
|
55
|
+
.small-3.columns
|
56
|
+
= "(#{@translations.total_count})"
|
57
|
+
= check_box_tag :untranslated, 1, untranslated?, id: :untranslated_listing
|
58
|
+
= label_tag :untranslated_listing, I18n.t('couch_i18n.general.untranslated_label'), class: 'untranslated-label'
|
59
|
+
.row
|
60
|
+
.small-12.columns
|
61
|
+
ul.button-group
|
62
|
+
- for offset in @available_deeper_offsets
|
63
|
+
li= link_to offset[:name], {offset: offset[:offset], untranslated: params[:untranslated]}, class: 'secondary tiny button'
|
64
|
+
- if @translations.any?
|
65
|
+
.row: .small-12.columns= paginate @translations, right: 3, left: 3, theme: 'couch_i18n'
|
66
|
+
.row: .small-12.columns
|
67
|
+
table.table.table-striped
|
68
|
+
thead
|
69
|
+
tr
|
70
|
+
th= CouchI18n::Translation.human_attribute_name(:translation_key)
|
71
|
+
th= CouchI18n::Translation.human_attribute_name(:translation_value)
|
72
|
+
th= CouchI18n::Translation.human_attribute_name(:translated)
|
73
|
+
th.action.edit
|
74
|
+
th.action.destroy
|
75
|
+
tbody
|
76
|
+
- @translations.each do |translation|
|
77
|
+
tr class=cycle('odd', 'even')
|
78
|
+
td
|
79
|
+
- if partfinder? || valuefinder?
|
80
|
+
= link_to translation.translation_key.to_s.sub(/^\./, ''), couch_i18n.edit_translation_path(translation, offset: params[:offset])
|
81
|
+
- else
|
82
|
+
= link_to translation.translation_key.to_s[(params[:offset].try(:size) || 0)..-1].sub(/^\./, ''), couch_i18n.edit_translation_path(translation, offset: params[:offset])
|
83
|
+
td= link_to translation.translation_value, couch_i18n.edit_translation_path(translation, offset: params[:offset])
|
84
|
+
td.boolean= boolean_show(translation.translated)
|
85
|
+
td.action.edit= link_to link_to_edit_content(translation), couch_i18n.edit_translation_path(translation, offset: params[:offset]), class: 'tiny warning button'
|
86
|
+
td.action.destroy= link_to link_to_destroy_content(translation),couch_i18n.translation_path(translation, offset: params[:offset]), data: {confirm: are_you_sure}, method: :delete, class: 'destroy-translation-button'
|
87
|
+
- else
|
88
|
+
.row: .small-12.columns: h3= t("couch_i18n.general.none_found")
|
89
|
+
|
90
|
+
- content_for :page_links do
|
91
|
+
= link_to link_to_new_content(:translation), couch_i18n.new_translation_path(offset: params[:offset]), class: 'button'
|
@@ -0,0 +1,17 @@
|
|
1
|
+
<%= paginator.render do -%>
|
2
|
+
<div class="pagination-centered">
|
3
|
+
<ul class="pagination">
|
4
|
+
<%= first_page_tag unless current_page.first? %>
|
5
|
+
<%= prev_page_tag unless current_page.first? %>
|
6
|
+
<% each_page do |page| -%>
|
7
|
+
<% if page.left_outer? || page.right_outer? || page.inside_window? -%>
|
8
|
+
<%= page_tag page %>
|
9
|
+
<% elsif !page.was_truncated? -%>
|
10
|
+
<%= gap_tag %>
|
11
|
+
<% end -%>
|
12
|
+
<% end -%>
|
13
|
+
<%= next_page_tag unless current_page.last? %>
|
14
|
+
<%= last_page_tag unless current_page.last? %>
|
15
|
+
</ul>
|
16
|
+
</div>
|
17
|
+
<% end -%>
|
@@ -0,0 +1,12 @@
|
|
1
|
+
= paginator.render do
|
2
|
+
.pagination-centered
|
3
|
+
ul.pagination
|
4
|
+
= first_page_tag unless current_page.first?
|
5
|
+
= prev_page_tag unless current_page.first?
|
6
|
+
- each_page do |page|
|
7
|
+
- if page.left_outer? || page.right_outer? || page.inside_window?
|
8
|
+
= page_tag page
|
9
|
+
- elsif !page.was_truncated?
|
10
|
+
= gap_tag
|
11
|
+
= next_page_tag unless current_page.last?
|
12
|
+
= last_page_tag unless current_page.last?
|