translate-rails3 0.1.1 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +11 -0
- data/VERSION +1 -1
- data/app/controllers/translate_controller.rb +17 -3
- data/app/helpers/translate_helper.rb +31 -0
- data/app/views/translate/_array_form.html.erb +42 -0
- data/app/views/translate/_pagination.html.erb +1 -1
- data/app/views/translate/_string_form.html.erb +32 -0
- data/app/views/translate/index.html.erb +8 -33
- data/lib/translate/keys.rb +48 -15
- data/translate-rails3.gemspec +10 -17
- metadata +6 -17
data/README.md
CHANGED
@@ -43,6 +43,16 @@ Add to your Gemfile:
|
|
43
43
|
|
44
44
|
Now visit /translate in your web browser to start translating.
|
45
45
|
|
46
|
+
Configuration
|
47
|
+
-------------
|
48
|
+
|
49
|
+
(Optional) You can configure from_locales and to_locales explicitly through your environments/development.rb by adding
|
50
|
+
|
51
|
+
config.from_locales = [:en]
|
52
|
+
config.to_locales = [:ja, :es, :fr]
|
53
|
+
|
54
|
+
Where [:en] and [:ja, :es, :fr] could be replaced by locale list of your choice.
|
55
|
+
|
46
56
|
Dependencies
|
47
57
|
------------
|
48
58
|
|
@@ -56,6 +66,7 @@ Authors
|
|
56
66
|
- Joakim Westerlund (web design)
|
57
67
|
- Milan Novota (initial Rails 3 support)
|
58
68
|
- Roman Shterenzon (Rails 3 cleanup and gem packaging)
|
69
|
+
- Ichiro Yamamoto
|
59
70
|
|
60
71
|
Many thanks to http://newsdesk.se for sponsoring the development of this plugin.
|
61
72
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1.
|
1
|
+
0.1.2
|
@@ -19,7 +19,8 @@ class TranslateController < ActionController::Base
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def translate
|
22
|
-
|
22
|
+
processed_parameters = process_array_parameters(params[:key])
|
23
|
+
I18n.backend.store_translations(@to_locale, Translate::Keys.to_deep_hash(processed_parameters))
|
23
24
|
Translate::Storage.new(@to_locale).write_to_file
|
24
25
|
Translate::Log.new(@from_locale, @to_locale, params[:key].keys).write_to_file
|
25
26
|
force_init_translations # Force reload from YAML file
|
@@ -39,8 +40,8 @@ class TranslateController < ActionController::Base
|
|
39
40
|
@keys.reject! do |key|
|
40
41
|
from_text = lookup(@from_locale, key)
|
41
42
|
# When translating from one language to another, make sure there is a text to translate from.
|
42
|
-
#
|
43
|
-
(@from_locale != @to_locale && !from_text.present?) || (from_text.present? && !from_text.is_a?(String))
|
43
|
+
# The only supported formats are String and Array. We don't support other formats
|
44
|
+
(@from_locale != @to_locale && !from_text.present?) || (from_text.present? && !from_text.is_a?(String) && !from_text.is_a?(Array))
|
44
45
|
end
|
45
46
|
end
|
46
47
|
|
@@ -162,4 +163,17 @@ class TranslateController < ActionController::Base
|
|
162
163
|
def log_hash
|
163
164
|
@log_hash ||= Translate::Log.new(@from_locale, @to_locale, {}).read
|
164
165
|
end
|
166
|
+
|
167
|
+
def process_array_parameters(parameter)
|
168
|
+
reconstructed_hash = Hash.new
|
169
|
+
|
170
|
+
parameter.each do |key, value|
|
171
|
+
if value.is_a?(String)
|
172
|
+
reconstructed_hash[key] = value
|
173
|
+
elsif value.is_a?(Hash)
|
174
|
+
reconstructed_hash[key] = Translate::Keys.arraylize(value)
|
175
|
+
end
|
176
|
+
end
|
177
|
+
reconstructed_hash
|
178
|
+
end
|
165
179
|
end
|
@@ -1,4 +1,35 @@
|
|
1
1
|
module TranslateHelper
|
2
|
+
|
3
|
+
def render_translate_form(from_locale, to_locale, key)
|
4
|
+
from_text = lookup(from_locale, key)
|
5
|
+
if from_text.is_a?(String)
|
6
|
+
render :partial => 'string_form', :locals =>
|
7
|
+
{:from_locale => from_locale,
|
8
|
+
:to_locale => to_locale,
|
9
|
+
:key => key}
|
10
|
+
elsif from_text.is_a?(Array)
|
11
|
+
render :partial => 'array_form', :locals =>
|
12
|
+
{:from_locale => from_locale,
|
13
|
+
:to_locale => to_locale,
|
14
|
+
:key => key}
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def from_locales
|
19
|
+
# Attempt to get the list of locale from configuration
|
20
|
+
from_loc = Rails.application.config.from_locales if Rails.application.config.respond_to?(:from_locales)
|
21
|
+
return I18n.available_locales if from_loc.blank?
|
22
|
+
raise StandardError, "from_locale expected to be an array" if from_loc.class != Array
|
23
|
+
from_loc
|
24
|
+
end
|
25
|
+
|
26
|
+
def to_locales
|
27
|
+
to_loc = Rails.application.config.to_locales if Rails.application.config.respond_to?(:to_locales)
|
28
|
+
return I18n.available_locales if to_loc.blank?
|
29
|
+
raise StandardError, "to_locales expected to be an array" if to_loc.class != Array
|
30
|
+
to_loc
|
31
|
+
end
|
32
|
+
|
2
33
|
def simple_filter(labels, param_name = 'filter', selected_value = nil)
|
3
34
|
selected_value ||= params[param_name]
|
4
35
|
filter = []
|
@@ -0,0 +1,42 @@
|
|
1
|
+
<%
|
2
|
+
from_text = lookup(from_locale, key)
|
3
|
+
to_text = lookup(to_locale, key)
|
4
|
+
field_name = "key[#{key}]"
|
5
|
+
%>
|
6
|
+
|
7
|
+
<div class="translation">
|
8
|
+
<% if from_text.present? %>
|
9
|
+
<p class="translation-text">
|
10
|
+
<ol>
|
11
|
+
<% from_text.each_with_index do |from_text_section, index| %>
|
12
|
+
<%
|
13
|
+
from_text_section = from_text_section.to_s
|
14
|
+
line_size = 100
|
15
|
+
n_lines = n_lines(from_text_section, line_size)
|
16
|
+
# this is needed so the controller doesn't freak out when there is no translations found
|
17
|
+
# for this element yet...
|
18
|
+
to_text = Array.new if to_text.blank?
|
19
|
+
%>
|
20
|
+
<li><%= from_text_section %></li>
|
21
|
+
<p class="edit-form">
|
22
|
+
<% if n_lines > 1 %>
|
23
|
+
<%= text_area_tag("#{field_name}[#{index}]", to_text[index], :size => "#{line_size}x#{n_lines}", :id => "#{key}[#{index}]") %>
|
24
|
+
<% else %>
|
25
|
+
<%= text_field_tag("#{field_name}[#{index}]", to_text[index], :size => line_size, :id => "#{key}[#{index}]") %>
|
26
|
+
<% end %>
|
27
|
+
<%= link_to_function 'Auto Translate', "getGoogleTranslation('#{key}[#{index}]', \"#{escape_javascript(from_text_section)}\", '#{@from_locale}', '#{@to_locale}')", :style => 'padding: 0; margin: 0;' %>
|
28
|
+
</p>
|
29
|
+
<% end %>
|
30
|
+
</ol>
|
31
|
+
</p>
|
32
|
+
<% end %>
|
33
|
+
<p>
|
34
|
+
<em>
|
35
|
+
<br/>
|
36
|
+
<strong>Key:</strong><%=h key %><br/>
|
37
|
+
<% if @files[key] %>
|
38
|
+
<strong>File:</strong><%= @files[key].join("<br/>") %>
|
39
|
+
<% end %>
|
40
|
+
</em>
|
41
|
+
</p>
|
42
|
+
</div>
|
@@ -0,0 +1,32 @@
|
|
1
|
+
<%
|
2
|
+
from_text = lookup(from_locale, key)
|
3
|
+
to_text = lookup(to_locale, key)
|
4
|
+
line_size = 100
|
5
|
+
n_lines = n_lines(from_text, line_size)
|
6
|
+
field_name = "key[#{key}]"
|
7
|
+
%>
|
8
|
+
|
9
|
+
<div class="translation">
|
10
|
+
<% if from_text.present? %>
|
11
|
+
<p class="translation-text">
|
12
|
+
<%= simple_format(h(from_text)) %>
|
13
|
+
</p>
|
14
|
+
<% end %>
|
15
|
+
<p class="edit-form">
|
16
|
+
<% if n_lines > 1 %>
|
17
|
+
<%= text_area_tag(field_name, to_text, :size => "#{line_size}x#{n_lines}", :id => key) %>
|
18
|
+
<% else %>
|
19
|
+
<%= text_field_tag(field_name, to_text, :size => line_size, :id => key) %>
|
20
|
+
<% end %>
|
21
|
+
</p>
|
22
|
+
<p>
|
23
|
+
<em>
|
24
|
+
<%= link_to_function 'Auto Translate', "getGoogleTranslation('#{key}', \"#{escape_javascript(from_text)}\", '#{@from_locale}', '#{@to_locale}')", :style => 'padding: 0; margin: 0;' %>
|
25
|
+
<br/>
|
26
|
+
<strong>Key:</strong><%=h key %><br/>
|
27
|
+
<% if @files[key] %>
|
28
|
+
<strong>File:</strong><%= @files[key].join("<br/>") %>
|
29
|
+
<% end %>
|
30
|
+
</em>
|
31
|
+
</p>
|
32
|
+
</div>
|
@@ -20,8 +20,8 @@
|
|
20
20
|
<%= hidden_field_tag(:filter, params[:filter]) %>
|
21
21
|
<%= hidden_field_tag(:sort_by, params[:sort_by]) %>
|
22
22
|
<label>Translate from</label>
|
23
|
-
<%= select_tag(:from_locale, options_for_select(
|
24
|
-
<%= select_tag(:to_locale, options_for_select(
|
23
|
+
<%= select_tag(:from_locale, options_for_select(from_locales, @from_locale.to_sym)) %> <span>to</span>
|
24
|
+
<%= select_tag(:to_locale, options_for_select(to_locales, @to_locale.to_sym)) %>
|
25
25
|
<%= submit_tag "Display" %>
|
26
26
|
</p>
|
27
27
|
</div>
|
@@ -70,38 +70,13 @@
|
|
70
70
|
<p class="translate">
|
71
71
|
<%= submit_tag "Save Translations" %>
|
72
72
|
</p>
|
73
|
-
<% @paginated_keys.each do |key|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
%>
|
80
|
-
<div class="translation">
|
81
|
-
<% if from_text.present? %>
|
82
|
-
<p class="translation-text">
|
83
|
-
<%= simple_format(h(from_text)) %>
|
84
|
-
</p>
|
73
|
+
<% @paginated_keys.each do |key| %>
|
74
|
+
<%=
|
75
|
+
# this is a helper method, we need to determine if the thing we are trying to translate is
|
76
|
+
# a string or an array, and it would be very messey if i put everything in this view
|
77
|
+
render_translate_form(@from_locale, @to_locale, key)
|
78
|
+
%>
|
85
79
|
<% end %>
|
86
|
-
<p class="edit-form">
|
87
|
-
<% if n_lines > 1 %>
|
88
|
-
<%= text_area_tag(field_name, to_text, :size => "#{line_size}x#{n_lines}", :id => key) %>
|
89
|
-
<% else %>
|
90
|
-
<%= text_field_tag(field_name, to_text, :size => line_size, :id => key) %>
|
91
|
-
<% end %>
|
92
|
-
</p>
|
93
|
-
<p>
|
94
|
-
<em>
|
95
|
-
<%= link_to_function 'Auto Translate', "getGoogleTranslation('#{key}', \"#{escape_javascript(from_text)}\", '#{@from_locale}', '#{@to_locale}')", :style => 'padding: 0; margin: 0;' %>
|
96
|
-
<br/>
|
97
|
-
<strong>Key:</strong><%=h key %><br/>
|
98
|
-
<% if @files[key] %>
|
99
|
-
<strong>File:</strong><%= @files[key].join("<br/>") %>
|
100
|
-
<% end %>
|
101
|
-
</em>
|
102
|
-
</p>
|
103
|
-
</div>
|
104
|
-
<% end %>
|
105
80
|
<p class="translate">
|
106
81
|
<%= submit_tag "Save Translations" %>
|
107
82
|
</p>
|
data/lib/translate/keys.rb
CHANGED
@@ -5,17 +5,17 @@ class Translate::Keys
|
|
5
5
|
def self.files
|
6
6
|
@@files ||= Translate::Keys.new.files
|
7
7
|
end
|
8
|
-
|
8
|
+
|
9
9
|
# Allows flushing of the files cache
|
10
10
|
def self.files=(files)
|
11
11
|
@@files = files
|
12
12
|
end
|
13
|
-
|
13
|
+
|
14
14
|
def files
|
15
15
|
@files ||= extract_files
|
16
|
-
end
|
16
|
+
end
|
17
17
|
alias_method :to_hash, :files
|
18
|
-
|
18
|
+
|
19
19
|
def keys
|
20
20
|
files.keys
|
21
21
|
end
|
@@ -44,7 +44,7 @@ class Translate::Keys
|
|
44
44
|
end
|
45
45
|
|
46
46
|
def self.translated_locales
|
47
|
-
I18n.available_locales.reject { |locale| [:root, I18n.default_locale.to_sym].include?(locale) }
|
47
|
+
I18n.available_locales.reject { |locale| [:root, I18n.default_locale.to_sym].include?(locale) }
|
48
48
|
end
|
49
49
|
|
50
50
|
# Checks if a nested hash contains the keys in dot separated I18n key.
|
@@ -71,9 +71,9 @@ class Translate::Keys
|
|
71
71
|
memo.is_a?(Hash) ? memo.try(:[], key) : nil
|
72
72
|
end.nil?
|
73
73
|
end
|
74
|
-
|
74
|
+
|
75
75
|
# Convert something like:
|
76
|
-
#
|
76
|
+
#
|
77
77
|
# {
|
78
78
|
# :pressrelease => {
|
79
79
|
# :label => {
|
@@ -81,9 +81,9 @@ class Translate::Keys
|
|
81
81
|
# }
|
82
82
|
# }
|
83
83
|
# }
|
84
|
-
#
|
84
|
+
#
|
85
85
|
# to:
|
86
|
-
#
|
86
|
+
#
|
87
87
|
# {'pressrelease.label.one' => "Pressmeddelande"}
|
88
88
|
#
|
89
89
|
def self.to_shallow_hash(hash)
|
@@ -98,13 +98,13 @@ class Translate::Keys
|
|
98
98
|
shallow_hash
|
99
99
|
end
|
100
100
|
end
|
101
|
-
|
101
|
+
|
102
102
|
# Convert something like:
|
103
|
-
#
|
103
|
+
#
|
104
104
|
# {'pressrelease.label.one' => "Pressmeddelande"}
|
105
|
-
#
|
105
|
+
#
|
106
106
|
# to:
|
107
|
-
#
|
107
|
+
#
|
108
108
|
# {
|
109
109
|
# :pressrelease => {
|
110
110
|
# :label => {
|
@@ -112,7 +112,7 @@ class Translate::Keys
|
|
112
112
|
# }
|
113
113
|
# }
|
114
114
|
# }
|
115
|
-
def self.to_deep_hash(hash)
|
115
|
+
def self.to_deep_hash(hash)
|
116
116
|
hash.inject({}) do |deep_hash, (key, value)|
|
117
117
|
keys = key.to_s.split('.').reverse
|
118
118
|
leaf_key = keys.shift
|
@@ -128,11 +128,44 @@ class Translate::Keys
|
|
128
128
|
hash1.merge!(hash2, &merger)
|
129
129
|
end
|
130
130
|
|
131
|
+
# Convert something like:
|
132
|
+
#
|
133
|
+
# {'0' => "elem 1", '1' => "elem 2"}
|
134
|
+
#
|
135
|
+
# to:
|
136
|
+
#
|
137
|
+
# ["elem 1", "elem 2"]
|
138
|
+
#
|
139
|
+
def self.arraylize(input_hash)
|
140
|
+
input_hash.inject([]) do |constructed_array, (key, value)|
|
141
|
+
constructed_array << value
|
142
|
+
constructed_array
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
131
146
|
private
|
132
147
|
|
133
148
|
def extract_files
|
134
149
|
files_to_scan.inject(HashWithIndifferentAccess.new) do |files, file|
|
135
|
-
IO.read(file)
|
150
|
+
keys = IO.read(file)
|
151
|
+
if keys.respond_to? "encode"
|
152
|
+
keys = keys.encode("UTF-8").force_encoding("UTF-8")
|
153
|
+
end
|
154
|
+
error_count = 0
|
155
|
+
begin
|
156
|
+
encoded_keys = keys.scan(i18n_lookup_pattern)
|
157
|
+
rescue => e
|
158
|
+
unless error_count > 1
|
159
|
+
if keys.respond_to? 'encode!'
|
160
|
+
keys.encode!('utf-8', 'utf-8', :invalid => :replace)
|
161
|
+
end
|
162
|
+
error_count += 1
|
163
|
+
retry
|
164
|
+
else
|
165
|
+
puts "cannot fix: #{e} on : #{file}"
|
166
|
+
end
|
167
|
+
end
|
168
|
+
encoded_keys.flatten.map(&:to_sym).each do |key|
|
136
169
|
files[key] ||= []
|
137
170
|
path = Pathname.new(File.expand_path(file)).relative_path_from(Pathname.new(Rails.root)).to_s
|
138
171
|
files[key] << path if !files[key].include?(path)
|
data/translate-rails3.gemspec
CHANGED
@@ -4,22 +4,14 @@
|
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
|
-
s.name =
|
8
|
-
s.version = "0.1.
|
7
|
+
s.name = "translate-rails3"
|
8
|
+
s.version = "0.1.2"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Peter Marklund", "Milan Novota", "Roman Shterenzon"]
|
12
|
-
s.date =
|
13
|
-
s.description =
|
14
|
-
|
15
|
-
The plugin has been tested only with the simple I18n backend that ships
|
16
|
-
with Rails.
|
17
|
-
I18n texts are read from and written to YAML files under config/locales.
|
18
|
-
|
19
|
-
This gem is a fork of the original https://github.com/mynewsdesk/translate
|
20
|
-
and also includes work from this fork: https://github.com/milann/translate
|
21
|
-
}
|
22
|
-
s.email = %q{romanbsd@yahoo.com}
|
12
|
+
s.date = "2011-11-23"
|
13
|
+
s.description = "This plugin provides a web interface for translating Rails I18n texts\n(requires Rails 3.0 or higher) from one locale to another.\nThe plugin has been tested only with the simple I18n backend that ships\nwith Rails.\nI18n texts are read from and written to YAML files under config/locales.\n\nThis gem is a fork of the original https://github.com/mynewsdesk/translate\nand also includes work from this fork: https://github.com/milann/translate\n"
|
14
|
+
s.email = "romanbsd@yahoo.com"
|
23
15
|
s.extra_rdoc_files = [
|
24
16
|
"README.md"
|
25
17
|
]
|
@@ -31,7 +23,9 @@ and also includes work from this fork: https://github.com/milann/translate
|
|
31
23
|
"app/controllers/translate_controller.rb",
|
32
24
|
"app/helpers/translate_helper.rb",
|
33
25
|
"app/views/layouts/translate.html.erb",
|
26
|
+
"app/views/translate/_array_form.html.erb",
|
34
27
|
"app/views/translate/_pagination.html.erb",
|
28
|
+
"app/views/translate/_string_form.html.erb",
|
35
29
|
"app/views/translate/index.html.erb",
|
36
30
|
"config/routes.rb",
|
37
31
|
"init.rb",
|
@@ -56,13 +50,12 @@ and also includes work from this fork: https://github.com/milann/translate
|
|
56
50
|
"spec/storage_spec.rb",
|
57
51
|
"translate-rails3.gemspec"
|
58
52
|
]
|
59
|
-
s.homepage =
|
53
|
+
s.homepage = "https://github.com/romanbsd/translate"
|
60
54
|
s.require_paths = ["lib"]
|
61
|
-
s.rubygems_version =
|
62
|
-
s.summary =
|
55
|
+
s.rubygems_version = "1.8.11"
|
56
|
+
s.summary = "Newsdesk translate plugin for Rails 3"
|
63
57
|
|
64
58
|
if s.respond_to? :specification_version then
|
65
|
-
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
66
59
|
s.specification_version = 3
|
67
60
|
|
68
61
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
metadata
CHANGED
@@ -1,12 +1,8 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: translate-rails3
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
prerelease:
|
5
|
-
|
6
|
-
- 0
|
7
|
-
- 1
|
8
|
-
- 1
|
9
|
-
version: 0.1.1
|
4
|
+
prerelease:
|
5
|
+
version: 0.1.2
|
10
6
|
platform: ruby
|
11
7
|
authors:
|
12
8
|
- Peter Marklund
|
@@ -16,8 +12,7 @@ autorequire:
|
|
16
12
|
bindir: bin
|
17
13
|
cert_chain: []
|
18
14
|
|
19
|
-
date: 2011-
|
20
|
-
default_executable:
|
15
|
+
date: 2011-11-23 00:00:00 Z
|
21
16
|
dependencies:
|
22
17
|
- !ruby/object:Gem::Dependency
|
23
18
|
name: ya2yaml
|
@@ -27,9 +22,6 @@ dependencies:
|
|
27
22
|
requirements:
|
28
23
|
- - ~>
|
29
24
|
- !ruby/object:Gem::Version
|
30
|
-
segments:
|
31
|
-
- 0
|
32
|
-
- 30
|
33
25
|
version: "0.30"
|
34
26
|
type: :runtime
|
35
27
|
version_requirements: *id001
|
@@ -58,7 +50,9 @@ files:
|
|
58
50
|
- app/controllers/translate_controller.rb
|
59
51
|
- app/helpers/translate_helper.rb
|
60
52
|
- app/views/layouts/translate.html.erb
|
53
|
+
- app/views/translate/_array_form.html.erb
|
61
54
|
- app/views/translate/_pagination.html.erb
|
55
|
+
- app/views/translate/_string_form.html.erb
|
62
56
|
- app/views/translate/index.html.erb
|
63
57
|
- config/routes.rb
|
64
58
|
- init.rb
|
@@ -82,7 +76,6 @@ files:
|
|
82
76
|
- spec/spec_helper.rb
|
83
77
|
- spec/storage_spec.rb
|
84
78
|
- translate-rails3.gemspec
|
85
|
-
has_rdoc: true
|
86
79
|
homepage: https://github.com/romanbsd/translate
|
87
80
|
licenses: []
|
88
81
|
|
@@ -96,21 +89,17 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
96
89
|
requirements:
|
97
90
|
- - ">="
|
98
91
|
- !ruby/object:Gem::Version
|
99
|
-
segments:
|
100
|
-
- 0
|
101
92
|
version: "0"
|
102
93
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
103
94
|
none: false
|
104
95
|
requirements:
|
105
96
|
- - ">="
|
106
97
|
- !ruby/object:Gem::Version
|
107
|
-
segments:
|
108
|
-
- 0
|
109
98
|
version: "0"
|
110
99
|
requirements: []
|
111
100
|
|
112
101
|
rubyforge_project:
|
113
|
-
rubygems_version: 1.
|
102
|
+
rubygems_version: 1.8.11
|
114
103
|
signing_key:
|
115
104
|
specification_version: 3
|
116
105
|
summary: Newsdesk translate plugin for Rails 3
|