couch_i18n 0.3.0 → 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.
Files changed (54) hide show
  1. checksums.yaml +7 -0
  2. data/README.rdoc +0 -1
  3. data/app/assets/javascripts/couch_i18n/application.js.coffee +8 -0
  4. data/app/assets/stylesheets/couch_i18n/application.sass +4 -0
  5. data/app/assets/stylesheets/couch_i18n/components/_buttons.sass +11 -0
  6. data/app/assets/stylesheets/couch_i18n/components/_forms.sass +45 -0
  7. data/app/assets/stylesheets/couch_i18n/components/_offset_navigation.sass +19 -0
  8. data/app/assets/stylesheets/couch_i18n/foundation_and_overrides.scss +1447 -0
  9. data/app/assets/stylesheets/couch_i18n/{structure.css.scss → structure.scss} +0 -24
  10. data/app/controllers/couch_i18n/application_controller.rb +5 -1
  11. data/app/controllers/couch_i18n/translations_controller.rb +24 -19
  12. data/app/models/couch_i18n/translation.rb +81 -35
  13. data/app/views/couch_i18n/application/_error_messages.html.slim +6 -0
  14. data/app/views/couch_i18n/translations/_form.html.slim +15 -0
  15. data/app/views/couch_i18n/translations/edit.html.slim +2 -0
  16. data/app/views/couch_i18n/translations/index.html.slim +91 -0
  17. data/app/views/couch_i18n/translations/new.html.slim +2 -0
  18. data/app/views/kaminari/couch_i18n/_first_page.html.erb +3 -0
  19. data/app/views/kaminari/couch_i18n/_first_page.html.slim +2 -0
  20. data/app/views/kaminari/couch_i18n/_gap.html.erb +3 -0
  21. data/app/views/kaminari/couch_i18n/_gap.html.slim +2 -0
  22. data/app/views/kaminari/couch_i18n/_last_page.html.erb +3 -0
  23. data/app/views/kaminari/couch_i18n/_last_page.html.slim +2 -0
  24. data/app/views/kaminari/couch_i18n/_next_page.html.erb +3 -0
  25. data/app/views/kaminari/couch_i18n/_next_page.html.slim +2 -0
  26. data/app/views/kaminari/couch_i18n/_page.html.erb +3 -0
  27. data/app/views/kaminari/couch_i18n/_page.html.slim +2 -0
  28. data/app/views/kaminari/couch_i18n/_paginator.html.erb +17 -0
  29. data/app/views/kaminari/couch_i18n/_paginator.html.slim +12 -0
  30. data/app/views/kaminari/couch_i18n/_prev_page.html.erb +3 -0
  31. data/app/views/kaminari/couch_i18n/_prev_page.html.slim +2 -0
  32. data/app/views/layouts/couch_i18n/application.html.slim +28 -0
  33. data/config/initializers/assets.rb +1 -0
  34. data/config/locales/couch_i18n.en.yml +8 -2
  35. data/config/routes.rb +2 -1
  36. data/lib/couch_i18n/active_model_errors.rb +2 -2
  37. data/lib/couch_i18n/backend.rb +1 -5
  38. data/lib/couch_i18n/engine.rb +2 -0
  39. data/lib/couch_i18n/store.rb +24 -12
  40. data/lib/couch_i18n/version.rb +3 -0
  41. data/lib/couch_i18n.rb +30 -9
  42. metadata +51 -43
  43. data/app/assets/javascripts/couch_i18n/application.js +0 -10
  44. data/app/assets/stylesheets/couch_i18n/application.css +0 -7
  45. data/app/assets/stylesheets/couch_i18n/bootstrap_and_override.css.sass +0 -6
  46. data/app/views/couch_i18n/application/_error_messages.html.haml +0 -6
  47. data/app/views/couch_i18n/translations/_form.html.haml +0 -17
  48. data/app/views/couch_i18n/translations/edit.html.haml +0 -4
  49. data/app/views/couch_i18n/translations/index.html.haml +0 -84
  50. data/app/views/couch_i18n/translations/new.html.haml +0 -4
  51. data/app/views/couch_i18n/translations/new.html.haml~ +0 -4
  52. data/app/views/layouts/couch_i18n/application.html.haml +0 -27
  53. /data/app/assets/stylesheets/couch_i18n/{alerts.css.scss → alerts.scss} +0 -0
  54. /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,10 +1,14 @@
