couch_i18n 0.0.4 → 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- 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])
|