couch_i18n 0.0.4 → 0.0.5
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.
- data/README.rdoc +15 -31
- data/app/assets/images/couch_i18n/alert.png +0 -0
- data/app/assets/images/couch_i18n/notice.png +0 -0
- data/app/assets/javascripts/{application.js → couch_i18n/application.js} +2 -4
- data/app/assets/javascripts/couch_i18n/structure.js +2 -0
- data/app/assets/stylesheets/couch_i18n/alerts.css.scss +32 -0
- data/app/assets/stylesheets/{application.css → couch_i18n/application.css} +0 -0
- data/app/assets/stylesheets/couch_i18n/structure.css.scss +69 -0
- data/app/controllers/couch_i18n/application_controller.rb +1 -0
- data/app/controllers/couch_i18n/translations_controller.rb +143 -0
- data/app/helpers/couch_i18n/application_helper.rb +33 -0
- data/app/models/couch_i18n/translation.rb +51 -0
- data/app/views/couch_i18n/application/_alerts.html.haml +6 -0
- data/app/views/couch_i18n/application/_error_messages.html.haml +6 -0
- data/app/views/couch_i18n/translations/_form.html.haml +13 -0
- data/app/views/couch_i18n/translations/edit.html.haml +4 -0
- data/app/views/couch_i18n/translations/index.html.haml +54 -0
- data/app/views/couch_i18n/{stores → translations}/new.html.haml +0 -0
- data/app/views/layouts/couch_i18n/application.html.haml +5 -1
- data/config/routes.rb +10 -0
- data/lib/couch_i18n/backend.rb +3 -3
- data/lib/couch_i18n/engine.rb +1 -2
- data/lib/couch_i18n/store.rb +13 -52
- data/lib/couch_i18n.rb +12 -8
- metadata +18 -9
- data/app/controllers/couch_i18n/stores_controller.rb +0 -127
- data/app/views/couch_i18n/stores/_form.html.haml +0 -10
- data/app/views/couch_i18n/stores/edit.html.haml +0 -4
- data/app/views/couch_i18n/stores/index.html.haml +0 -46
data/README.rdoc
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
= CouchI18n
|
2
2
|
|
3
|
+
<b>Note this is a Rails >= 3.1 engine</b>
|
4
|
+
|
3
5
|
This projects is created to make translations editable. It is created using
|
4
6
|
the simply_stored gem. To use the web frontend please read the README section
|
5
7
|
on this carefully. Important to know is that this system sits *on top* of the
|
@@ -15,30 +17,7 @@ Your Gemfile should look like:
|
|
15
17
|
gem 'couch_i18n'
|
16
18
|
gem 'kaminari'
|
17
19
|
And in your config routes put:
|
18
|
-
|
19
|
-
root :to => "stores#index"
|
20
|
-
resources :stores do
|
21
|
-
collection do
|
22
|
-
post :export
|
23
|
-
post :import
|
24
|
-
delete :destroy_offset
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
28
|
-
Or to put is at a different location:
|
29
|
-
namespace :translations, :module => :couch_i18n, :as => 'couch_i18n' do
|
30
|
-
root :to => "stores#index"
|
31
|
-
resources :stores do
|
32
|
-
collection do
|
33
|
-
post :export
|
34
|
-
post :import
|
35
|
-
delete :destroy_offset
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
39
|
-
The intention is to make this a mountable application, but this will not happen
|
40
|
-
before Rails 3.1 is officially out. But beware of using this if your application
|
41
|
-
will not be Rails 3.1 compatible.
|
20
|
+
mount CouchI18n::Engine => '/couch_i18n'
|
42
21
|
|
43
22
|
== Security!!!
|
44
23
|
By default there is no security activated for editing the translation. This is
|
@@ -81,10 +60,10 @@ the following yamlL
|
|
81
60
|
activemodel:
|
82
61
|
models:
|
83
62
|
couch_i18n:
|
84
|
-
|
63
|
+
translation: Translation
|
85
64
|
attributes:
|
86
65
|
couch_i18n:
|
87
|
-
|
66
|
+
translation:
|
88
67
|
key: Key
|
89
68
|
value: Value
|
90
69
|
action:
|
@@ -94,16 +73,18 @@ the following yamlL
|
|
94
73
|
successful: %{model} successfully updated
|
95
74
|
destroy:
|
96
75
|
successful: %{model} successfully removed
|
97
|
-
|
98
|
-
|
76
|
+
couch_i18n:
|
77
|
+
translation:
|
99
78
|
index title: Translations
|
100
79
|
none found: No translations present
|
101
80
|
new title: New translation
|
102
81
|
show title: Translation
|
103
82
|
edit title: Edit translation
|
104
83
|
go to offset: Go to
|
105
|
-
|
106
|
-
export:
|
84
|
+
go to zero offset: x
|
85
|
+
export:
|
86
|
+
execute: Export
|
87
|
+
untranslated: Untranslated
|
107
88
|
import: Import
|
108
89
|
offset deleted: "%{count} translations with offset %{offset} are deleted"
|
109
90
|
no proper import extension: Files with extension%{extension} cannot be imported
|
@@ -159,13 +140,16 @@ It should <tt>yield</tt> the following parts:
|
|
159
140
|
!!!
|
160
141
|
%html
|
161
142
|
%head
|
162
|
-
%title= defined?(site_title) ? site_title : I18n.t('couch_i18n.
|
143
|
+
%title= defined?(site_title) ? site_title : I18n.t('couch_i18n.translation.site_title')
|
163
144
|
= csrf_meta_tag
|
145
|
+
= stylesheet_link_tag 'couch_i18n/application'
|
146
|
+
= javascript_include_tag 'couch_i18n/application'
|
164
147
|
= yield :head
|
165
148
|
%body
|
166
149
|
#page-wrapper
|
167
150
|
#page-content
|
168
151
|
%h1= yield :title
|
152
|
+
= render 'alerts'
|
169
153
|
= yield
|
170
154
|
#page-links= yield :page_links
|
171
155
|
== TODO
|
Binary file
|
Binary file
|
@@ -4,8 +4,6 @@
|
|
4
4
|
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
|
5
5
|
// the compiled file.
|
6
6
|
//
|
7
|
-
|
8
|
-
//= require
|
9
|
-
//= require <%= options[:javascript] %>_ujs
|
10
|
-
<% end -%>
|
7
|
+
//= require jquery
|
8
|
+
//= require jquery_ujs
|
11
9
|
//= require_tree .
|
@@ -0,0 +1,32 @@
|
|
1
|
+
$green: #729A37;
|
2
|
+
$red: #D65819;
|
3
|
+
.alert-message, #error_explanation{
|
4
|
+
margin: 10px 40px;
|
5
|
+
border-width: 2px;
|
6
|
+
border-style: solid;
|
7
|
+
background-repeat: no-repeat;
|
8
|
+
background-position: left center;
|
9
|
+
font-weight: bold;
|
10
|
+
}
|
11
|
+
.alert-message .message, #error_explanation .errors-content{
|
12
|
+
margin-left: 40px;
|
13
|
+
padding: 20px;
|
14
|
+
}
|
15
|
+
.notice{
|
16
|
+
background-color: lighten($green, 50%);
|
17
|
+
border-color: darken($green, 10%);
|
18
|
+
color: darken($green, 20%);
|
19
|
+
background-image: url('/assets/couch_i18n/notice.png');
|
20
|
+
}
|
21
|
+
.alert, #error_explanation{
|
22
|
+
background-color: lighten($red, 50%);
|
23
|
+
border-color: darken($red, 10%);
|
24
|
+
color: darken($red, 20%);
|
25
|
+
background-image: url('/assets/couch_i18n/alert.png');
|
26
|
+
}
|
27
|
+
.field_with_errors{
|
28
|
+
padding: 2px 5px;
|
29
|
+
background-color: $red;
|
30
|
+
display: table;
|
31
|
+
color: white;
|
32
|
+
}
|
File without changes
|
@@ -0,0 +1,69 @@
|
|
1
|
+
html, body{
|
2
|
+
margin: 0;
|
3
|
+
padding: 0;
|
4
|
+
}
|
5
|
+
body{
|
6
|
+
background-color: #ddf;
|
7
|
+
}
|
8
|
+
h1, h2, h3, h4, h5, h6{
|
9
|
+
margin: 0;
|
10
|
+
padding: 0;
|
11
|
+
}
|
12
|
+
h1{
|
13
|
+
font-size: 22px;
|
14
|
+
}
|
15
|
+
#page-wrapper{
|
16
|
+
width: 922px;
|
17
|
+
margin: 10px auto;
|
18
|
+
border: 1px solid #555;
|
19
|
+
background-color: white;
|
20
|
+
}
|
21
|
+
#page-content{
|
22
|
+
padding: 8px;
|
23
|
+
a{
|
24
|
+
color: black;
|
25
|
+
text-decoration: none;
|
26
|
+
}
|
27
|
+
.destroy-link{
|
28
|
+
float: right;
|
29
|
+
a{
|
30
|
+
background-color: #800;
|
31
|
+
color: white;
|
32
|
+
font-weight: bold;
|
33
|
+
padding: 4px 10px;
|
34
|
+
}
|
35
|
+
}
|
36
|
+
}
|
37
|
+
tr.even{
|
38
|
+
background-color: #ddf;
|
39
|
+
}
|
40
|
+
#page-links{
|
41
|
+
margin-top: 8px;
|
42
|
+
margin-bottom: 8px;
|
43
|
+
a{
|
44
|
+
padding: 4px;
|
45
|
+
border: 1px dotted #555;
|
46
|
+
&:hover {
|
47
|
+
background-color: #ddd;
|
48
|
+
border-style: solid;
|
49
|
+
}
|
50
|
+
}
|
51
|
+
}
|
52
|
+
|
53
|
+
.offset-navigation-block{
|
54
|
+
border-style: double;
|
55
|
+
border-color: #444;
|
56
|
+
border-left-width: 0;
|
57
|
+
border-right-width: 0;
|
58
|
+
.offset-navigation-deeper, .offset-navigation-higher{
|
59
|
+
a{
|
60
|
+
padding: 4px;
|
61
|
+
border: 1px solid #aaa;
|
62
|
+
&:hover {
|
63
|
+
background-color: #ddd;
|
64
|
+
border-color: black;
|
65
|
+
}
|
66
|
+
}
|
67
|
+
padding: 8px;
|
68
|
+
}
|
69
|
+
}
|
@@ -0,0 +1,143 @@
|
|
1
|
+
module CouchI18n
|
2
|
+
class TranslationsController < CouchI18n::ApplicationController
|
3
|
+
def index
|
4
|
+
@available_higher_offsets = []
|
5
|
+
if params[:offset].present?
|
6
|
+
@levels = params[:offset].split('.')
|
7
|
+
# Add higher levels. Do not add the last level, since it is the current one => 0..-2
|
8
|
+
@levels[0..-2].each_with_index do |level_name, i|
|
9
|
+
@available_higher_offsets << {
|
10
|
+
:name => level_name,
|
11
|
+
:offset => @levels[0..i].join('.')
|
12
|
+
}
|
13
|
+
end
|
14
|
+
@translations = CouchI18n::Translation.with_offset(params[:offset], :page => params[:page], :per_page => 30)
|
15
|
+
@available_deeper_offsets = CouchI18n::Translation.get_keys_by_level(@levels.size, :startkey => @levels, :endkey => @levels + [{}]).
|
16
|
+
map{|dl| {:name => dl, :offset => [params[:offset], dl].join('.')}}
|
17
|
+
else
|
18
|
+
@translations = CouchI18n::Translation.all(:page => params[:page], :per_page => 30)
|
19
|
+
@available_deeper_offsets = CouchI18n::Translation.get_keys_by_level(0).
|
20
|
+
map{|dl| {:name => dl, :offset => dl}}
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def show
|
25
|
+
@translation = CouchI18n::Translation.find(params[:id])
|
26
|
+
end
|
27
|
+
|
28
|
+
def new
|
29
|
+
@translation = CouchI18n::Translation.new :key => params[:offset]
|
30
|
+
end
|
31
|
+
|
32
|
+
def create
|
33
|
+
@translation = CouchI18n::Translation.new params[:translation]
|
34
|
+
if @translation.value.present? && params[:is_json].present?
|
35
|
+
@translation.value = JSON.parse(@translation.value)
|
36
|
+
end
|
37
|
+
if @translation.save
|
38
|
+
redirect_to({:action => :index, :offset => @translation.key.to_s.sub(/\.[\w\s-]+$/, '')}, :notice => I18n.t('action.create.successful', :model => CouchI18n::Translation.model_name.human))
|
39
|
+
else
|
40
|
+
render :action => :new
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# GET /couch_i18n/translations/:id/edit
|
45
|
+
def edit
|
46
|
+
@translation = CouchI18n::Translation.find(params[:id])
|
47
|
+
end
|
48
|
+
|
49
|
+
# PUT /couch_i18n/translations/:id
|
50
|
+
def update
|
51
|
+
@translation = CouchI18n::Translation.find(params[:id])
|
52
|
+
@translation.translated = true
|
53
|
+
if params[:translation]["value"].present? && params[:is_json].present?
|
54
|
+
params[:translation]["value"] = JSON.parse(params[:translation]["value"])
|
55
|
+
end
|
56
|
+
if @translation.update_attributes(params[:translation])
|
57
|
+
redirect_to({:action => :index, :offset => @translation.key.to_s.sub(/\.[\w\s-]+$/, '')}, :notice => I18n.t('action.update.successful', :model => CouchI18n::Translation.model_name.human))
|
58
|
+
else
|
59
|
+
render :action => :edit
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def destroy
|
64
|
+
@translation = CouchI18n::Translation.find(params[:id])
|
65
|
+
if @translation.destroy
|
66
|
+
flash[:notice] = I18n.t('action.destroy.successful', :model => CouchI18n::Translation.model_name.human)
|
67
|
+
end
|
68
|
+
redirect_to({:action => :index, :offset => @translation.key.to_s.sub(/\.\w+$/, '')})
|
69
|
+
end
|
70
|
+
|
71
|
+
# POST /couch_i18n/translations/export
|
72
|
+
# Export to yml, csv or json
|
73
|
+
def export
|
74
|
+
if params[:offset].present?
|
75
|
+
if params[:untranslated].present?
|
76
|
+
@translations = CouchI18n::Translation.unstranslated_with_offset(params[:offset])
|
77
|
+
else
|
78
|
+
@translations = CouchI18n::Translation.with_offset(params[:offset])
|
79
|
+
end
|
80
|
+
else
|
81
|
+
if params[:untranslated].present?
|
82
|
+
@translations = CouchI18n::Translation.untranslated
|
83
|
+
else
|
84
|
+
@translations = CouchI18n::Translation.all
|
85
|
+
end
|
86
|
+
end
|
87
|
+
base_filename = "export#{Time.now.strftime('%Y%m%d%H%M')}"
|
88
|
+
if params[:exportformat] == 'csv'
|
89
|
+
response.headers['Content-Type'] = 'text/csv'
|
90
|
+
response.headers['Content-Disposition'] = %{attachment; filename="#{base_filename}.csv"}
|
91
|
+
render :text => @translations.map{|s| [s.key, s.value.to_json].join(',')}.join("\n")
|
92
|
+
elsif params[:exportformat] == 'json'
|
93
|
+
response.headers['Content-Type'] = 'application/json'
|
94
|
+
response.headers['Content-Disposition'] = %{attachment; filename="#{base_filename}.json"}
|
95
|
+
# render :text => CouchI18n.indent_keys(@translations).to_json # for indented json
|
96
|
+
render :json => @translations.map{|s| {s.key => s.value}}.to_json
|
97
|
+
else #yaml
|
98
|
+
response.headers['Content-Type'] = 'application/x-yaml'
|
99
|
+
response.headers['Content-Disposition'] = %{attachment; filename="#{base_filename}.yml"}
|
100
|
+
render :text => CouchI18n.indent_keys(@translations).to_yaml
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
# POST /couch_i18n/translations/import
|
105
|
+
# Import yml files
|
106
|
+
def import
|
107
|
+
redirect_to({:action => :index, :offset => params[:offset]}, :alert => I18n.t('couch_i18n.translation.no import file given')) and return unless params[:importfile].present?
|
108
|
+
filename = params[:importfile].original_filename
|
109
|
+
extension = filename.sub(/.*\./, '')
|
110
|
+
if extension == 'yml'
|
111
|
+
hash = YAML.load_file(params[:importfile].tempfile.path) rescue nil
|
112
|
+
redirect_to({:action => :index, :offset => params[:offset]}, :alert => I18n.t('couch_i18n.translation.cannot parse yaml')) and return unless hash
|
113
|
+
CouchI18n.traverse_flatten_keys(hash).each do |key, value|
|
114
|
+
existing = CouchI18n::Translation.find_by_key(key)
|
115
|
+
if existing
|
116
|
+
if existing.value != value
|
117
|
+
existing.value = value
|
118
|
+
existing.translated = true
|
119
|
+
existing.save
|
120
|
+
end
|
121
|
+
else
|
122
|
+
CouchI18n::Translation.create :key => key, :value => value
|
123
|
+
end
|
124
|
+
end
|
125
|
+
else
|
126
|
+
redirect_to({:action => :index, :offset => params[:offset]}, :alert => I18n.t('couch_i18n.translation.no proper import extension', :extension => extension)) and return
|
127
|
+
end
|
128
|
+
redirect_to({:action => :index, :offset => params[:offset]}, :notice => I18n.t('couch_i18n.translation.file imported', :filename => filename))
|
129
|
+
end
|
130
|
+
|
131
|
+
# Very dangarous action, please handle this with care, large removals are supported!
|
132
|
+
# DELETE /couch_i18n/translations/destroy_offset?...
|
133
|
+
def destroy_offset
|
134
|
+
if params[:offset].present?
|
135
|
+
@translations = CouchI18n::Translation.with_offset(params[:offset])
|
136
|
+
else
|
137
|
+
@translations = CouchI18n::Translation.all
|
138
|
+
end
|
139
|
+
@translations.map(&:destroy)
|
140
|
+
redirect_to({:action => :index}, :notice => I18n.t('couch_i18n.translation.offset deleted', :count => @translations.size, :offset => params[:offset]))
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
@@ -1,4 +1,37 @@
|
|
1
1
|
module CouchI18n
|
2
2
|
module ApplicationHelper
|
3
|
+
def title(msg)
|
4
|
+
content_for :title do
|
5
|
+
msg
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
def link_to_new_content(obj)
|
10
|
+
t('New')
|
11
|
+
end
|
12
|
+
def link_to_edit_content(obj = nil)
|
13
|
+
t('Edit')
|
14
|
+
end
|
15
|
+
def link_to_show_content(obj = nil)
|
16
|
+
t('Show')
|
17
|
+
end
|
18
|
+
def link_to_index_content(singular_name)
|
19
|
+
t('Back')
|
20
|
+
end
|
21
|
+
def link_to_destroy_content(obj = nil)
|
22
|
+
t('Delete')
|
23
|
+
end
|
24
|
+
def update_button_text(obj = nil)
|
25
|
+
t('Save')
|
26
|
+
end
|
27
|
+
def create_button_text(obj = nil)
|
28
|
+
t('Create')
|
29
|
+
end
|
30
|
+
def boolean_show(truefalse)
|
31
|
+
truefalse ? t('boolean true') : t('boolean false')
|
32
|
+
end
|
33
|
+
def are_you_sure(obj = nil)
|
34
|
+
t('Are you sure')
|
35
|
+
end
|
3
36
|
end
|
4
37
|
end
|
@@ -0,0 +1,51 @@
|
|
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(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 => '_sum'
|
22
|
+
|
23
|
+
view :untranslated_view, :key => :key, :conditions => "!doc['translated']"
|
24
|
+
|
25
|
+
def self.get_keys_by_level(level = 0, options = {})
|
26
|
+
data = database.view(with_key_array(options.merge(:group_level => level.succ)))["rows"]
|
27
|
+
# data = data.select{|h| h["key"].size > level } # Only select ones that have a deeper nesting
|
28
|
+
data.map{|h| h['key'][level].try(:to_sym)}.compact
|
29
|
+
end
|
30
|
+
|
31
|
+
# Shorthand for selecting all stored with a given offset
|
32
|
+
def self.with_offset(offset, options = {})
|
33
|
+
CouchI18n::Translation.find_all_by_key("#{offset}.".."#{offset}.ZZZZZZZZZ", options)
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.untranslated(*args)
|
37
|
+
database.view(untranslated_view(*args))
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.untranslated_with_offset(offset, options = {})
|
41
|
+
CouchI18n::Translation.untranslated("#{offset}.".."#{offset}.ZZZZZZZZZ", options)
|
42
|
+
end
|
43
|
+
|
44
|
+
# Expire I18n when record is update
|
45
|
+
def reload_i18n
|
46
|
+
Rails.cache.write(key, value)
|
47
|
+
I18n.reload!
|
48
|
+
I18n.cache_store.clear if I18n.respond_to?(:cache_store) && I18n.cache_store.respond_to?(:clear)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
= form_for @translation do |f|
|
2
|
+
= render 'error_messages', :target => @translation
|
3
|
+
.field
|
4
|
+
= f.label :key
|
5
|
+
= f.text_field :key, :size => 70
|
6
|
+
.field
|
7
|
+
= f.label :value
|
8
|
+
= f.text_field :value, :size => 70
|
9
|
+
.field
|
10
|
+
= label_tag :is_json
|
11
|
+
= check_box_tag :is_json, 1, ['{', '['].include?(@translation.value.to_s.first)
|
12
|
+
.actions
|
13
|
+
= f.submit @submit || update_button_text
|
@@ -0,0 +1,54 @@
|
|
1
|
+
- if params[:offset].present?
|
2
|
+
- title params[:offset]
|
3
|
+
- else
|
4
|
+
- title t("couch_i18n.translation.index title")
|
5
|
+
.destroy-link
|
6
|
+
= link_to t('couch_i18n.translation.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.translation.are you sure'))
|
7
|
+
.import-form
|
8
|
+
= form_tag({:action => :import}, :multipart => true) do
|
9
|
+
= file_field_tag :importfile
|
10
|
+
= submit_tag I18n.t('couch_i18n.translation.import')
|
11
|
+
.export-form
|
12
|
+
= form_tag :action => :export do
|
13
|
+
= hidden_field_tag :offset, params[:offset]
|
14
|
+
= select_tag :exportformat, options_for_select(%w[yml csv json], params[:exportformat])
|
15
|
+
= check_box_tag :untranslated
|
16
|
+
= label_tag :untranslated, t('couch_i18n.translation.export.untranslated')
|
17
|
+
= submit_tag I18n.t('couch_i18n.translation.export.execute')
|
18
|
+
.offset-navigation-block.block
|
19
|
+
.offset-navigation-higher
|
20
|
+
- for offset in @available_higher_offsets
|
21
|
+
= link_to offset[:name], :offset => offset[:offset]
|
22
|
+
.offset-navigation-form
|
23
|
+
= form_tag({}, :method => :get )do
|
24
|
+
- if params[:offset].present?
|
25
|
+
= link_to I18n.t('couch_i18n.translation.go to zero offset'), :offset => nil
|
26
|
+
= text_field_tag :offset, params[:offset], :size => 60
|
27
|
+
= "(#{@translations.total_entries})"
|
28
|
+
= submit_tag I18n.t('couch_i18n.translation.go to offset')
|
29
|
+
.offset-navigation-deeper
|
30
|
+
- for offset in @available_deeper_offsets
|
31
|
+
= link_to offset[:name], :offset => offset[:offset]
|
32
|
+
- if @translations.any?
|
33
|
+
= paginate @translations, :right => 3, :left => 3
|
34
|
+
%table.index-table
|
35
|
+
%thead
|
36
|
+
%tr
|
37
|
+
%th= CouchI18n::Translation.human_attribute_name(:key)
|
38
|
+
%th= CouchI18n::Translation.human_attribute_name(:value)
|
39
|
+
%th= CouchI18n::Translation.human_attribute_name(:translated)
|
40
|
+
%th.action.edit
|
41
|
+
%th.action.destroy
|
42
|
+
%tbody
|
43
|
+
- @translations.each do |translation|
|
44
|
+
%tr{:class => cycle('odd', 'even')}
|
45
|
+
%td= link_to translation.key[(params[:offset].try(:size) || 0)..-1].sub(/^\./, ''), couch_i18n.edit_translation_path(translation)
|
46
|
+
%td= link_to translation.value, couch_i18n.edit_translation_path(translation)
|
47
|
+
%td.boolean= boolean_show(translation.translated)
|
48
|
+
%td.action.edit= link_to link_to_edit_content(translation), couch_i18n.edit_translation_path(translation)
|
49
|
+
%td.action.destroy= link_to link_to_destroy_content(translation),couch_i18n.translation_path(translation), :confirm => are_you_sure, :method => :delete
|
50
|
+
- else
|
51
|
+
%h3= t("translation.none found")
|
52
|
+
|
53
|
+
- content_for :page_links do
|
54
|
+
= link_to link_to_new_content(:translation), couch_i18n.new_translation_path(:offset => params[:offset])
|
File without changes
|
@@ -3,10 +3,14 @@
|
|
3
3
|
%head
|
4
4
|
%title= defined?(site_title) ? site_title : I18n.t('couch_i18n.store.site_title')
|
5
5
|
= csrf_meta_tag
|
6
|
+
= stylesheet_link_tag 'couch_i18n/application'
|
7
|
+
= javascript_include_tag 'couch_i18n/application'
|
6
8
|
= yield :head
|
7
9
|
%body
|
8
10
|
#page-wrapper
|
9
|
-
#page-
|
11
|
+
#page-header
|
10
12
|
%h1= yield :title
|
13
|
+
#page-content
|
14
|
+
= render 'alerts'
|
11
15
|
= yield
|
12
16
|
#page-links= yield :page_links
|
data/config/routes.rb
ADDED
data/lib/couch_i18n/backend.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'i18n/backend/base'
|
2
2
|
require 'active_support/json'
|
3
3
|
require 'active_support/ordered_hash' # active_support/json/encoding uses ActiveSupport::OrderedHash but does not require it
|
4
|
-
|
4
|
+
require "i18n/backend/cache"
|
5
5
|
module CouchI18n
|
6
6
|
class Backend
|
7
7
|
# This is a basic backend for key value stores. It receives on
|
@@ -52,7 +52,7 @@ module CouchI18n
|
|
52
52
|
attr_accessor :store
|
53
53
|
|
54
54
|
include I18n::Backend::Base, I18n::Backend::Flatten
|
55
|
-
|
55
|
+
include I18n::Backend::Cache
|
56
56
|
def initialize(store, subtrees=true)
|
57
57
|
@store, @subtrees = store, subtrees
|
58
58
|
end
|
@@ -89,7 +89,7 @@ module CouchI18n
|
|
89
89
|
def lookup(locale, key, scope = [], options = {})
|
90
90
|
key = normalize_flat_keys(locale, key, scope, options[:separator])
|
91
91
|
value = @store["#{locale}.#{key}"]
|
92
|
-
|
92
|
+
value = ActiveSupport::JSON.decode(value) rescue value
|
93
93
|
value.is_a?(Hash) ? value.deep_symbolize_keys : value
|
94
94
|
end
|
95
95
|
end
|
data/lib/couch_i18n/engine.rb
CHANGED
data/lib/couch_i18n/store.rb
CHANGED
@@ -1,69 +1,30 @@
|
|
1
|
-
# First comment out backend declaration in config/initializers/i18n_backend.rb
|
2
|
-
# this looks like:
|
3
|
-
# #I18n.backend = I18n::Backend::Chain.new(I18n::Backend::KeyValue.new(CouchI18n::Store), I18n.backend)
|
4
|
-
# Then load the translations:
|
5
|
-
# I18n.t('New')
|
6
|
-
# Then create the translations
|
7
|
-
# I18n.t('New');I18n.backend.send(:translations).flatten_keys.each{|k, v| CouchI18n::Store.create(:key => k, :value => v)}
|
8
1
|
module CouchI18n
|
9
2
|
class Store
|
10
|
-
include SimplyStored::Couch
|
11
|
-
per_page_method :limit_value
|
12
3
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
validates_uniqueness_of :key
|
17
|
-
|
18
|
-
after_save :reload_i18n
|
19
|
-
|
20
|
-
view :all_documents, :key => :key
|
21
|
-
view :by_key, :key => :key
|
22
|
-
|
23
|
-
view :with_key_array, :map => %|function(doc){
|
24
|
-
if(doc.ruby_class && doc.ruby_class == 'CouchI18n::Store') {
|
25
|
-
emit(doc.key.split('.').slice(0,-1), 1);
|
26
|
-
}
|
27
|
-
}|, :type => :raw, :reduce => '_sum'
|
28
|
-
|
29
|
-
def self.available_locales
|
30
|
-
get_keys_by_level
|
31
|
-
end
|
32
|
-
|
33
|
-
def self.get_keys_by_level(level = 0, options = {})
|
34
|
-
data = database.view(with_key_array(options.merge(:group_level => level.succ)))["rows"]
|
35
|
-
# data = data.select{|h| h["key"].size > level } # Only select ones that have a deeper nesting
|
36
|
-
data.map{|h| h['key'][level].try(:to_sym)}.compact
|
4
|
+
def available_locales
|
5
|
+
CouchI18n::Translation.get_keys_by_level(0)
|
37
6
|
end
|
38
7
|
|
39
8
|
# Now the store features
|
40
|
-
def
|
9
|
+
def []=(key, value, options = {})
|
41
10
|
key = key.to_s
|
42
|
-
existing = find_by_key(key) rescue nil
|
43
|
-
translation = existing || new(:key => key)
|
11
|
+
existing = CouchI18n::Translation.find_by_key(key) rescue nil
|
12
|
+
translation = existing || CouchI18n::Translation.new(:key => key)
|
44
13
|
translation.value = value
|
45
14
|
translation.save
|
46
15
|
end
|
47
16
|
|
48
|
-
# Shorthand for selecting all stored with a given offset
|
49
|
-
def self.with_offset(offset, options = {})
|
50
|
-
find_all_by_key("#{offset}.".."#{offset}.ZZZZZZZZZ", options)
|
51
|
-
end
|
52
|
-
|
53
17
|
# alias for read
|
54
|
-
def
|
55
|
-
|
18
|
+
def [](key, options=nil)
|
19
|
+
Rails.cache.fetch(key) do
|
20
|
+
translation = CouchI18n::Translation.find_by_key(key.to_s)
|
21
|
+
translation ||= CouchI18n::Translation.create(:key => key, :value => key.to_s.split('.').last, :translated => false)
|
22
|
+
translation.value
|
23
|
+
end
|
56
24
|
end
|
57
25
|
|
58
|
-
def
|
59
|
-
all.map(&:key)
|
60
|
-
end
|
61
|
-
|
62
|
-
private
|
63
|
-
|
64
|
-
def reload_i18n
|
65
|
-
I18n.reload!
|
66
|
-
I18n.cache_store.clear if I18n.respond_to?(:cache_store) && I18n.cache_store.respond_to?(:clear)
|
26
|
+
def keys
|
27
|
+
CouchI18n::Translation.all.map(&:key)
|
67
28
|
end
|
68
29
|
end
|
69
30
|
end
|
data/lib/couch_i18n.rb
CHANGED
@@ -1,8 +1,6 @@
|
|
1
|
-
require "i18n/backend/cache"
|
2
1
|
require "couch_i18n/engine"
|
3
2
|
require 'couch_i18n/store'
|
4
3
|
require 'couch_i18n/backend'
|
5
|
-
I18n::Backend::KeyValue.send(:include, I18n::Backend::Cache)
|
6
4
|
module CouchI18n
|
7
5
|
# This method imports yaml translations to the couchdb version. When run again new ones will
|
8
6
|
# be added. Translations already stored in the couchdb database are not overwritten
|
@@ -15,7 +13,7 @@ module CouchI18n
|
|
15
13
|
yml_backend.load_translations
|
16
14
|
flattened_hash = traverse_flatten_keys(yml_backend.send(:translations))
|
17
15
|
flattened_hash.each do |key, value|
|
18
|
-
CouchI18n::
|
16
|
+
CouchI18n::Translation.create :key => key, :value => value
|
19
17
|
end
|
20
18
|
end
|
21
19
|
|
@@ -26,7 +24,7 @@ module CouchI18n
|
|
26
24
|
obj.each{|k, v| traverse_flatten_keys(v, store, [path, k].compact.join('.'))}
|
27
25
|
when Array
|
28
26
|
# Do not store array for now. There is no good solution yet
|
29
|
-
|
27
|
+
store[path] = obj # Keeyp arrays intact
|
30
28
|
# store[path] = obj.to_json
|
31
29
|
# obj.each_with_index{|v, i| traverse_flatten_keys(store, v, [path, i].compact.join('.'))}
|
32
30
|
else
|
@@ -38,7 +36,7 @@ module CouchI18n
|
|
38
36
|
# This will return an indented strucutre of a collection of stores. If no argument is given
|
39
37
|
# by default all the translations are indented. So a command:
|
40
38
|
# CouchI18n.indent_keys.to_yaml will return one big yaml string of the translations
|
41
|
-
def self.indent_keys(selection =
|
39
|
+
def self.indent_keys(selection = CouchI18n::Translation.all)
|
42
40
|
traverse_indent_keys(selection.map{|kv| [kv.key.split('.'), kv.value]})
|
43
41
|
end
|
44
42
|
|
@@ -49,13 +47,19 @@ module CouchI18n
|
|
49
47
|
h[pair.first.first] = pair.last
|
50
48
|
else
|
51
49
|
h[pair.first.first] ||= {}
|
50
|
+
next unless h[pair.first.first].is_a?(Hash) # In case there is a translation en.a: A, en.a.b: B this is invalid
|
52
51
|
traverse_indent_keys([[pair.first[1..-1], pair.last]], h[pair.first.first])
|
53
52
|
end
|
54
53
|
end
|
55
54
|
h
|
56
55
|
end
|
57
|
-
end
|
58
56
|
|
57
|
+
# Add all translations to the cache to avoid one by one loading and caching
|
58
|
+
def self.cache_all
|
59
|
+
CouchI18n::Translation.all.each do |t|
|
60
|
+
Rails.cache.write(t.key, t.value)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
59
64
|
# Now extend the I18n backend
|
60
|
-
I18n.backend = I18n::Backend::Chain.new(CouchI18n::Backend.new(CouchI18n::Store), I18n.backend)
|
61
|
-
I18n.cache_store = ActiveSupport::Cache.lookup_store(:memory_store)
|
65
|
+
I18n.backend = I18n::Backend::Chain.new(CouchI18n::Backend.new(CouchI18n::Store.new), I18n.backend)
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: couch_i18n
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.0.
|
5
|
+
version: 0.0.5
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Benjamin ter Kuile
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2011-
|
13
|
+
date: 2011-07-10 00:00:00 +02:00
|
14
14
|
default_executable:
|
15
15
|
dependencies: []
|
16
16
|
|
@@ -28,16 +28,25 @@ files:
|
|
28
28
|
- lib/couch_i18n/store.rb
|
29
29
|
- lib/couch_i18n.rb
|
30
30
|
- lib/tasks/couch_i18n_tasks.rake
|
31
|
-
- app/
|
31
|
+
- app/models/couch_i18n/translation.rb
|
32
32
|
- app/controllers/couch_i18n/application_controller.rb
|
33
|
-
- app/
|
34
|
-
- app/assets/
|
33
|
+
- app/controllers/couch_i18n/translations_controller.rb
|
34
|
+
- app/assets/javascripts/couch_i18n/structure.js
|
35
|
+
- app/assets/javascripts/couch_i18n/application.js
|
36
|
+
- app/assets/images/couch_i18n/alert.png
|
37
|
+
- app/assets/images/couch_i18n/notice.png
|
38
|
+
- app/assets/stylesheets/couch_i18n/alerts.css.scss
|
39
|
+
- app/assets/stylesheets/couch_i18n/structure.css.scss
|
40
|
+
- app/assets/stylesheets/couch_i18n/application.css
|
35
41
|
- app/helpers/couch_i18n/application_helper.rb
|
36
|
-
- app/views/couch_i18n/
|
37
|
-
- app/views/couch_i18n/
|
38
|
-
- app/views/couch_i18n/
|
39
|
-
- app/views/couch_i18n/
|
42
|
+
- app/views/couch_i18n/application/_alerts.html.haml
|
43
|
+
- app/views/couch_i18n/application/_error_messages.html.haml
|
44
|
+
- app/views/couch_i18n/translations/_form.html.haml
|
45
|
+
- app/views/couch_i18n/translations/index.html.haml
|
46
|
+
- app/views/couch_i18n/translations/edit.html.haml
|
47
|
+
- app/views/couch_i18n/translations/new.html.haml
|
40
48
|
- app/views/layouts/couch_i18n/application.html.haml
|
49
|
+
- config/routes.rb
|
41
50
|
- MIT-LICENSE
|
42
51
|
- Rakefile
|
43
52
|
- README.rdoc
|
@@ -1,127 +0,0 @@
|
|
1
|
-
module CouchI18n
|
2
|
-
class StoresController < ApplicationController
|
3
|
-
def index
|
4
|
-
@available_higher_offsets = []
|
5
|
-
if params[:offset].present?
|
6
|
-
@levels = params[:offset].split('.')
|
7
|
-
# Add higher levels. Do not add the last level, since it is the current one => 0..-2
|
8
|
-
@levels[0..-2].each_with_index do |level_name, i|
|
9
|
-
@available_higher_offsets << {
|
10
|
-
:name => level_name,
|
11
|
-
:offset => @levels[0..i].join('.')
|
12
|
-
}
|
13
|
-
end
|
14
|
-
@couch_i18n_stores = CouchI18n::Store.with_offset(params[:offset], :page => params[:page], :per_page => 30)
|
15
|
-
@available_deeper_offsets = CouchI18n::Store.get_keys_by_level(@levels.size, :startkey => @levels, :endkey => @levels + [{}]).
|
16
|
-
map{|dl| {:name => dl, :offset => [params[:offset], dl].join('.')}}
|
17
|
-
else
|
18
|
-
@couch_i18n_stores = CouchI18n::Store.all(:page => params[:page], :per_page => 30)
|
19
|
-
@available_deeper_offsets = CouchI18n::Store.get_keys_by_level(0).
|
20
|
-
map{|dl| {:name => dl, :offset => dl}}
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
def show
|
25
|
-
@couch_i18n_store = CouchI18n::Store.find(params[:id])
|
26
|
-
end
|
27
|
-
|
28
|
-
def new
|
29
|
-
@couch_i18n_store = CouchI18n::Store.new :key => params[:offset]
|
30
|
-
end
|
31
|
-
|
32
|
-
def create
|
33
|
-
@couch_i18n_store = CouchI18n::Store.new params[:couch_i18n_store]
|
34
|
-
if @couch_i18n_store.save
|
35
|
-
redirect_to({:action => :index, :offset => @couch_i18n_store.key.to_s.sub(/\.[\w\s-]+$/, '')}, :notice => I18n.t('action.create.successful', :model => CouchI18n::Store.model_name.human))
|
36
|
-
else
|
37
|
-
render :action => :new
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
# GET /couch_i18n/stores/:id/edit
|
42
|
-
def edit
|
43
|
-
@couch_i18n_store = CouchI18n::Store.find(params[:id])
|
44
|
-
end
|
45
|
-
|
46
|
-
# PUT /couch_i18n/stores/:id
|
47
|
-
def update
|
48
|
-
@couch_i18n_store = CouchI18n::Store.find(params[:id])
|
49
|
-
if @couch_i18n_store.update_attributes(params[:couch_i18n_store])
|
50
|
-
redirect_to({:action => :index, :offset => @couch_i18n_store.key.to_s.sub(/\.[\w\s-]+$/, '')}, :notice => I18n.t('action.update.successful', :model => CouchI18n::Store.model_name.human))
|
51
|
-
else
|
52
|
-
render :action => :edit
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
def destroy
|
57
|
-
@couch_i18n_store = CouchI18n::Store.find(params[:id])
|
58
|
-
if @couch_i18n_store.destroy
|
59
|
-
flash[:notice] = I18n.t('action.destroy.successful', :model => CouchI18n::Store.model_name.human)
|
60
|
-
end
|
61
|
-
redirect_to({:action => :index, :offset => @couch_i18n_store.key.to_s.sub(/\.\w+$/, '')})
|
62
|
-
end
|
63
|
-
|
64
|
-
# POST /couch_i18n/stores/export
|
65
|
-
# Export to yml, csv or json
|
66
|
-
def export
|
67
|
-
if params[:offset].present?
|
68
|
-
@couch_i18n_stores = CouchI18n::Store.with_offset(params[:offset])
|
69
|
-
else
|
70
|
-
@couch_i18n_stores = CouchI18n::Store.all
|
71
|
-
end
|
72
|
-
base_filename = "export#{Time.now.strftime('%Y%m%d%H%M')}"
|
73
|
-
if params[:exportformat] == 'csv'
|
74
|
-
response.headers['Content-Type'] = 'text/csv'
|
75
|
-
response.headers['Content-Disposition'] = %{attachment; filename="#{base_filename}.csv"}
|
76
|
-
render :text => @couch_i18n_stores.map{|s| [s.key, s.value.to_json].join(',')}.join("\n")
|
77
|
-
elsif params[:exportformat] == 'json'
|
78
|
-
response.headers['Content-Type'] = 'application/json'
|
79
|
-
response.headers['Content-Disposition'] = %{attachment; filename="#{base_filename}.json"}
|
80
|
-
# render :text => CouchI18n.indent_keys(@couch_i18n_stores).to_json # for indented json
|
81
|
-
render :json => @couch_i18n_stores.map{|s| {s.key => s.value}}.to_json
|
82
|
-
else #yaml
|
83
|
-
response.headers['Content-Type'] = 'application/x-yaml'
|
84
|
-
response.headers['Content-Disposition'] = %{attachment; filename="#{base_filename}.yml"}
|
85
|
-
render :text => CouchI18n.indent_keys(@couch_i18n_stores).to_yaml
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
# POST /couch_i18n/stores/import
|
90
|
-
# Import yml files
|
91
|
-
def import
|
92
|
-
redirect_to({:action => :index, :offset => params[:offset]}, :alert => I18n.t('couch_i18n.store.no import file given')) and return unless params[:importfile].present?
|
93
|
-
filename = params[:importfile].original_filename
|
94
|
-
extension = filename.sub(/.*\./, '')
|
95
|
-
if extension == 'yml'
|
96
|
-
hash = YAML.load_file(params[:importfile].tempfile.path) rescue nil
|
97
|
-
redirect_to({:action => :index, :offset => params[:offset]}, :alert => I18n.t('couch_i18n.store.cannot parse yaml')) and return unless hash
|
98
|
-
CouchI18n.traverse_flatten_keys(hash).each do |key, value|
|
99
|
-
existing = CouchI18n::Store.find_by_key(key)
|
100
|
-
if existing
|
101
|
-
if existing.value != value
|
102
|
-
existing.value = value
|
103
|
-
existing.save
|
104
|
-
end
|
105
|
-
else
|
106
|
-
CouchI18n::Store.create :key => key, :value => value
|
107
|
-
end
|
108
|
-
end
|
109
|
-
else
|
110
|
-
redirect_to({:action => :index, :offset => params[:offset]}, :alert => I18n.t('couch_i18n.store.no proper import extension', :extension => extension)) and return
|
111
|
-
end
|
112
|
-
redirect_to({:action => :index, :offset => params[:offset]}, :notice => I18n.t('couch_i18n.store.file imported', :filename => filename))
|
113
|
-
end
|
114
|
-
|
115
|
-
# Very dangarous action, please handle this with care, large removals are supported!
|
116
|
-
# DELETE /couch_i18n/stores/destroy_offset?...
|
117
|
-
def destroy_offset
|
118
|
-
if params[:offset].present?
|
119
|
-
@couch_i18n_stores = CouchI18n::Store.with_offset(params[:offset])
|
120
|
-
else
|
121
|
-
@couch_i18n_stores = CouchI18n::Store.all
|
122
|
-
end
|
123
|
-
@couch_i18n_stores.map(&:destroy)
|
124
|
-
redirect_to({:action => :index}, :notice => I18n.t('couch_i18n.store.offset deleted', :count => @couch_i18n_stores, :offset => params[:offset]))
|
125
|
-
end
|
126
|
-
end
|
127
|
-
end
|
@@ -1,10 +0,0 @@
|
|
1
|
-
= form_for @couch_i18n_store do |f|
|
2
|
-
= render 'shared/error_messages', :target => @couch_i18n_store
|
3
|
-
.field
|
4
|
-
= f.label :key
|
5
|
-
= f.text_field :key, :size => 70
|
6
|
-
.field
|
7
|
-
= f.label :value
|
8
|
-
= f.text_field :value, :size => 70
|
9
|
-
.actions
|
10
|
-
= f.submit @submit || update_button_text
|
@@ -1,46 +0,0 @@
|
|
1
|
-
- title t("couch_i18n.store.index title")
|
2
|
-
.destroy-link
|
3
|
-
= link_to t('couch_i18n.store.destroy offset link'), destroy_offset_couch_i18n_stores_path(:offset => params[:offset]), :method => :delete, :confirm => (defined?(:are_you_sure) ? are_you_sure : t('couch_i18n.store.are you sure'))
|
4
|
-
.import-form
|
5
|
-
= form_tag({:action => :import}, :multipart => true) do
|
6
|
-
= file_field_tag :importfile
|
7
|
-
= submit_tag I18n.t('couch_i18n.store.import')
|
8
|
-
.export-form
|
9
|
-
= form_tag :action => :export do
|
10
|
-
= hidden_field_tag :offset, params[:offset]
|
11
|
-
= select_tag :exportformat, options_for_select(%w[yml csv json], params[:exportformat])
|
12
|
-
= submit_tag I18n.t('couch_i18n.store.export')
|
13
|
-
.offset-navigation-block.block
|
14
|
-
.offset-navigation-higher
|
15
|
-
- for offset in @available_higher_offsets
|
16
|
-
= link_to offset[:name], :offset => offset[:offset]
|
17
|
-
.offset-navigation-form
|
18
|
-
= form_tag({}, :method => :get )do
|
19
|
-
- if params[:offset].present?
|
20
|
-
= link_to I18n.t('couch_i18n.store.go to zero offset'), :offset => nil
|
21
|
-
= text_field_tag :offset, params[:offset], :size => 60
|
22
|
-
= "(#{@couch_i18n_stores.total_entries})"
|
23
|
-
= submit_tag I18n.t('couch_i18n.store.go to offset')
|
24
|
-
.offset-navigation-deeper
|
25
|
-
- for offset in @available_deeper_offsets
|
26
|
-
= link_to offset[:name], :offset => offset[:offset]
|
27
|
-
- if @couch_i18n_stores.any?
|
28
|
-
= paginate @couch_i18n_stores, :right => 3, :left => 3
|
29
|
-
%table.index-table
|
30
|
-
%thead
|
31
|
-
%tr
|
32
|
-
%th= CouchI18n::Store.human_attribute_name(:key)
|
33
|
-
%th= CouchI18n::Store.human_attribute_name(:value)
|
34
|
-
%th
|
35
|
-
%tbody
|
36
|
-
- @couch_i18n_stores.each do |couch_i18n_store|
|
37
|
-
%tr
|
38
|
-
%td= link_to couch_i18n_store.key[(params[:offset].try(:size) || 0)..-1].sub(/^\./, ''), edit_couch_i18n_store_path(couch_i18n_store)
|
39
|
-
%td= link_to couch_i18n_store.value, edit_couch_i18n_store_path(couch_i18n_store)
|
40
|
-
%td= link_to link_to_edit_content(couch_i18n_store), edit_couch_i18n_store_path(couch_i18n_store)
|
41
|
-
%td= link_to link_to_destroy_content(couch_i18n_store),couch_i18n_store_path(couch_i18n_store), :confirm => are_you_sure, :method => :delete
|
42
|
-
- else
|
43
|
-
%h3= t("couch_i18n_store.none found")
|
44
|
-
|
45
|
-
- content_for :page_links do
|
46
|
-
= link_to link_to_new_content(:couch_i18n_store), new_couch_i18n_store_path(:offset => params[:offset])
|