1
1
  module CouchI18n
2
2
  class ApplicationController < ::ApplicationController
3
- before_filter :authorize_user
3
+ before_action :authorize_user
4
4
  layout :couch_i18n_layout
5
5
 
6
6
  private
7
7
 
8
+ def cmtool_user
9
+ main_app.cmtool_user
10
+ end
11
+
8
12
  def couch_i18n_layout
9
13
  defined?(Cmtool) ? 'cmtool/application' : 'couch_i18n/application'
10
14
  # Does not integrate well with cmtool layout at the moment (2012-12-17)
@@ -40,16 +40,16 @@ module CouchI18n
40
40
  end
41
41
 
42
42
  def new
43
- @translation = CouchI18n::Translation.new :key => params[:offset]
43
+ @translation = CouchI18n::Translation.new translation_key: params[:offset]
44
44
  end
45
45
 
46
46
  def create
47
- @translation = CouchI18n::Translation.new params[:translation]
47
+ @translation = CouchI18n::Translation.new translation_params
48
48
  if @translation.value.present? && params[:is_json].present?
49
49
  @translation.value = JSON.parse(@translation.value)
50
50
  end
51
51
  if @translation.save
52
- redirect_to({:action => :index, :offset => @translation.key.to_s.sub(/\.[\w\s-]+$/, '')}, :notice => I18n.t('couch_i18n.action.create.successful', :model => CouchI18n::Translation.model_name.human))
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))
53
53
  else
54
54
  render :action => :new
55
55
  end
@@ -64,11 +64,12 @@ module CouchI18n
64
64
  def update
65
65
  @translation = CouchI18n::Translation.find(params[:id])
66
66
  @translation.translated = true
67
- if params[:translation]["value"].present? && params[:is_json].present?
68
- params[:translation]["value"] = JSON.parse(params[:translation]["value"])
67
+ tparams = translation_params
68
+ if tparams["value"].present? && params[:is_json].present?
69
+ tparams["value"] = JSON.parse(tparams["value"])
69
70
  end
70
- if @translation.update_attributes(params[:translation])
71
- redirect_to({:action => :index, :offset => @translation.key.to_s.sub(/\.[\w\s-]+$/, '')}, :notice => I18n.t('couch_i18n.action.update.successful', :model => CouchI18n::Translation.model_name.human))
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))
72
73
  else
73
74
  render :action => :edit
74
75
  end
@@ -79,7 +80,7 @@ module CouchI18n
79
80
  if @translation.destroy
80
81
  flash[:notice] = I18n.t('couch_i18n.action.destroy.successful', :model => CouchI18n::Translation.model_name.human)
81
82
  end
82
- redirect_to({:action => :index, :offset => @translation.key.to_s.sub(/\.\w+$/, '')})
83
+ redirect_to({:action => :index, :offset => @translation.translation_key.to_s.sub(/\.\w+$/, '')})
83
84
  end
84
85
 
85
86
  # POST /couch_i18n/translations/export
@@ -102,12 +103,12 @@ module CouchI18n
102
103
  if params[:exportformat] == 'csv'
103
104
  response.headers['Content-Type'] = 'text/csv'
104
105
  response.headers['Content-Disposition'] = %{attachment; filename="#{base_filename}.csv"}
105
- render :text => @translations.map{|s| [s.key, s.value.to_json].join(',')}.join("\n")
106
+ render :text => @translations.map{|s| [s.translation_key, s.translation_value.to_json].join(',')}.join("\n")
106
107
  elsif params[:exportformat] == 'json'
107
108
  response.headers['Content-Type'] = 'application/json'
