translate_routes 3.0.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.
@@ -0,0 +1,100 @@
1
+ TranslateRoutes
2
+ ===============
3
+
4
+ This branch works with Rails 3.x, you can find branches for Rails [2.1.x](http://github.com/raul/translate_routes/tree/rails2.1), [2.2.x](http://github.com/raul/translate_routes/tree/rails2.2) and [2.3.x](http://github.com/raul/translate_routes/tree/rails2.3)
5
+
6
+ This Rails plugin provides a simple way to translate your URLs to any number of languages, even on a fully working application.
7
+
8
+ It works fine with all kind of routing definitions, including RESTful and named routes.
9
+ **Your current code will remain untouched**: your current routing code, helpers and links will be translated transparently - even in your tests.
10
+ (Un)installing it is a very clean and simple process, so why don't you give it a chance? ;)
11
+
12
+ Quick start
13
+ -----------
14
+
15
+ Let's start with a tiny example. Of course you need to define your routes first, e.g:
16
+
17
+ YourApp::Application.routes.draw do
18
+ match 'contact', :to => 'contact#index', :as => 'contact'
19
+ end
20
+
21
+ 1) Download the plugin to your app's `/vendor/plugins` directory.
22
+
23
+ 2) Write your translations on a standard YAML file (e.g: i18n-routes.yml), including the locales and it translations pairs:
24
+
25
+ es:
26
+ contact: contacto
27
+
28
+
29
+ 3) Append a line to your routes.rb file to activate the translations. If you loaded the translations file with
30
+ your other I18n translations files, the line will be:
31
+
32
+ ActionDispatch::Routing::Translator.i18n('es')
33
+
34
+ and if you want to keep the file separated (e.g: config/i18n-routes.yml), the line to append is:
35
+
36
+ ActionDispatch::Routing::Translator.translate_from_file('config','i18n-routes.yml')
37
+
38
+ You can see it working by executing `rake routes` on the shell:
39
+
40
+
41
+ contact_es_es_path /es-ES/contacto {:locale=>"es", :controller=>"contact", :action=>"index"}
42
+ contact_en_us_path /contact {:locale=>"'en'", :controller=>"contact", :action=>"index"}
43
+
44
+
45
+ As we can see, a new spanish route has been setted up and a `locale` parameter has been added to the routes.
46
+
47
+ 4) Include this filter in your ApplicationController:
48
+
49
+ before_filter :set_locale_from_url
50
+
51
+ Now your application recognizes the different routes and sets the `I18n.locale` value on your controllers,
52
+ but what about the routes generation? As you can see on the previous `rake routes` execution, the
53
+ `contact_es_es_path` and `contact_en_us_path` routing helpers have been generated and are
54
+ available in your controllers and views. Additionally, a `contact_path` helper has been generated, which
55
+ generates the routes according to the current request's locale. This way your link
56
+
57
+ This means that if you use named routes **you don't need to modify your application links** because the routing helpers are automatically adapted to the current locale.
58
+
59
+ 5) Hey, but what about my tests?
60
+
61
+ Of course, your functional and integration testing involves some requests.
62
+ The plugin includes some code to add a default locale parameter so they can remain untouched.
63
+ Append it to your `test_helper` and it will be applied.
64
+
65
+ Documentation
66
+ -------------
67
+ You can find additional information in [the translate_routes' wiki](http://wiki.github.com/raul/translate_routes).
68
+
69
+ Questions, suggestions, bug reports...
70
+ --------------------------------------
71
+ Feedback, questions and comments will be always welcome at raul@murciano.net
72
+
73
+ Credits
74
+ -------
75
+ * Main development:
76
+ * Raul Murciano <http://raul.murciano.net> - code
77
+ * Domestika INTERNET S.L <http://domestika.org> - incredible support, really nice people to work with!
78
+
79
+ * Contributors:
80
+ * [Aitor Garay-Romero](http://github.com/aitorgr)
81
+ * [Christian Hølmer](http://github.com/hoelmer)
82
+ * Nico Ritsche
83
+ * [Cedric Darricau](http://github.com/devsigner)
84
+ * [Olivier Gonzalez](http://github.com/gonzoyumo)
85
+ * [Kristian Mandrup](http://github.com/kristianmandrup)
86
+ * [Pieter Visser](http://github.com/pietervisser)
87
+ * [Marian Theisen](http://github.com/cice)
88
+
89
+ Rails routing resources
90
+ -----------------------
91
+ * David Black's 'Rails Routing' ebook rocks! - 'Ruby for Rails' too, BTW.
92
+ * Obie Fernandez's 'The Rails Way' - the definitive RoR reference, great work Obie!
93
+ * As a part of the impressive Rails Guides set there is an [awesome document about rails routing](http://guides.rails.info/routing_outside_in.html) by Mike Gunderloy:
94
+
95
+
96
+ License
97
+ -------
98
+ Copyright (c) 2007 Released under the MIT license (see MIT-LICENSE)
99
+ Raul Murciano <http://raul.murciano.net>
100
+ Domestika INTERNET S.L. <http://domestika.org>
@@ -0,0 +1,306 @@
1
+
2
+ # This class knows nothing
3
+ # about Rails.root or Rails.application.routes, and therefor is easier to
4
+ # test without an Rails App.
5
+ class RouteTranslator
6
+ TRANSLATABLE_SEGMENT = /^(\w+)(\()?/.freeze
7
+ LOCALE_PARAM_KEY = :locale.freeze
8
+ ROUTE_HELPER_CONTAINER = [
9
+ ActionController::Base,
10
+ ActionView::Base,
11
+ ActionMailer::Base,
12
+ ActionDispatch::Routing::UrlFor
13
+ ].freeze
14
+
15
+ # Attributes
16
+
17
+ attr_accessor :dictionary
18
+
19
+ def available_locales
20
+ @available_locales ||= I18n.available_locales.map(&:to_s)
21
+ end
22
+
23
+ def available_locales= locales
24
+ @available_locales = locales.map(&:to_s)
25
+ end
26
+
27
+ def default_locale
28
+ @default_locale ||= I18n.default_locale.to_s
29
+ end
30
+
31
+ def default_locale= locale
32
+ @default_locale = locale.to_s
33
+ end
34
+
35
+ def default_locale? locale
36
+ default_locale == locale.to_s
37
+ end
38
+
39
+
40
+ class << self
41
+ # Default locale suffix generator
42
+ def locale_suffix locale
43
+ locale.to_s.underscore
44
+ end
45
+
46
+ # Creates a RouteTranslator instance, using I18n dictionaries of
47
+ # your app
48
+ def init_with_i18n *wanted_locales
49
+ new.tap do |t|
50
+ t.init_i18n_dictionary *wanted_locales
51
+ end
52
+ end
53
+
54
+ # Creates a RouteTranslator instance and evaluates given block
55
+ # with an empty dictionary
56
+ def init_with_yield &block
57
+ new.tap do |t|
58
+ t.yield_dictionary &block
59
+ end
60
+ end
61
+
62
+ # Creates a RouteTranslator instance and reads the translations
63
+ # from a specified file
64
+ def init_from_file file_path
65
+ new.tap do |t|
66
+ t.load_dictionary_from_file file_path
67
+ end
68
+ end
69
+ end
70
+
71
+ module DictionaryManagement
72
+ # Resets dictionary and yields the block wich can be used to manually fill the dictionary
73
+ # with translations e.g.
74
+ # route_translator = RouteTranslator.new
75
+ # route_translator.yield_dictionary do |dict|
76
+ # dict['en'] = { 'people' => 'people' }
77
+ # dict['de'] = { 'people' => 'personen' }
78
+ # end
79
+ def yield_dictionary &block
80
+ reset_dictionary
81
+ yield @dictionary
82
+ set_available_locales_from_dictionary
83
+ end
84
+
85
+ # Resets dictionary and loads translations from specified file
86
+ # config/locales/routes.yml:
87
+ # en:
88
+ # people: people
89
+ # de:
90
+ # people: personen
91
+ # routes.rb:
92
+ # ... your routes ...
93
+ # ActionDispatch::Routing::Translator.translate_from_file
94
+ # or, to specify a custom file
95
+ # ActionDispatch::Routing::Translator.translate_from_file 'config', 'locales', 'routes.yml'
96
+ def load_dictionary_from_file file_path
97
+ reset_dictionary
98
+ add_dictionary_from_file file_path
99
+ end
100
+
101
+ # Add translations from another file to the dictionary.
102
+ def add_dictionary_from_file file_path
103
+ yaml = YAML.load_file(file_path)
104
+ yaml.each_pair do |locale, translations|
105
+ merge_translations locale, translations
106
+ end
107
+ set_available_locales_from_dictionary
108
+ end
109
+
110
+ # Merge translations for a specified locale into the dictionary
111
+ def merge_translations locale, translations
112
+ locale = locale.to_s
113
+ if translations.blank?
114
+ @dictionary[locale] ||= {}
115
+ return
116
+ end
117
+ @dictionary[locale] = (@dictionary[locale] || {}).merge(translations)
118
+ end
119
+
120
+ # Init dictionary to use I18n to translate route parts. Creates
121
+ # a hash with a block for each locale to lookup keys in I18n dynamically.
122
+ def init_i18n_dictionary *wanted_locales
123
+ wanted_locales = available_locales if wanted_locales.blank?
124
+ reset_dictionary
125
+ wanted_locales.each do |locale|
126
+ @dictionary[locale] = Hash.new do |hsh, key|
127
+ hsh[key] = I18n.translate key, :locale => locale #DISCUSS: caching or no caching (store key and translation in dictionary?)
128
+ end
129
+ end
130
+ @available_locales = @dictionary.keys.map &:to_s
131
+ end
132
+
133
+ private
134
+ def set_available_locales_from_dictionary
135
+ @available_locales = @dictionary.keys.map &:to_s
136
+ end
137
+
138
+ # Resets dictionary
139
+ def reset_dictionary
140
+ @dictionary = { default_locale => {}}
141
+ end
142
+ end
143
+ include DictionaryManagement
144
+
145
+ module Translator
146
+ # Translate a specific RouteSet, usually Rails.application.routes, but can
147
+ # be a RouteSet of a gem, plugin/engine etc.
148
+ def translate route_set
149
+ Rails.logger.info "Translating routes (default locale: #{default_locale})" if defined?(Rails) && defined?(Rails.logger)
150
+
151
+ # save original routes and clear route set
152
+ original_routes = route_set.routes.dup # Array [routeA, routeB, ...]
153
+
154
+ original_named_routes = route_set.named_routes.routes.dup # Hash {:name => :route}
155
+
156
+ reset_route_set route_set
157
+
158
+ original_routes.each do |original_route|
159
+ translations_for(original_route).each do |translated_route_args|
160
+ route_set.add_route *translated_route_args
161
+ end
162
+ end
163
+
164
+ original_named_routes.each_key do |route_name|
165
+ route_set.named_routes.helpers.concat add_untranslated_helpers_to_controllers_and_views(route_name)
166
+ end
167
+
168
+ end
169
+
170
+ # Add unmodified root route to route_set
171
+ def add_root_route root_route, route_set
172
+ root_route.conditions[:path_info] = root_route.conditions[:path_info].dup
173
+ route_set.set.add_route *root_route
174
+ route_set.named_routes[root_route.name] = root_route
175
+ route_set.routes << root_route
176
+ end
177
+
178
+ # Add standard route helpers for default locale e.g.
179
+ # I18n.locale = :de
180
+ # people_path -> people_de_path
181
+ # I18n.locale = :fr
182
+ # people_path -> people_fr_path
183
+ def add_untranslated_helpers_to_controllers_and_views old_name
184
+ ['path', 'url'].map do |suffix|
185
+ new_helper_name = "#{old_name}_#{suffix}"
186
+
187
+ ROUTE_HELPER_CONTAINER.each do |helper_container|
188
+ helper_container.send :define_method, new_helper_name do |*args|
189
+ send "#{old_name}_#{locale_suffix(I18n.locale)}_#{suffix}", *args
190
+ end
191
+ end
192
+
193
+ new_helper_name.to_sym
194
+ end
195
+ end
196
+
197
+ # Generate translations for a single route for all available locales
198
+ def translations_for route
199
+ available_locales.map do |locale|
200
+ translate_route route, locale
201
+ end
202
+ end
203
+
204
+ # Generate translation for a single route for one locale
205
+ def translate_route route, locale
206
+ conditions = { :path_info => translate_path(route.path, locale) }
207
+ conditions[:request_method] = route.conditions[:request_method].source.upcase if route.conditions.has_key? :request_method
208
+ requirements = route.requirements.merge LOCALE_PARAM_KEY => locale
209
+ defaults = route.defaults.merge LOCALE_PARAM_KEY => locale
210
+ new_name = "#{route.name}_#{locale_suffix(locale)}" if route.name
211
+
212
+ [route.app, conditions, requirements, defaults, new_name]
213
+ end
214
+
215
+ # Add prefix for all non-default locales
216
+ def add_prefix? locale
217
+ !default_locale?(locale)
218
+ end
219
+
220
+ # Translates a path and adds the locale prefix.
221
+ def translate_path path, locale
222
+ final_optional_segments = path.match(/(\(.+\))$/)[1] rescue nil # i.e: (.:format)
223
+ path_segments = path.gsub(final_optional_segments,'').split("/")
224
+ new_path = path_segments.map{ |seg| translate_path_segment(seg, locale) }.join('/')
225
+ new_path = "/#{locale}#{new_path}" if add_prefix? locale
226
+ new_path = '/' if new_path.blank?
227
+ final_optional_segments ? new_path + final_optional_segments : new_path
228
+ end
229
+
230
+ # Tries to translate a single path segment. If the path segment
231
+ # contains sth. like a optional format "people(.:format)", only
232
+ # "people" will be translated, if there is no translation, the path
233
+ # segment is blank or begins with a ":" (param key), the segment
234
+ # is returned untouched
235
+ def translate_path_segment segment, locale
236
+ return segment if segment.blank? or segment.starts_with?(":")
237
+
238
+ match = TRANSLATABLE_SEGMENT.match(segment)[1] rescue nil
239
+
240
+ translate_string(match, locale) || segment
241
+ end
242
+
243
+ def translate_string str, locale
244
+ @dictionary[locale.to_s][str.to_s]
245
+ end
246
+
247
+ private
248
+ def reset_route_set route_set
249
+ route_set.clear!
250
+ remove_all_methods_in route_set.named_routes.module
251
+ end
252
+
253
+ def remove_all_methods_in mod
254
+ mod.instance_methods.each do |method|
255
+ mod.send :remove_method, method
256
+ end
257
+ end
258
+ end
259
+ include Translator
260
+
261
+ def locale_suffix locale
262
+ self.class.locale_suffix locale
263
+ end
264
+ end
265
+
266
+ # Adapter for Rails 3 Apps
267
+ module ActionDispatch
268
+ module Routing
269
+ module Translator
270
+ class << self
271
+ def translate &block
272
+ RouteTranslator.init_with_yield(&block).translate Rails.application.routes
273
+ end
274
+
275
+ def translate_from_file *file_path
276
+ file_path = %w(config locales routes.yml) if file_path.blank?
277
+ RouteTranslator.init_from_file(File.join(Rails.root, *file_path)).translate Rails.application.routes
278
+ end
279
+
280
+ def i18n *locales
281
+ RouteTranslator.init_with_i18n(*locales).translate Rails.application.routes
282
+ end
283
+ end
284
+ end
285
+ end
286
+ end
287
+
288
+ # Add set_locale_from_url to controllers
289
+ ActionController::Base.class_eval do
290
+ private
291
+ # called by before_filter
292
+ def set_locale_from_url
293
+ I18n.locale = params[RouteTranslator::LOCALE_PARAM_KEY]
294
+ default_url_options.merge! RouteTranslator::LOCALE_PARAM_KEY => I18n.locale
295
+ end
296
+ end
297
+
298
+ # Add locale_suffix to controllers, views and mailers
299
+ RouteTranslator::ROUTE_HELPER_CONTAINER.each do |klass|
300
+ klass.class_eval do
301
+ private
302
+ def locale_suffix locale
303
+ RouteTranslator.locale_suffix locale
304
+ end
305
+ end
306
+ end
@@ -0,0 +1,33 @@
1
+ # Author: Raul Murciano [http://raul.murciano.net] for Domestika [http://domestika.org]
2
+ # Copyright (c) 2007, Released under the MIT license (see MIT-LICENSE)
3
+
4
+ require 'rails/test_help'
5
+
6
+ # Include default lang on your test requests (test requests doesn't support default_url_options):
7
+ ActionController::TestCase.class_eval do
8
+ unless method_defined?(:process_without_default_language)
9
+ def process_with_default_language(action, parameters = nil, session = nil, flash = nil, http_method = 'GET')
10
+ lang_pair = {:locale, I18n.default_locale.to_s}
11
+ parameters = lang_pair.merge(parameters) rescue lang_pair
12
+ process_without_default_language(action, parameters, session, flash, http_method)
13
+ end
14
+
15
+ alias :process_without_default_language :process
16
+ alias :process :process_with_default_language
17
+ end
18
+ end
19
+
20
+ # Add untranslated helper for named routes to integration tests
21
+ ActionController::Integration::Session.class_eval do
22
+ ['path', 'url'].each do |suffix|
23
+ ActionDispatch::Routing::Translator.original_names.each do |old_name|
24
+ new_helper_name = "#{old_name}_#{suffix}"
25
+ def_new_helper = <<-DEF_NEW_HELPER
26
+ def #{new_helper_name}(*args)
27
+ send("#{old_name}_#{ActionDispatch::Routing::Translator.locale_suffix(I18n.locale)}_#{suffix}", *args)
28
+ end
29
+ DEF_NEW_HELPER
30
+ eval def_new_helper
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,269 @@
1
+ require 'test/unit'
2
+ require 'rubygems'
3
+ require 'mocha'
4
+
5
+ %w(actionpack activesupport actionmailer).each{ |gem_lib| gem gem_lib, '3.0.1' }
6
+ %w(active_support action_pack action_mailer action_controller action_dispatch).each{ |lib| require lib }
7
+
8
+ plugin_root = File.join(File.dirname(__FILE__), '..')
9
+ require "#{plugin_root}/lib/route_translator"
10
+
11
+
12
+ class PeopleController < ActionController::Base; end
13
+
14
+ class TranslateRoutesTest < ActionController::TestCase
15
+ include ActionDispatch::Assertions::RoutingAssertions
16
+
17
+ def config_default_locale_settings(locale)
18
+ I18n.default_locale = locale
19
+ end
20
+
21
+ def translate_routes
22
+ @route_translator.translate @routes
23
+ @routes.finalize!
24
+ @routes.named_routes.install
25
+ end
26
+
27
+ def setup
28
+ @controller = ActionController::Base.new
29
+ @view = ActionView::Base.new
30
+ @routes = ActionDispatch::Routing::RouteSet.new
31
+ @route_translator = RouteTranslator.new
32
+ end
33
+
34
+ def test_unnamed_root_route
35
+ @routes.draw { root :to => 'people#index' }
36
+ config_default_locale_settings 'en'
37
+ @route_translator.yield_dictionary { |t| t['en'] = {}; t['es'] = {'people' => 'gente'} }
38
+ translate_routes
39
+
40
+ assert_routing '/', :controller => 'people', :action => 'index', :locale => 'en'
41
+ assert_routing '/es', :controller => 'people', :action => 'index', :locale => 'es'
42
+ end
43
+
44
+ def test_unnamed_root_route_without_prefix
45
+ @routes.draw { root :to => 'people#index' }
46
+ config_default_locale_settings 'es'
47
+ @route_translator.load_dictionary_from_file File.expand_path('locales/routes.yml', File.dirname(__FILE__))
48
+ translate_routes
49
+
50
+ assert_routing '/', :controller => 'people', :action => 'index', :locale => 'es'
51
+ assert_routing '/en', :controller => 'people', :action => 'index', :locale => 'en'
52
+ assert_unrecognized_route '/es', :controller => 'people', :action => 'index', :locale => 'es'
53
+ end
54
+
55
+ def test_unnamed_untranslated_route
56
+ @routes.draw { match 'foo', :to => 'people#index' }
57
+ config_default_locale_settings 'en'
58
+ @route_translator.yield_dictionary { |t| t['en'] = {}; t['es'] = {'people' => 'gente'} }
59
+ translate_routes
60
+
61
+ assert_routing '/es/foo', :controller => 'people', :action => 'index', :locale => 'es'
62
+ assert_routing '/foo', :controller => 'people', :action => 'index', :locale => 'en'
63
+ end
64
+
65
+ def test_unnamed_translated_route_on_default_locale
66
+ @routes.draw { match 'people', :to => 'people#index' }
67
+ config_default_locale_settings 'es'
68
+ @route_translator.yield_dictionary { |t| t['en'] = {}; t['es'] = {'people' => 'gente'} }
69
+ translate_routes
70
+
71
+ assert_routing '/en/people', :controller => 'people', :action => 'index', :locale => 'en'
72
+ assert_routing '/gente', :controller => 'people', :action => 'index', :locale => 'es'
73
+ end
74
+
75
+ def test_unnamed_translated_route_on_non_default_locale
76
+ @routes.draw { match 'people', :to => 'people#index' }
77
+ config_default_locale_settings 'en'
78
+ @route_translator.yield_dictionary { |t| t['en'] = {}; t['es'] = {'people' => 'gente'} }
79
+ translate_routes
80
+
81
+ assert_routing '/es/gente', :controller => 'people', :action => 'index', :locale => 'es'
82
+ assert_routing '/people', :controller => 'people', :action => 'index', :locale => 'en'
83
+ end
84
+
85
+ def test_named_translated_route_with_prefix_must_have_locale_as_static_segment
86
+ @routes.draw { match 'people', :to => 'people#index', :as => 'people' }
87
+ config_default_locale_settings 'en'
88
+ @route_translator.yield_dictionary { |t| t['en'] = {}; t['es'] = {'people' => 'gente'} }
89
+ translate_routes
90
+
91
+ # we check the string representation of the route,
92
+ # if it stores locale as a dynamic segment it would be represented as: "/:locale/gente"
93
+ assert_equal "/es/gente(.:format)", path_string(named_route('people_es'))
94
+ end
95
+
96
+ def test_named_empty_route_without_prefix
97
+ @routes.draw { root :to => 'people#index', :as => 'people' }
98
+ config_default_locale_settings 'es'
99
+ @route_translator.yield_dictionary { |t| t['es'] = {}; t['en'] = {'people' => 'gente'}; }
100
+ translate_routes
101
+
102
+ assert_routing '/en', :controller => 'people', :action => 'index', :locale => 'en'
103
+ assert_routing '/', :controller => 'people', :action => 'index', :locale => 'es'
104
+ assert_routing '', :controller => 'people', :action => 'index', :locale => 'es'
105
+ end
106
+
107
+ def test_named_root_route_without_prefix
108
+ @routes.draw { root :to => 'people#index' }
109
+ config_default_locale_settings 'es'
110
+ @route_translator.load_dictionary_from_file File.expand_path('locales/routes.yml', File.dirname(__FILE__))
111
+ translate_routes
112
+
113
+ assert_routing '/', :controller => 'people', :action => 'index', :locale => 'es'
114
+ assert_routing '/en', :controller => 'people', :action => 'index', :locale => 'en'
115
+ assert_unrecognized_route '/es', :controller => 'people', :action => 'index', :locale => 'es'
116
+ end
117
+
118
+ def test_named_untranslated_route_without_prefix
119
+ @routes.draw { match 'foo', :to => 'people#index', :as => 'people' }
120
+ config_default_locale_settings 'es'
121
+ @route_translator.yield_dictionary { |t| t['en'] = {}; t['es'] = {'people' => 'gente'} }
122
+ translate_routes
123
+
124
+ assert_routing '/en/foo', :controller => 'people', :action => 'index', :locale => 'en'
125
+ assert_routing 'foo', :controller => 'people', :action => 'index', :locale => 'es'
126
+ assert_helpers_include :people_en, :people_es, :people
127
+ end
128
+
129
+ def test_named_translated_route_on_default_locale_without_prefix
130
+ @routes.draw { match 'people', :to => 'people#index', :as => 'people'}
131
+ config_default_locale_settings 'es'
132
+ @route_translator.yield_dictionary { |t| t['en'] = {}; t['es'] = {'people' => 'gente'} }
133
+ translate_routes
134
+
135
+ assert_routing '/en/people', :controller => 'people', :action => 'index', :locale => 'en'
136
+ assert_routing 'gente', :controller => 'people', :action => 'index', :locale => 'es'
137
+ assert_helpers_include :people_en, :people_es, :people
138
+ end
139
+
140
+ def test_named_translated_route_on_non_default_locale_without_prefix
141
+ @routes.draw { match 'people', :to => 'people#index', :as => 'people'}
142
+ config_default_locale_settings 'en'
143
+ @route_translator.yield_dictionary { |t| t['en'] = {}; t['es'] = {'people' => 'gente'} }
144
+ translate_routes
145
+
146
+ assert_routing '/people', :controller => 'people', :action => 'index', :locale => 'en'
147
+ assert_routing '/es/gente', :controller => 'people', :action => 'index', :locale => 'es'
148
+ assert_helpers_include :people_en, :people_es, :people
149
+ end
150
+
151
+ def test_formatted_root_route
152
+ @routes.draw{ root :to => 'people#index', :as => 'root' }
153
+ @route_translator.yield_dictionary { |t| t['en'] = {}; t['es'] = {'people' => 'gente'} }
154
+ assert_equal '/(.:format)', path_string(named_route('root'))
155
+ translate_routes
156
+ assert_equal '/(.:format)', path_string(named_route('root_en'))
157
+ assert_equal '/es(.:format)', path_string(named_route('root_es'))
158
+ end
159
+
160
+
161
+ def test_languages_load_from_file
162
+ @routes.draw { match 'people', :to => 'people#index', :as => 'people'}
163
+ config_default_locale_settings 'en'
164
+ @route_translator.load_dictionary_from_file File.expand_path('locales/routes.yml', File.dirname(__FILE__))
165
+ translate_routes
166
+
167
+ assert_routing '/people', :controller => 'people', :action => 'index', :locale => 'en'
168
+ assert_routing '/es/gente', :controller => 'people', :action => 'index', :locale => 'es'
169
+ assert_helpers_include :people_en, :people_es, :people
170
+ end
171
+
172
+ def test_languages_load_from_file_without_dictionary_for_default_locale
173
+ @routes.draw { match 'people', :to => 'people#index', :as => 'people'}
174
+ config_default_locale_settings 'fr'
175
+ @route_translator.load_dictionary_from_file File.expand_path('locales/routes.yml', File.dirname(__FILE__))
176
+ translate_routes
177
+
178
+ assert_routing '/people', :controller => 'people', :action => 'index', :locale => 'fr'
179
+ assert_routing '/en/people', :controller => 'people', :action => 'index', :locale => 'en'
180
+ assert_routing '/es/gente', :controller => 'people', :action => 'index', :locale => 'es'
181
+ assert_helpers_include :people_fr, :people_en, :people_es, :people
182
+ end
183
+
184
+ def test_i18n_based_translations_setting_locales
185
+ @routes.draw { match 'people', :to => 'people#index', :as => 'people'}
186
+ config_default_locale_settings 'en'
187
+ I18n.backend = StubbedI18nBackend
188
+ @route_translator.init_i18n_dictionary 'es'
189
+ translate_routes
190
+
191
+ assert_routing '/es/gente', :controller => 'people', :action => 'index', :locale => 'es'
192
+ assert_routing '/people', :controller => 'people', :action => 'index', :locale => 'en'
193
+ assert_helpers_include :people_en, :people_es, :people
194
+ end
195
+
196
+ def test_i18n_based_translations_taking_i18n_available_locales
197
+ @routes.draw { match 'people', :to => 'people#index', :as => 'people'}
198
+ config_default_locale_settings 'en'
199
+ I18n.stubs(:available_locales).at_least_once.returns StubbedI18nBackend.available_locales
200
+ I18n.backend = StubbedI18nBackend
201
+ @route_translator.init_i18n_dictionary
202
+ translate_routes
203
+
204
+ assert_routing '/fr/people', :controller => 'people', :action => 'index', :locale => 'fr'
205
+ assert_routing '/es/gente', :controller => 'people', :action => 'index', :locale => 'es'
206
+ assert_routing '/people', :controller => 'people', :action => 'index', :locale => 'en'
207
+ assert_helpers_include :people_fr, :people_en, :people_es, :people
208
+ end
209
+
210
+ def test_action_controller_gets_locale_setter
211
+ ActionController::Base.instance_methods.include?('set_locale_from_url')
212
+ end
213
+
214
+ def test_action_controller_gets_locale_suffix_helper
215
+ ActionController::Base.instance_methods.include?('locale_suffix')
216
+ end
217
+
218
+ def test_action_view_gets_locale_suffix_helper
219
+ ActionView::Base.instance_methods.include?('locale_suffix')
220
+ end
221
+
222
+ private
223
+
224
+ # Given a route defined as a string like this:
225
+ # 'ANY /es(.:format) {:controller=>"people", :action=>"index"}'
226
+ # returns "/es(.:format)"
227
+ def path_string(route)
228
+ route.to_s.split(' ')[1]
229
+ end
230
+
231
+ def named_route(name)
232
+ @routes.routes.select{ |r| r.name == name }.first
233
+ end
234
+
235
+ def assert_helpers_include(*helpers)
236
+ helpers.each do |helper|
237
+ ['url', 'path'].each do |suffix|
238
+ [@controller, @view].each { |obj| assert_respond_to obj, "#{helper}_#{suffix}".to_sym }
239
+ end
240
+ end
241
+ end
242
+
243
+ def assert_unrecognized_route(route_path, options)
244
+ assert_raise ActionController::RoutingError do
245
+ assert_routing route_path, options
246
+ end
247
+ end
248
+
249
+ class StubbedI18nBackend
250
+
251
+
252
+ @@translations = {
253
+ 'es' => { 'people' => 'gente'},
254
+ 'fr' => {} # empty on purpose to test behaviour on incompleteness scenarios
255
+ }
256
+
257
+ def self.translate(locale, key, options)
258
+ @@translations[locale.to_s][key] || options[:default]
259
+ rescue
260
+ options[:default]
261
+ end
262
+
263
+ def self.available_locales
264
+ @@translations.keys
265
+ end
266
+
267
+ end
268
+
269
+ end
metadata ADDED
@@ -0,0 +1,70 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: translate_routes
3
+ version: !ruby/object:Gem::Version
4
+ hash: 5
5
+ prerelease: false
6
+ segments:
7
+ - 3
8
+ - 0
9
+ - 1
10
+ version: 3.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Raul Murciano
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-11-18 00:00:00 +01:00
19
+ default_executable:
20
+ dependencies: []
21
+
22
+ description: Translates the Rails routes of your application into the languages defined in your locale files
23
+ email: raul@murciano.net
24
+ executables: []
25
+
26
+ extensions: []
27
+
28
+ extra_rdoc_files:
29
+ - README.markdown
30
+ files:
31
+ - lib/route_translator.rb
32
+ - lib/translate_routes_test_helper.rb
33
+ - README.markdown
34
+ - test/translate_routes_test.rb
35
+ has_rdoc: true
36
+ homepage: http://github.com/raul/translate_routes
37
+ licenses: []
38
+
39
+ post_install_message:
40
+ rdoc_options:
41
+ - --charset=UTF-8
42
+ require_paths:
43
+ - lib
44
+ required_ruby_version: !ruby/object:Gem::Requirement
45
+ none: false
46
+ requirements:
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ hash: 3
50
+ segments:
51
+ - 0
52
+ version: "0"
53
+ required_rubygems_version: !ruby/object:Gem::Requirement
54
+ none: false
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ hash: 3
59
+ segments:
60
+ - 0
61
+ version: "0"
62
+ requirements: []
63
+
64
+ rubyforge_project:
65
+ rubygems_version: 1.3.7
66
+ signing_key:
67
+ specification_version: 3
68
+ summary: Translate your Rails routes in a simple manner
69
+ test_files:
70
+ - test/translate_routes_test.rb