couch_i18n 0.0.3 → 0.0.4
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 +119 -8
- data/app/controllers/couch_i18n/stores_controller.rb +68 -1
- data/app/views/couch_i18n/stores/_form.html.haml +1 -1
- data/app/views/couch_i18n/stores/edit.html.haml +1 -1
- data/app/views/couch_i18n/stores/index.html.haml +27 -12
- data/app/views/couch_i18n/stores/new.html.haml +1 -1
- data/lib/couch_i18n/backend.rb +99 -0
- data/lib/couch_i18n/store.rb +5 -0
- data/lib/couch_i18n.rb +29 -6
- metadata +7 -12
data/README.rdoc
CHANGED
@@ -9,10 +9,7 @@ database type:
|
|
9
9
|
Now all translations are ported to the database. If you change then now in the
|
10
10
|
yaml files, they will nolonger be displayed in the website. They should be managed
|
11
11
|
in the database. This gem also provides a translation management system. To place this
|
12
|
-
in your own design,
|
13
|
-
following content:
|
14
|
-
= render :template => '/layouts/application'
|
15
|
-
Or create your own really nice template. Let me know if there is a nice layout!
|
12
|
+
in your own design, read the layout section.
|
16
13
|
Your Gemfile should look like:
|
17
14
|
gem 'simply_stored', :git => 'git://github.com/bterkuile/simply_stored.git'
|
18
15
|
gem 'couch_i18n'
|
@@ -20,12 +17,24 @@ Your Gemfile should look like:
|
|
20
17
|
And in your config routes put:
|
21
18
|
namespace :couch_i18n do
|
22
19
|
root :to => "stores#index"
|
23
|
-
resources :stores
|
20
|
+
resources :stores do
|
21
|
+
collection do
|
22
|
+
post :export
|
23
|
+
post :import
|
24
|
+
delete :destroy_offset
|
25
|
+
end
|
26
|
+
end
|
24
27
|
end
|
25
28
|
Or to put is at a different location:
|
26
29
|
namespace :translations, :module => :couch_i18n, :as => 'couch_i18n' do
|
27
30
|
root :to => "stores#index"
|
28
|
-
resources :stores
|
31
|
+
resources :stores do
|
32
|
+
collection do
|
33
|
+
post :export
|
34
|
+
post :import
|
35
|
+
delete :destroy_offset
|
36
|
+
end
|
37
|
+
end
|
29
38
|
end
|
30
39
|
The intention is to make this a mountable application, but this will not happen
|
31
40
|
before Rails 3.1 is officially out. But beware of using this if your application
|
@@ -52,16 +61,118 @@ initializer: _config/initializers/couch_I18n_modifications.rb_
|
|
52
61
|
end
|
53
62
|
And in _config/authorization_rules.rb_ put your personalized version of:
|
54
63
|
role :translator do
|
55
|
-
has_permission_on :couch_i18n_stores, :to => :manage
|
64
|
+
has_permission_on :couch_i18n_stores, :to => [:manage, :import, :export, :destroy_offset]
|
56
65
|
end
|
57
66
|
Beware that a permission denied message will appear when the server is restarted
|
58
67
|
this way. This is because the current user is set in ApplicationController which
|
59
68
|
is not part of the CouchI18n controller stack.
|
60
69
|
|
70
|
+
== couch_i18n translations
|
71
|
+
Ofcourse couch_i18n is working with translations as well. To get them working import
|
72
|
+
the following yamlL
|
73
|
+
en:
|
74
|
+
New: New
|
75
|
+
Edit: Edit
|
76
|
+
Show: Show
|
77
|
+
Back: Back
|
78
|
+
Save: Save
|
79
|
+
Create: Create
|
80
|
+
Are you sure: 'Are you sure?'
|
81
|
+
activemodel:
|
82
|
+
models:
|
83
|
+
couch_i18n:
|
84
|
+
store: Translation
|
85
|
+
attributes:
|
86
|
+
couch_i18n:
|
87
|
+
store:
|
88
|
+
key: Key
|
89
|
+
value: Value
|
90
|
+
action:
|
91
|
+
create:
|
92
|
+
successful: %{model} successfully created
|
93
|
+
update:
|
94
|
+
successful: %{model} successfully updated
|
95
|
+
destroy:
|
96
|
+
successful: %{model} successfully removed
|
97
|
+
chouch_i18n:
|
98
|
+
store:
|
99
|
+
index title: Translations
|
100
|
+
none found: No translations present
|
101
|
+
new title: New translation
|
102
|
+
show title: Translation
|
103
|
+
edit title: Edit translation
|
104
|
+
go to offset: Go to
|
105
|
+
got to zero offset: x
|
106
|
+
export: Export
|
107
|
+
import: Import
|
108
|
+
offset deleted: "%{count} translations with offset %{offset} are deleted"
|
109
|
+
no proper import extension: Files with extension%{extension} cannot be imported
|
110
|
+
no import file given: There is no file to be imported
|
111
|
+
cannot parse yaml: The file cannot be read
|
112
|
+
file imported: File %{filename} was successfully imported
|
113
|
+
# The following tranlation will only work if no are_you_sure helper is present
|
114
|
+
are you sure: 'Are you sure?'
|
115
|
+
destroy offset link: Delete all translations with current offset
|
116
|
+
# The following tranlation will only work if no site_title helper is present
|
117
|
+
site_title: Translations
|
118
|
+
== couch_i18n helpers
|
119
|
+
The following helpers are assumed:
|
120
|
+
module CouchI18nViewHelpers
|
121
|
+
def title(str)
|
122
|
+
content_for :title do
|
123
|
+
content_tag(:h1, str)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
def link_to_new_content(obj)
|
127
|
+
t('New')
|
128
|
+
end
|
129
|
+
def link_to_edit_content(obj = nil)
|
130
|
+
t('Edit')
|
131
|
+
end
|
132
|
+
def link_to_show_content(obj = nil)
|
133
|
+
t('Show')
|
134
|
+
end
|
135
|
+
def link_to_index_content(singular_name)
|
136
|
+
t('Back')
|
137
|
+
end
|
138
|
+
def link_to_destroy_content(obj = nil)
|
139
|
+
t('Delete')
|
140
|
+
end
|
141
|
+
def update_button_text(obj = nil)
|
142
|
+
t('Save')
|
143
|
+
end
|
144
|
+
def create_button_text(obj = nil)
|
145
|
+
t('Create')
|
146
|
+
end
|
147
|
+
def boolean_text(truefalse)
|
148
|
+
truefalse ? t('boolean true') : t('boolean false')
|
149
|
+
end
|
150
|
+
def are_you_sure(obj = nil)
|
151
|
+
t('Are you sure')
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
== couch_i18n layout
|
156
|
+
This gem comes with its own layout file, but you can ofcourse use your own. To do this place a layout at your application with the
|
157
|
+
path: <tt>app/views/layouts/couch_i18n/application.html.haml</tt>
|
158
|
+
It should <tt>yield</tt> the following parts:
|
159
|
+
!!!
|
160
|
+
%html
|
161
|
+
%head
|
162
|
+
%title= defined?(site_title) ? site_title : I18n.t('couch_i18n.store.site_title')
|
163
|
+
= csrf_meta_tag
|
164
|
+
= yield :head
|
165
|
+
%body
|
166
|
+
#page-wrapper
|
167
|
+
#page-content
|
168
|
+
%h1= yield :title
|
169
|
+
= yield
|
170
|
+
#page-links= yield :page_links
|
61
171
|
== TODO
|
62
172
|
Here my todo list for this project. Makes it insightful for everybody what is on
|
63
173
|
the planning of being made.
|
64
174
|
* Check on locale inclusion with are you sure? force creation of new locale. Mostly a stupic mistake omitting these.
|
65
|
-
* Add grouped deletes. Dangerous, but controllable using the declarative_authorization example
|
66
175
|
* Add grouped search/replaces to move one group of translations to another section. Same comment as above
|
67
176
|
* Search through values. If anyone has a better idea than searching by ruby through all the translations or adding lucene please feel free.
|
177
|
+
* A lot of testing
|
178
|
+
* Add error_messages partial to manual
|
@@ -11,7 +11,7 @@ module CouchI18n
|
|
11
11
|
:offset => @levels[0..i].join('.')
|
12
12
|
}
|
13
13
|
end
|
14
|
-
@couch_i18n_stores = CouchI18n::Store.
|
14
|
+
@couch_i18n_stores = CouchI18n::Store.with_offset(params[:offset], :page => params[:page], :per_page => 30)
|
15
15
|
@available_deeper_offsets = CouchI18n::Store.get_keys_by_level(@levels.size, :startkey => @levels, :endkey => @levels + [{}]).
|
16
16
|
map{|dl| {:name => dl, :offset => [params[:offset], dl].join('.')}}
|
17
17
|
else
|
@@ -37,9 +37,13 @@ module CouchI18n
|
|
37
37
|
render :action => :new
|
38
38
|
end
|
39
39
|
end
|
40
|
+
|
41
|
+
# GET /couch_i18n/stores/:id/edit
|
40
42
|
def edit
|
41
43
|
@couch_i18n_store = CouchI18n::Store.find(params[:id])
|
42
44
|
end
|
45
|
+
|
46
|
+
# PUT /couch_i18n/stores/:id
|
43
47
|
def update
|
44
48
|
@couch_i18n_store = CouchI18n::Store.find(params[:id])
|
45
49
|
if @couch_i18n_store.update_attributes(params[:couch_i18n_store])
|
@@ -56,5 +60,68 @@ module CouchI18n
|
|
56
60
|
end
|
57
61
|
redirect_to({:action => :index, :offset => @couch_i18n_store.key.to_s.sub(/\.\w+$/, '')})
|
58
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
|
59
126
|
end
|
60
127
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
- title t("couch_i18n.store.
|
1
|
+
- title t("couch_i18n.store.edit title")
|
2
2
|
= render 'form'
|
3
3
|
- content_for :page_links do
|
4
4
|
= link_to link_to_index_content(:couch_i18n_stores), couch_i18n_stores_path(:offset => params[:offset] || @couch_i18n_store.key.to_s.sub(/\.[\w\s-]+$/, ''))
|
@@ -1,14 +1,29 @@
|
|
1
|
-
- title t("couch_i18n.store.
|
2
|
-
-
|
3
|
-
= link_to offset
|
4
|
-
|
5
|
-
|
6
|
-
=
|
7
|
-
|
8
|
-
|
9
|
-
=
|
10
|
-
|
11
|
-
|
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]
|
12
27
|
- if @couch_i18n_stores.any?
|
13
28
|
= paginate @couch_i18n_stores, :right => 3, :left => 3
|
14
29
|
%table.index-table
|
@@ -25,7 +40,7 @@
|
|
25
40
|
%td= link_to link_to_edit_content(couch_i18n_store), edit_couch_i18n_store_path(couch_i18n_store)
|
26
41
|
%td= link_to link_to_destroy_content(couch_i18n_store),couch_i18n_store_path(couch_i18n_store), :confirm => are_you_sure, :method => :delete
|
27
42
|
- else
|
28
|
-
%h3= t("couch_i18n_store.
|
43
|
+
%h3= t("couch_i18n_store.none found")
|
29
44
|
|
30
45
|
- content_for :page_links do
|
31
46
|
= link_to link_to_new_content(:couch_i18n_store), new_couch_i18n_store_path(:offset => params[:offset])
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require 'i18n/backend/base'
|
2
|
+
require 'active_support/json'
|
3
|
+
require 'active_support/ordered_hash' # active_support/json/encoding uses ActiveSupport::OrderedHash but does not require it
|
4
|
+
|
5
|
+
module CouchI18n
|
6
|
+
class Backend
|
7
|
+
# This is a basic backend for key value stores. It receives on
|
8
|
+
# initialization the store, which should respond to three methods:
|
9
|
+
#
|
10
|
+
# * store#[](key) - Used to get a value
|
11
|
+
# * store#[]=(key, value) - Used to set a value
|
12
|
+
# * store#keys - Used to get all keys
|
13
|
+
#
|
14
|
+
# Since these stores only supports string, all values are converted
|
15
|
+
# to JSON before being stored, allowing it to also store booleans,
|
16
|
+
# hashes and arrays. However, this store does not support Procs.
|
17
|
+
#
|
18
|
+
# As the ActiveRecord backend, Symbols are just supported when loading
|
19
|
+
# translations from the filesystem or through explicit store translations.
|
20
|
+
#
|
21
|
+
# Also, avoid calling I18n.available_locales since it's a somehow
|
22
|
+
# expensive operation in most stores.
|
23
|
+
#
|
24
|
+
# == Example
|
25
|
+
#
|
26
|
+
# To setup I18n to use TokyoCabinet in memory is quite straightforward:
|
27
|
+
#
|
28
|
+
# require 'rufus/tokyo/cabinet' # gem install rufus-tokyo
|
29
|
+
# I18n.backend = I18n::Backend::KeyValue.new(Rufus::Tokyo::Cabinet.new('*'))
|
30
|
+
#
|
31
|
+
# == Performance
|
32
|
+
#
|
33
|
+
# You may make this backend even faster by including the Memoize module.
|
34
|
+
# However, notice that you should properly clear the cache if you change
|
35
|
+
# values directly in the key-store.
|
36
|
+
#
|
37
|
+
# == Subtrees
|
38
|
+
#
|
39
|
+
# In most backends, you are allowed to retrieve part of a translation tree:
|
40
|
+
#
|
41
|
+
# I18n.backend.store_translations :en, :foo => { :bar => :baz }
|
42
|
+
# I18n.t "foo" #=> { :bar => :baz }
|
43
|
+
#
|
44
|
+
# This backend supports this feature by default, but it slows down the storage
|
45
|
+
# of new data considerably and makes hard to delete entries. That said, you are
|
46
|
+
# allowed to disable the storage of subtrees on initialization:
|
47
|
+
#
|
48
|
+
# I18n::Backend::KeyValue.new(@store, false)
|
49
|
+
#
|
50
|
+
# This is useful if you are using a KeyValue backend chained to a Simple backend.
|
51
|
+
module Implementation
|
52
|
+
attr_accessor :store
|
53
|
+
|
54
|
+
include I18n::Backend::Base, I18n::Backend::Flatten
|
55
|
+
|
56
|
+
def initialize(store, subtrees=true)
|
57
|
+
@store, @subtrees = store, subtrees
|
58
|
+
end
|
59
|
+
|
60
|
+
def store_translations(locale, data, options = {})
|
61
|
+
escape = options.fetch(:escape, true)
|
62
|
+
flatten_translations(locale, data, escape, @subtrees).each do |key, value|
|
63
|
+
key = "#{locale}.#{key}"
|
64
|
+
|
65
|
+
case value
|
66
|
+
when Hash
|
67
|
+
if @subtrees && (old_value = @store[key])
|
68
|
+
old_value = ActiveSupport::JSON.decode(old_value)
|
69
|
+
value = old_value.deep_symbolize_keys.deep_merge!(value) if old_value.is_a?(Hash)
|
70
|
+
end
|
71
|
+
when Proc
|
72
|
+
raise "Key-value stores cannot handle procs"
|
73
|
+
end
|
74
|
+
|
75
|
+
@store[key] = ActiveSupport::JSON.encode(value) unless value.is_a?(Symbol)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def available_locales
|
80
|
+
locales = @store.keys.map { |k| k =~ /\./; $` }
|
81
|
+
locales.uniq!
|
82
|
+
locales.compact!
|
83
|
+
locales.map! { |k| k.to_sym }
|
84
|
+
locales
|
85
|
+
end
|
86
|
+
|
87
|
+
protected
|
88
|
+
|
89
|
+
def lookup(locale, key, scope = [], options = {})
|
90
|
+
key = normalize_flat_keys(locale, key, scope, options[:separator])
|
91
|
+
value = @store["#{locale}.#{key}"]
|
92
|
+
#value = ActiveSupport::JSON.decode(value) if value
|
93
|
+
value.is_a?(Hash) ? value.deep_symbolize_keys : value
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
include Implementation
|
98
|
+
end
|
99
|
+
end
|
data/lib/couch_i18n/store.rb
CHANGED
@@ -45,6 +45,11 @@ module CouchI18n
|
|
45
45
|
translation.save
|
46
46
|
end
|
47
47
|
|
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
|
+
|
48
53
|
# alias for read
|
49
54
|
def self.[](key, options=nil)
|
50
55
|
find_by_key(key.to_s).try(:value) rescue nil
|
data/lib/couch_i18n.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require "i18n/backend/cache"
|
2
2
|
require "couch_i18n/engine"
|
3
3
|
require 'couch_i18n/store'
|
4
|
+
require 'couch_i18n/backend'
|
4
5
|
I18n::Backend::KeyValue.send(:include, I18n::Backend::Cache)
|
5
6
|
module CouchI18n
|
6
7
|
# This method imports yaml translations to the couchdb version. When run again new ones will
|
@@ -12,27 +13,49 @@ module CouchI18n
|
|
12
13
|
|
13
14
|
raise "Last backend not a I18n::Backend::Simple" unless yml_backend.is_a?(I18n::Backend::Simple)
|
14
15
|
yml_backend.load_translations
|
15
|
-
flattened_hash = traverse_flatten_keys(
|
16
|
+
flattened_hash = traverse_flatten_keys(yml_backend.send(:translations))
|
16
17
|
flattened_hash.each do |key, value|
|
17
18
|
CouchI18n::Store.create :key => key, :value => value
|
18
19
|
end
|
19
20
|
end
|
20
21
|
|
21
22
|
# Recursive flattening.
|
22
|
-
def self.traverse_flatten_keys(
|
23
|
+
def self.traverse_flatten_keys(obj, store = {}, path = nil)
|
23
24
|
case obj
|
24
25
|
when Hash
|
25
|
-
obj.each{|k, v| traverse_flatten_keys(
|
26
|
+
obj.each{|k, v| traverse_flatten_keys(v, store, [path, k].compact.join('.'))}
|
26
27
|
when Array
|
27
|
-
store
|
28
|
-
#obj
|
28
|
+
# Do not store array for now. There is no good solution yet
|
29
|
+
# store[path] = obj # Keeyp arrays intact
|
30
|
+
# store[path] = obj.to_json
|
31
|
+
# obj.each_with_index{|v, i| traverse_flatten_keys(store, v, [path, i].compact.join('.'))}
|
29
32
|
else
|
30
33
|
store[path] = obj
|
31
34
|
end
|
32
35
|
return store
|
33
36
|
end
|
37
|
+
|
38
|
+
# This will return an indented strucutre of a collection of stores. If no argument is given
|
39
|
+
# by default all the translations are indented. So a command:
|
40
|
+
# CouchI18n.indent_keys.to_yaml will return one big yaml string of the translations
|
41
|
+
def self.indent_keys(selection = Store.all)
|
42
|
+
traverse_indent_keys(selection.map{|kv| [kv.key.split('.'), kv.value]})
|
43
|
+
end
|
44
|
+
|
45
|
+
# Traversing helper for indent_keys
|
46
|
+
def self.traverse_indent_keys(ary, h = {})
|
47
|
+
for pair in ary
|
48
|
+
if pair.first.size == 1
|
49
|
+
h[pair.first.first] = pair.last
|
50
|
+
else
|
51
|
+
h[pair.first.first] ||= {}
|
52
|
+
traverse_indent_keys([[pair.first[1..-1], pair.last]], h[pair.first.first])
|
53
|
+
end
|
54
|
+
end
|
55
|
+
h
|
56
|
+
end
|
34
57
|
end
|
35
58
|
|
36
59
|
# Now extend the I18n backend
|
37
|
-
I18n.backend = I18n::Backend::Chain.new(
|
60
|
+
I18n.backend = I18n::Backend::Chain.new(CouchI18n::Backend.new(CouchI18n::Store), I18n.backend)
|
38
61
|
I18n.cache_store = ActiveSupport::Cache.lookup_store(:memory_store)
|
metadata
CHANGED
@@ -1,12 +1,8 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: couch_i18n
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
prerelease:
|
5
|
-
|
6
|
-
- 0
|
7
|
-
- 0
|
8
|
-
- 3
|
9
|
-
version: 0.0.3
|
4
|
+
prerelease:
|
5
|
+
version: 0.0.4
|
10
6
|
platform: ruby
|
11
7
|
authors:
|
12
8
|
- Benjamin ter Kuile
|
@@ -14,7 +10,7 @@ autorequire:
|
|
14
10
|
bindir: bin
|
15
11
|
cert_chain: []
|
16
12
|
|
17
|
-
date: 2011-05-
|
13
|
+
date: 2011-05-21 00:00:00 +02:00
|
18
14
|
default_executable:
|
19
15
|
dependencies: []
|
20
16
|
|
@@ -28,6 +24,7 @@ extra_rdoc_files: []
|
|
28
24
|
|
29
25
|
files:
|
30
26
|
- lib/couch_i18n/engine.rb
|
27
|
+
- lib/couch_i18n/backend.rb
|
31
28
|
- lib/couch_i18n/store.rb
|
32
29
|
- lib/couch_i18n.rb
|
33
30
|
- lib/tasks/couch_i18n_tasks.rake
|
@@ -54,23 +51,21 @@ rdoc_options: []
|
|
54
51
|
require_paths:
|
55
52
|
- lib
|
56
53
|
required_ruby_version: !ruby/object:Gem::Requirement
|
54
|
+
none: false
|
57
55
|
requirements:
|
58
56
|
- - ">="
|
59
57
|
- !ruby/object:Gem::Version
|
60
|
-
segments:
|
61
|
-
- 0
|
62
58
|
version: "0"
|
63
59
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
60
|
+
none: false
|
64
61
|
requirements:
|
65
62
|
- - ">="
|
66
63
|
- !ruby/object:Gem::Version
|
67
|
-
segments:
|
68
|
-
- 0
|
69
64
|
version: "0"
|
70
65
|
requirements: []
|
71
66
|
|
72
67
|
rubyforge_project: couch_i18n
|
73
|
-
rubygems_version: 1.
|
68
|
+
rubygems_version: 1.6.2
|
74
69
|
signing_key:
|
75
70
|
specification_version: 3
|
76
71
|
summary: couch_i18n is an in database storage for I18n translations, tested for rails, with online management views
|