108
109
  response.headers['Content-Disposition'] = %{attachment; filename="#{base_filename}.json"}
109
110
  # render :text => CouchI18n.indent_keys(@translations).to_json # for indented json
110
- render :json => @translations.map{|s| {s.key => s.value}}.to_json
111
+ render :json => @translations.map{|s| {s.translation_key => s.translation_value}}.to_json
111
112
  else #yaml
112
113
  response.headers['Content-Type'] = 'application/x-yaml'
113
114
  response.headers['Content-Disposition'] = %{attachment; filename="#{base_filename}.yml"}
@@ -118,28 +119,28 @@ module CouchI18n
118
119
  # POST /couch_i18n/translations/import
119
120
  # Import yml files
120
121
  def import
121
- redirect_to({:action => :index, :offset => params[:offset]}, :alert => I18n.t('couch_i18n.translation.no import file given')) and return unless params[:importfile].present?
122
+ redirect_to({:action => :index, :offset => params[:offset]}, :alert => I18n.t('couch_i18n.import.no_file_given')) and return unless params[:importfile].present?
122
123
  filename = params[:importfile].original_filename
123
124
  extension = filename.sub(/.*\./, '')
124
125
  if extension == 'yml'
125
126
  hash = YAML.load_file(params[:importfile].tempfile.path) rescue nil
126
- redirect_to({:action => :index, :offset => params[:offset]}, :alert => I18n.t('couch_i18n.translation.cannot parse yaml')) and return unless hash
127
+ redirect_to({:action => :index, :offset => params[:offset]}, :alert => I18n.t('couch_i18n.import.cannot_parse')) and return unless hash
127
128
  CouchI18n.traverse_flatten_keys(hash).each do |key, value|
128
- existing = CouchI18n::Translation.find_by_key(key)
129
+ existing = CouchI18n::Translation.find_by_translation_key(key)
129
130
  if existing
130
- if existing.value != value
131
- existing.value = value
131
+ if existing.translation_value != value || !existing.translated?
132
+ existing.translation_value = value
132
133
  existing.translated = true
133
134
  existing.save
134
135
  end
135
136
  else
136
- CouchI18n::Translation.create :key => key, :value => value
137
+ CouchI18n::Translation.create translation_key: key, translation_value: value
137
138
  end
138
139
  end
139
140
  else
140
- redirect_to({:action => :index, :offset => params[:offset]}, :alert => I18n.t('couch_i18n.translation.no proper import extension', :extension => extension)) and return
141
+ redirect_to({:action => :index, :offset => params[:offset]}, :alert => I18n.t('couch_i18n.import.extension_not_valid', :extension => extension)) and return
141
142
  end
142
- redirect_to({:action => :index, :offset => params[:offset]}, :notice => I18n.t('couch_i18n.translation.file imported', :filename => filename))
143
+ redirect_to({:action => :index, :offset => params[:offset]}, :notice => I18n.t('couch_i18n.import.notice', :filename => filename))
143
144
  end
144
145
 
145
146
  # Very dangarous action, please handle this with care, large removals are supported!
@@ -151,7 +152,7 @@ module CouchI18n
151
152
  @translations = CouchI18n::Translation.all
152
153
  end
153
154
  @translations.map(&:destroy)
154
- redirect_to({:action => :index}, :notice => I18n.t('couch_i18n.translation.offset deleted', :count => @translations.size, :offset => params[:offset]))
155
+ redirect_to({:action => :index}, :notice => I18n.t('couch_i18n.general.offset_deleted_notice', :count => @translations.size, :offset => params[:offset]))
155
156
  end
156
157
 
157
158
  private
@@ -160,5 +161,9 @@ module CouchI18n
160
161
  params[:untranslated].presence
161
162
  end
162
163
  helper_method :untranslated?
164
+
165
+ def translation_params
166
+ params.require(:translation).permit(:translation_key, :translation_value, :translated)
167
+ end
163
168
  end
164
169
  end
@@ -3,53 +3,86 @@ module CouchI18n
3
3
  include SimplyStored::Couch
