translate-rails3-plus 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 [name of plugin creator]
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,86 @@
1
+ Translate
2
+ =========
3
+
4
+ This plugin provides a web interface for translating Rails I18n texts (requires Rails 3.0 or higher) from one locale to another. The plugin has been tested only with the simple I18n backend that ships with Rails. I18n texts are read from and written to YAML files under config/locales.
5
+
6
+ To translate to a new locale you need to add a YAML file for that locale that contains the locale as the top key and at least one translation.
7
+
8
+ Please note that there are certain I18n keys that map to Array objects rather than strings and those are currently not dealt with by the translation UI. This means that Rails built in keys such as date.day_names need to be translated manually directly in the YAML file.
9
+
10
+ To get the translation UI to write the YAML files in UTF8 you need to install the ya2yaml gem.
11
+
12
+ The translation UI finds all I18n keys by extracting them from I18n lookups in your application source code. In addition it adds all :en and default locale keys from the I18n backend.
13
+
14
+ Strings in the UI can have an "Auto Translate" link (if configured, see below),
15
+ which will send the original text to translation API and will input the returned
16
+ translation into the form field for further clean up and review prior to saving.
17
+
18
+
19
+ Rake Tasks
20
+ ----------
21
+
22
+ In addition to the web UI this plugin adds the following rake tasks:
23
+
24
+ translate:untranslated
25
+ translate:missing
26
+ translate:remove_obsolete_keys
27
+ translate:merge_keys
28
+ translate:google
29
+ translate:changed
30
+
31
+ The missing task shows you any I18n keys in your code that do not have translations in the YAML file for your default locale, i.e. config/locales/sv.yml.
32
+
33
+ The merge_keys task is supposed to be used in conjunction with Sven Fuch's Rails I18n TextMate bundle (http://github.com/svenfuchs/rails-i18n/tree/master). Texts and keys extracted with the TextMate bundle end up in the temporary file log/translations.yml. When you run the merge_keys rake task the keys are moved over to the corresponding I18n locale file, i.e. config/locales/sv.yml. The merge_keys task also checks for overwrites of existing keys by warning you that one of your extracted keys already exists with a different translation.
34
+
35
+ The google task is used for auto translating from one locale to another using Google Translate.
36
+ * Note: this task is currently broken, as Google is now charging for the Google Translate service.
37
+
38
+ The changed rake task can show you between one YAML file to another which keys have had their texts changed.
39
+
40
+ Installation
41
+ ------------
42
+
43
+ Add to your Gemfile:
44
+
45
+ gem 'translate-rails3', :require => 'translate', :group => :development
46
+
47
+ Now visit /translate in your web browser to start translating.
48
+
49
+ Configuration
50
+ -------------
51
+
52
+ (Optional) You can configure from_locales and to_locales explicitly through your environments/development.rb by adding
53
+
54
+ config.from_locales = [:en]
55
+ config.to_locales = [:ja, :es, :fr]
56
+
57
+ Where [:en] and [:ja, :es, :fr] could be replaced by locale list of your choice.
58
+
59
+ (Optional) You can bring back "Auto Translate" support by specifying Bing AppId or
60
+ Google API Key in config/initializers/translate.rb with:
61
+
62
+ Translate.app_id = 'myappid'
63
+
64
+ or
65
+
66
+ Translate.api_key = 'mysecretkey'
67
+
68
+
69
+ Dependencies
70
+ ------------
71
+
72
+ - Rails 3.0 or higher
73
+ - The ya2yaml gem if you want your YAML files written in UTF8 encoding.
74
+
75
+ Authors
76
+ -------
77
+
78
+ - Peter Marklund (programming)
79
+ - Joakim Westerlund (web design)
80
+ - Milan Novota (initial Rails 3 support)
81
+ - Roman Shterenzon (Rails 3 cleanup and gem packaging)
82
+ - Ichiro Yamamoto
83
+
84
+ Many thanks to http://newsdesk.se for sponsoring the development of this plugin.
85
+
86
+ Copyright (c) 2009 Peter Marklund, released under the MIT license
data/Rakefile ADDED
@@ -0,0 +1,35 @@
1
+ require 'rspec/core/rake_task'
2
+ require "bundler/gem_tasks"
3
+
4
+ desc 'Default: run specs.'
5
+ task :default => :spec
6
+
7
+ desc 'Run the specs'
8
+ RSpec::Core::RakeTask.new do |t|
9
+ t.rspec_opts = ['--color --format progress']
10
+ end
11
+
12
+ begin
13
+ require 'jeweler'
14
+ Jeweler::Tasks.new do |gem|
15
+ gem.name = 'translate-rails3-plus'
16
+ gem.summary = %Q{Newsdesk translate plugin for Rails 3}
17
+ gem.description = <<EOF
18
+ This plugin provides a web interface for translating Rails I18n texts
19
+ (requires Rails 3.0 or higher) from one locale to another.
20
+ The plugin has been tested only with the simple I18n backend that ships
21
+ with Rails.
22
+ I18n texts are read from and written to YAML files under config/locales.
23
+
24
+ This gem is a fork of https://github.com/romanbsd/translate.
25
+ From the original https://github.com/mynewsdesk/translate
26
+ which also includes work from this fork: https://github.com/milann/translate
27
+ EOF
28
+ gem.email = 'gsmedley@kanayo.com'
29
+ gem.homepage = 'https://github.com/gsmedley/translate'
30
+ gem.authors = ['Peter Marklund', 'Milan Novota', 'Roman Shterenzon', 'Garth Smedley']
31
+ gem.add_dependency 'ya2yaml', '~> 0.30' # For UTF-8 support in YAML
32
+ end
33
+ Jeweler::GemcutterTasks.new
34
+ rescue LoadError
35
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.1
@@ -0,0 +1,222 @@
1
+ class TranslateController < ActionController::Base
2
+ # It seems users with active_record_store may get a "no :secret given" error if we don't disable csrf protection,
3
+ skip_before_filter :verify_authenticity_token
4
+
5
+ layout 'translate'
6
+
7
+ before_filter :init_translations
8
+ before_filter :set_locale
9
+
10
+ # GET /translate
11
+ def index
12
+ initialize_keys
13
+ filter_by_key_pattern
14
+ filter_by_text_pattern
15
+ filter_by_translated_text_pattern
16
+ filter_by_translated_or_changed
17
+ sort_keys
18
+ paginate_keys
19
+ @total_entries = @keys.size
20
+ @page_title = page_title
21
+ end
22
+
23
+ # POST /translate
24
+ def translate
25
+ processed_parameters = process_array_parameters(params[:key])
26
+ I18n.backend.store_translations(@to_locale, Translate::Keys.to_deep_hash(processed_parameters))
27
+ Translate::Storage.new(@to_locale).write_to_file
28
+ Translate::Log.new(@from_locale, @to_locale, params[:key].keys).write_to_file
29
+ force_init_translations # Force reload from YAML file
30
+ flash[:notice] = "Translations stored"
31
+ redirect_to params.slice(:filter, :sort_by, :key_type, :key_pattern, :text_type, :text_pattern, :translated_text_type, :translated_text_pattern).merge({:action => :index})
32
+ end
33
+
34
+ # GET /translate/reload
35
+ def reload
36
+ Translate::Keys.files = nil
37
+ redirect_to :action => 'index'
38
+ end
39
+
40
+ private
41
+ def initialize_keys
42
+ @files = Translate::Keys.files
43
+ @keys = (@files.keys.map(&:to_s) + Translate::Keys.new.i18n_keys(@from_locale)).uniq
44
+ @keys.reject! do |key|
45
+ from_text = lookup(@from_locale, key)
46
+ # When translating from one language to another, make sure there is a text to translate from.
47
+ # The only supported formats are String and Array. We don't support other formats
48
+ (@from_locale != @to_locale && !from_text.present?) || (from_text.present? && !from_text.is_a?(String) && !from_text.is_a?(Array))
49
+ end
50
+ end
51
+
52
+ def page_title
53
+ "Translate"
54
+ end
55
+
56
+ def lookup(locale, key)
57
+ I18n.backend.send(:lookup, locale, key)
58
+ end
59
+ helper_method :lookup
60
+
61
+ def from_locales
62
+ # Attempt to get the list of locale from configuration
63
+ from_loc = Rails.application.config.from_locales if Rails.application.config.respond_to?(:from_locales)
64
+ return I18n.available_locales if from_loc.blank?
65
+ raise StandardError, "from_locale expected to be an array" if from_loc.class != Array
66
+ from_loc
67
+ end
68
+ helper_method :from_locales
69
+
70
+ def to_locales
71
+ to_loc = Rails.application.config.to_locales if Rails.application.config.respond_to?(:to_locales)
72
+ return I18n.available_locales if to_loc.blank?
73
+ raise StandardError, "to_locales expected to be an array" if to_loc.class != Array
74
+ to_loc
75
+ end
76
+ helper_method :to_locales
77
+
78
+ def filter_by_translated_or_changed
79
+ params[:filter] ||= 'all'
80
+ return if params[:filter] == 'all'
81
+ @keys.reject! do |key|
82
+ case params[:filter]
83
+ when 'untranslated'
84
+ lookup(@to_locale, key).present?
85
+ when 'translated'
86
+ lookup(@to_locale, key).blank?
87
+ when 'changed'
88
+ old_from_text(key).blank? || lookup(@from_locale, key) == old_from_text(key)
89
+ else
90
+ raise "Unknown filter '#{params[:filter]}'"
91
+ end
92
+ end
93
+ end
94
+
95
+ def filter_by_key_pattern
96
+ return if params[:key_pattern].blank?
97
+ @keys.reject! do |key|
98
+ case params[:key_type]
99
+ when "starts_with"
100
+ !key.starts_with?(params[:key_pattern])
101
+ when "contains"
102
+ key.index(params[:key_pattern]).nil?
103
+ else
104
+ raise "Unknown key_type '#{params[:key_type]}'"
105
+ end
106
+ end
107
+ end
108
+
109
+ def filter_by_text_pattern
110
+ return if params[:text_pattern].blank?
111
+ @keys.reject! do |key|
112
+ case params[:text_type]
113
+ when 'contains'
114
+ !lookup(@from_locale, key).present? || !lookup(@from_locale, key).to_s.downcase.index(params[:text_pattern].downcase)
115
+ when 'equals'
116
+ !lookup(@from_locale, key).present? || lookup(@from_locale, key).to_s.downcase != params[:text_pattern].downcase
117
+ else
118
+ raise "Unknown text_type '#{params[:text_type]}'"
119
+ end
120
+ end
121
+ end
122
+
123
+ def filter_by_translated_text_pattern
124
+ return if params[:translated_text_pattern].blank?
125
+ @keys.reject! do |key|
126
+ case params[:translated_text_type]
127
+ when 'contains' then
128
+ !lookup(@to_locale, key).present? || !lookup(@to_locale, key).to_s.downcase.index(params[:translated_text_pattern].downcase)
129
+ when 'equals' then
130
+ !lookup(@to_locale, key).present? || lookup(@to_locale, key).to_s.downcase != params[:translated_text_pattern].downcase
131
+ else
132
+ raise "Unknown translated_text_type '#{params[:translated_text_type]}'"
133
+ end
134
+ end
135
+ end
136
+
137
+ def sort_keys
138
+ params[:sort_by] ||= "key"
139
+ case params[:sort_by]
140
+ when "key"
141
+ @keys.sort!
142
+ when "text"
143
+ @keys.sort! do |key1, key2|
144
+ if lookup(@from_locale, key1).present? && lookup(@from_locale, key2).present?
145
+ lookup(@from_locale, key1).to_s.downcase <=> lookup(@from_locale, key2).to_s.downcase
146
+ elsif lookup(@from_locale, key1).present?
147
+ -1
148
+ else
149
+ 1
150
+ end
151
+ end
152
+ else
153
+ raise "Unknown sort_by '#{params[:sort_by]}'"
154
+ end
155
+ end
156
+
157
+ def paginate_keys
158
+ params[:page] ||= 1
159
+ @paginated_keys = @keys[offset, per_page]
160
+ end
161
+
162
+ def offset
163
+ (params[:page].to_i - 1) * per_page
164
+ end
165
+
166
+ def per_page
167
+ 50
168
+ end
169
+ helper_method :per_page
170
+
171
+ def init_translations
172
+ I18n.backend.send(:init_translations) unless I18n.backend.initialized?
173
+ end
174
+
175
+ def force_init_translations
176
+ I18n.backend.send(:init_translations)
177
+ end
178
+
179
+ def default_locale
180
+ I18n.default_locale
181
+ end
182
+
183
+ def default_to_locale
184
+ :en
185
+ end
186
+
187
+ def set_locale
188
+ session[:from_locale] ||= default_locale
189
+ session[:to_locale] ||= default_to_locale
190
+ session[:from_locale] = params[:from_locale] if params[:from_locale].present?
191
+ session[:to_locale] = params[:to_locale] if params[:to_locale].present?
192
+ @from_locale = session[:from_locale].to_sym
193
+ @to_locale = session[:to_locale].to_sym
194
+ end
195
+
196
+ def old_from_text(key)
197
+ return @old_from_text[key] if @old_from_text && @old_from_text[key]
198
+ @old_from_text = {}
199
+ text = key.split(".").inject(log_hash) do |hash, k|
200
+ hash ? hash[k] : nil
201
+ end
202
+ @old_from_text[key] = text
203
+ end
204
+ helper_method :old_from_text
205
+
206
+ def log_hash
207
+ @log_hash ||= Translate::Log.new(@from_locale, @to_locale, {}).read
208
+ end
209
+
210
+ def process_array_parameters(parameter)
211
+ reconstructed_hash = Hash.new
212
+
213
+ parameter.each do |key, value|
214
+ if value.is_a?(String)
215
+ reconstructed_hash[key] = value
216
+ elsif value.is_a?(Hash)
217
+ reconstructed_hash[key] = Translate::Keys.arraylize(value)
218
+ end
219
+ end
220
+ reconstructed_hash
221
+ end
222
+ end
@@ -0,0 +1,57 @@
1
+ module TranslateHelper
2
+
3
+ def simple_filter(labels, param_name = 'filter', selected_value = nil)
4
+ selected_value ||= params[param_name]
5
+ filter = []
6
+ labels.each do |item|
7
+ if item.is_a?(Array)
8
+ type, label = item
9
+ else
10
+ type = label = item
11
+ end
12
+ if type.to_s == selected_value.to_s
13
+ filter << "<i>#{label}</i>"
14
+ else
15
+ link_params = params.merge({param_name.to_s => type})
16
+ link_params.merge!({"page" => nil}) if param_name.to_s != "page"
17
+ filter << link_to(label, link_params)
18
+ end
19
+ end
20
+ filter.join(" | ")
21
+ end
22
+
23
+ def n_lines(text, line_size)
24
+ n_lines = 1
25
+ if text.present?
26
+ n_lines = text.split("\n").size
27
+ if n_lines == 1 && text.length > line_size
28
+ n_lines = text.length / line_size + 1
29
+ end
30
+ end
31
+ n_lines
32
+ end
33
+
34
+ def translate_javascript_includes
35
+ sources = []
36
+ if File.exists?(File.join(Rails.root, "public", "javascripts", "prototype.js"))
37
+ sources << "/javascripts/prototype.js"
38
+ else
39
+ sources << "http://ajax.googleapis.com/ajax/libs/prototype/1.7.0.0/prototype.js"
40
+ end
41
+ sources.map do |src|
42
+ %Q{<script src="#{src}" type="text/javascript"></script>}
43
+ end.join("\n").html_safe
44
+ end
45
+
46
+ def translate_link(key, text, from, to)
47
+ method = if Translate.app_id
48
+ 'getBingTranslation'
49
+ elsif Translate.api_key
50
+ 'getGoogleTranslation'
51
+ else
52
+ nil
53
+ end
54
+ return nil unless method
55
+ link_to_function 'Auto Translate', "#{method}('#{key}', \"#{escape_javascript(text)}\", '#{from}', '#{to}')", :style => 'padding: 0; margin: 0;'
56
+ end
57
+ end