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