4
4
  per_page_method :limit_value
5
5
 
6
- property :key
7
- property :value
6
+ property :translation_value
8
7
  property :translated, type: :boolean, default: true
9
8
 
10
- validates_uniqueness_of :key
9
+ def translation_key
10
+ id.present? ? id[3..-1] : nil
11
+ end
11
12
 
12
- after_save :reload_i18n
13
+ def key
14
+ translation_key
15
+ end
13
16
 
14
- view :all_documents, :key => :key
15
- view :by_key, :key => :key
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.key.split('.').slice(0, -1), 1);
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, key: :key, conditions: "!doc['translated']"
24
- view :by_value, key: :value
25
- view :untranslated_by_value, key: :value, conditions: "!doc['translated']"
26
- view :by_key_part, type: :custom, map_function: %|function(doc){
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){
27
38
  if(doc.ruby_class && doc.ruby_class == 'CouchI18n::Translation') {
28
- var parts = doc.key.split('.');
29
- for(var i = 0; i < parts.length; i++){
30
- emit(parts[i], 1);
31
- }
39
+ doc._id.substr(3).split('.').forEach(function(key_part){
40
+ emit(key_part, 1)
41
+ })
32
42
  }
33
43
  }|, reduce_function: '_count'
34
44
 
35
- view :untranslated_by_key_part, type: :custom, map_function: %|function(doc){
45
+ view :untranslated_by_translation_key_part, type: :custom, map_function: %|function(doc){
36
46
  if(doc.ruby_class && doc.ruby_class == 'CouchI18n::Translation' && !doc.translated) {
37
- var parts = doc.key.split('.');
38
- for(var i = 0; i < parts.length; i++){
39
- emit(parts[i], 1);
40
- }
47
+ doc._id.substr(3).split('.').forEach(function(key_part){
48
+ emit(key_part, 1)
49
+ })
41
50
  }
42
51
  }|, reduce_function: '_count'
43
52
 
44
- def self.get_keys_by_level(level = 0, options = {})
45
- data = database.view(with_key_array(options.merge(:group_level => level.succ)))["rows"]
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"]
46
55
  # data = data.select{|h| h["key"].size > level } # Only select ones that have a deeper nesting
47
56
  data.map{|h| h['key'][level].try(:to_sym)}.compact
48
57
  end
49
58
 
59
+ def translation_key=(val)
60
+ self.id = "t::#{val}"
61
+ end
62
+
50
63
  # Shorthand for selecting all stored with a given offset
51
64
  def self.with_offset(offset, options = {})
52
- CouchI18n::Translation.find_all_by_key("#{offset}.".."#{offset}.ZZZZZZZZZ", options)
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
53
86
  end
54
87
 
55
88
  # Find all records having the term part in their key
@@ -60,9 +93,9 @@ module CouchI18n
60
93
  # find_all_by_part('action')
61
94
  # will return the first two since they have action as key part
62
95
  def self.find_all_by_key_part(part, options = {})
63
- total_entries = database.view(by_key_part(key: part, reduce: true))
96
+ total_entries = database.view(by_translation_key_part(key: part, reduce: true))
64
97
  with_pagination_options options.merge(total_entries: total_entries) do |options|
65
- database.view(by_key_part(options.merge(key: part, reduce: false, include_docs: true)))
98
+ database.view(by_translation_key_part(options.merge(key: part, reduce: false, include_docs: true)))
66
99
  end
67
100
  end
68
101
 
@@ -74,9 +107,9 @@ module CouchI18n
74
107
  # find_all_by_part('action')
75
108
  # will return the first two since they have action as key part
76
109
  def self.find_all_untranslated_by_key_part(part, options = {})
77
- total_entries = database.view(by_key_part(key: part, reduce: true))
110
+ total_entries = database.view(untranslated_by_translation_key_part(key: part, reduce: true))
78
111
  with_pagination_options options.merge(total_entries: total_entries) do |options|
79
- database.view(untranslated_by_key_part(options.merge(key: part, reduce: false, include_docs: true)))
112
+ database.view(untranslated_by_translation_key_part(options.merge(key: part, reduce: false, include_docs: true)))
80
113
  end
81
114
  end
82
115
 
@@ -88,9 +121,23 @@ module CouchI18n
88
121
  # find_all_untranslated_by_value('Value')
89
122
  # will return en.action.two
90
123
  def self.find_all_untranslated_by_value(part, options = {})
91
- total_entries = database.view(untranslated_by_value(key: part, reduce: true))
124
+ total_entries = database.view(untranslated_by_translation_value(key: part, reduce: true))
92
125
  with_pagination_options options.merge(total_entries: total_entries) do |options|
93
- database.view(untranslated_by_value(options.merge(key: part, reduce: false, include_docs: true)))
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)))
94
141
  end
95
142
  end
96
143
 
@@ -98,7 +145,7 @@ module CouchI18n
98
145
  def self.untranslated(options = {})
99
146
  total_entries = database.view(untranslated_view(options.slice(:key, :keys, :startkey, :endkey).merge(reduce: true)))
100
147
  with_pagination_options options.merge(total_entries: total_entries) do |options|
101
- database.view(untranslated_view(options))
148
+ database.view(untranslated_view(options.merge(reduce: false, include_docs: true)))
102
149
  end
103
150
  end
104
151
 
@@ -106,11 +153,10 @@ module CouchI18n
106
153
  CouchI18n::Translation.untranslated(options.merge(key: "#{offset}.".."#{offset}.ZZZZZZZZZ"))
107
154
  end
108
155
 
109
- # Expire I18n when record is update
110
- def reload_i18n
111
- Rails.cache.write("couch_i18n-#{key}", value)
112
- #I18n.reload!
113
- #I18n.cache_store.clear if I18n.respond_to?(:cache_store) && I18n.cache_store.respond_to?(:clear)
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
114
160
  end
115
161
 
116
162
  def self.deeper_keys_for_offset( offset )
@@ -0,0 +1,6 @@
1
+ -if target.errors.any?
2
+ #errorExplanation
3
+ h2= t('couch_i18n.errors.title', :count => target.errors.count)
4
+ ul
5
+ - target.errors.full_messages.each do |msg|
6
+ li= msg
@@ -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,2 @@
1
+ - title t("couch_i18n.action.edit.title")
2
+ = render 'form'
@@ -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 &#215
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 &#215
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,2 @@
1
+ - title t("couch_i18n.action.new.title")
2
+ = render 'form', submit: create_button_text
@@ -0,0 +1,3 @@
1
+ <li>
2
+ <%= link_to_unless current_page.first?, raw(t 'views.pagination.first'), url, :remote => remote %>
3
+ </li>
@@ -0,0 +1,2 @@
1
+ li
2
+ = link_to_unless current_page.first?, raw(t 'views.pagination.first'), url, :remote => remote
@@ -0,0 +1,3 @@
1
+ <li class="unavailable">
2
+ <%= link_to raw(t 'views.pagination.truncate'), '#' %>
3
+ </li>
@@ -0,0 +1,2 @@
1
+ li.unavailable
2
+ = link_to raw(t 'views.pagination.truncate'), '#'
@@ -0,0 +1,3 @@
1
+ <li>
2
+ <%= link_to_unless current_page.last?, raw(t 'views.pagination.last'), url, {:remote => remote} %>
3
+ </li>
@@ -0,0 +1,2 @@
1
+ li
2
+ = link_to_unless current_page.last?, raw(t 'views.pagination.last'), url, {:remote => remote}
@@ -0,0 +1,3 @@
1
+ <li>
2
+ <%= link_to_unless current_page.last?, raw(t 'views.pagination.next'), url, :rel => 'next', :remote => remote %>
3
+ </li>
@@ -0,0 +1,2 @@
1
+ li
2
+ = link_to_unless current_page.last?, raw(t 'views.pagination.next'), url, :rel => 'next', :remote => remote
@@ -0,0 +1,3 @@
1
+ <li class="<%= 'current' if page.current? %>">
2
+ <%= link_to page, page.current? ? '#' : url, {:remote => remote, :rel => page.next? ? 'next' : page.prev? ? 'prev' : nil} %>
3
+ </li>
@@ -0,0 +1,2 @@
1
+ li class: "#{'current' if page.current?}"
2
+ = link_to page, page.current? ? '#' : url, {:remote => remote, :rel => page.next? ? 'next' : page.prev? ? 'prev' : nil}
@@ -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?
@@ -0,0 +1,3 @@
1
+ <li>
2
+ <%= link_to_unless current_page.first?, raw(t 'views.pagination.previous'), url, :rel => 'prev', :remote => remote %>
3
+ </li>
@@ -0,0 +1,2 @@
1
+ li
2
+ = link_to_unless current_page.first?, raw(t 'views.pagination.previous'), url, :rel => 'prev', :remote => remote
@@ -0,0 +1,28 @@
1
+ doctype html
2
+ html
3
+ head
4
+ title= defined?(site_title) ? site_title : I18n.t('couch_i18n.general.site_title')
5
+ /![if lt IE 9]
6
+ | <script src="http://html5shim.googlecode.com/svn/trunk/html5.js" type="text/javascript"></script
7
+ = csrf_meta_tags
8
+ = stylesheet_link_tag 'couch_i18n/application'
9
+ = javascript_include_tag 'couch_i18n/application'
10
+ meta name="viewport" content="width=device-width, initial-scale=1.0"
11
+ = yield :head
12
+ body
13
+ - if defined?(Cmtool)
14
+ = render 'cmtool/application/menu'
15
+ - else
16
+ nav.top-bar data-topbar="" role="navigation"
17
+ ul.title-area
18
+ li.name
19
+ h1
20
+ a href=couch_i18n.root_path = yield :title
21
+ li.toggle-topbar.menu-icon
22
+ a href="#"
23
+ span Menu
24
+ .container
25
+ = render 'alerts'
26
+ = yield
27
+ .row: .small-12.columns
28
+ .form-actions=yield :page_links
@@ -0,0 +1 @@
1
+ Rails.application.config.assets.precompile += %w[ couch_i18n/application.css couch_i18n/application.js ]
@@ -13,6 +13,7 @@ en:
13
13
  label: Translations
14
14
  title: Translations
15
15
  new:
16
+ title: New translation
16
17
  label: New
17
18
  update:
18
19
  button_text: Update
@@ -31,6 +32,7 @@ en:
31
32
  boolean_true: 'yes'
32
33
  go_to_offset: Go to offset
33
34
  go_to_zero_offset: x
35
+ offset_deleted_notice: There were %{count} translations deleted having key offset %{offset}
34
36
  find_part: Find key part
35
37
  find_value: Find value
36
38
  none_found: No translations found
@@ -42,6 +44,10 @@ en:
42
44
  button: Import
43
45
  label: Import
44
46
  description: If you import keys, existing keys will be overwritten
47
+ notice: File imported
48
+ extension_not_valid: Please use the YAML file format for uploads
49
+ cannot_parse: The uploaded file cannot be parsed as valid translations
50
+ no_file_given: Please supply a file for upload
45
51
  activemodel:
46
52
  models:
47
53
  couch_i18n:
@@ -52,6 +58,6 @@ en:
52
58
  attributes:
53
59
  couch_i18n:
54
60
  translation:
55
- key: Key
56
- value: Value
61
+ translation_key: Key
62
+ translation_value: Value
57
63
  translated: 'Translated?'
data/config/routes.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  CouchI18n::Engine.routes.draw do
2
2
  root :to => "translations#index"
3
- resources :translations do
3
+ # allow escaped forms (%+) and unescaped forms (: ) (note the space!!) as id
4
+ resources :translations, constraints: {id: /[\w:% \.\+]+/} do
4
5
  collection do
5
6
  post :export
6
7
  post :import