fishman-i18n_routing 0.4.9
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.rdoc +99 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +81 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +32 -0
- data/Rakefile +28 -0
- data/init.rb +2 -0
- data/lib/i18n_routing.rb +8 -0
- data/lib/i18n_routing_common.rb +52 -0
- data/lib/i18n_routing_rails2.rb +237 -0
- data/lib/i18n_routing_rails3.rb +392 -0
- data/lib/i18n_routing_rails3.rb.orig +388 -0
- data/spec/i18n_routing/i18n_spec.rb +397 -0
- data/spec/locales/en.yml +15 -0
- data/spec/locales/fr.yml +36 -0
- data/spec/locales/pt-br.yml +9 -0
- data/spec/spec_helper.rb +44 -0
- metadata +82 -0
@@ -0,0 +1,397 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe :localized_routes do
|
4
|
+
|
5
|
+
$r = nil # Global routes in order to speed up testing
|
6
|
+
|
7
|
+
before(:all) do
|
8
|
+
|
9
|
+
if !$r
|
10
|
+
if !rails3?
|
11
|
+
ActionController::Routing::Routes.clear!
|
12
|
+
ActionController::Routing::Routes.draw do |map|
|
13
|
+
map.not_about 'not_about', :controller => 'not_about'
|
14
|
+
map.resources :not_users
|
15
|
+
map.resource :not_contact
|
16
|
+
|
17
|
+
map.localized(I18n.available_locales, :verbose => false) do
|
18
|
+
map.about 'about', :controller => 'about', :action => :show
|
19
|
+
map.welcome 'welcome/to/our/page', :controller => :welcome, :action => :index
|
20
|
+
map.empty 'empty', :controller => 'empty', :action => :show
|
21
|
+
|
22
|
+
map.resources :users, :member => {:level => :get, :one => :get, :two => :get}, :collection => {:groups => :get}
|
23
|
+
map.resource :contact
|
24
|
+
|
25
|
+
map.resources :authors do |m|
|
26
|
+
m.resources :books
|
27
|
+
end
|
28
|
+
|
29
|
+
map.resources :empty_resources
|
30
|
+
|
31
|
+
map.resource :foo do |m|
|
32
|
+
m.resources :bars
|
33
|
+
m.resource :foofoo do |mm|
|
34
|
+
mm.resources :bars
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
map.resources :universes do |m|
|
39
|
+
m.resources :galaxies do |mm|
|
40
|
+
mm.resources :planets do |mmm|
|
41
|
+
mmm.resources :countries
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
map.with_options :path_prefix => ':locale' do |l|
|
47
|
+
l.localized_root '/', :controller => "about", :action => "show"
|
48
|
+
l.about_with_locale 'about', :controller => "about", :action => "show"
|
49
|
+
l.about_with_locale_with_sep 'about', :controller => "about", :action => "show"
|
50
|
+
l.resources :empty__resources
|
51
|
+
end
|
52
|
+
|
53
|
+
map.resources :drones, :path_prefix => 'doubledrones/unimatrix/zero'
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
$r = ActionController::Routing::Routes
|
58
|
+
|
59
|
+
class UrlTester
|
60
|
+
include ActionController::UrlWriter
|
61
|
+
end
|
62
|
+
|
63
|
+
else
|
64
|
+
|
65
|
+
$r = ActionDispatch::Routing::RouteSet.new
|
66
|
+
$r.draw do
|
67
|
+
match 'not_about' => "not_about#show", :as => :not_about
|
68
|
+
resources :not_users
|
69
|
+
resources :empty_resources
|
70
|
+
resource :not_contact
|
71
|
+
|
72
|
+
localized(I18n.available_locales, :verbose => true) do
|
73
|
+
match 'about' => "about#show", :as => :about
|
74
|
+
match 'welcome/to/our/page' => "welcome#index", :as => :welcome
|
75
|
+
match 'empty' => 'empty#show', :as => :empty
|
76
|
+
|
77
|
+
scope '/:locale', :constraints => { :locale => /[a-z]{2}/ } do ### this constraint fail on rails 3.0.4, so I had to hack a turn around
|
78
|
+
match '/' => "about#show", :as => :localized_root
|
79
|
+
match 'about' => "about#show", :as => :about_with_locale
|
80
|
+
match '/about' => "about#show", :as => :about_with_locale_with_sep
|
81
|
+
resources :empty__resources
|
82
|
+
end
|
83
|
+
|
84
|
+
resources :users do
|
85
|
+
member do
|
86
|
+
get :level
|
87
|
+
get :one, :two
|
88
|
+
end
|
89
|
+
get :groups, :on => :collection
|
90
|
+
end
|
91
|
+
resource :contact
|
92
|
+
|
93
|
+
resources :authors do
|
94
|
+
resources :books
|
95
|
+
end
|
96
|
+
|
97
|
+
resource :foo do
|
98
|
+
resources :bars
|
99
|
+
resource :foofoo do
|
100
|
+
resources :bars
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
resources :universes do
|
105
|
+
resources :galaxies do
|
106
|
+
resources :planets do
|
107
|
+
scope do
|
108
|
+
resources :countries
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
class UrlTester; end
|
118
|
+
UrlTester.send :include, $r.url_helpers
|
119
|
+
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
end
|
124
|
+
|
125
|
+
let(:nested_routes) { $r.named_routes.instance_eval { routes } }
|
126
|
+
let(:routes) { UrlTester.new }
|
127
|
+
|
128
|
+
def url_for(opts)
|
129
|
+
$r.generate_extras(opts).first
|
130
|
+
end
|
131
|
+
|
132
|
+
context "do not break existing behavior" do
|
133
|
+
|
134
|
+
it "of named_routes" do
|
135
|
+
routes.send(:not_about_path).should == "/not_about"
|
136
|
+
end
|
137
|
+
|
138
|
+
it "of a singular resource" do
|
139
|
+
routes.send(:not_contact_path).should == "/not_contact"
|
140
|
+
end
|
141
|
+
|
142
|
+
it "of resources" do
|
143
|
+
routes.send(:not_users_path).should == "/not_users"
|
144
|
+
end
|
145
|
+
|
146
|
+
end
|
147
|
+
|
148
|
+
context "for default routes" do
|
149
|
+
|
150
|
+
before do
|
151
|
+
I18n.locale = :de # Not localized
|
152
|
+
end
|
153
|
+
|
154
|
+
it "named_route uses default values" do
|
155
|
+
routes.send(:about_path).should == "/about"
|
156
|
+
routes.send(:welcome_path).should == '/welcome/to/our/page'
|
157
|
+
end
|
158
|
+
|
159
|
+
it "resource generates routes using default values" do
|
160
|
+
routes.send(:contact_path).should == "/contact"
|
161
|
+
end
|
162
|
+
|
163
|
+
it "resources generates routes using default values" do
|
164
|
+
routes.send(:users_path).should == "/users"
|
165
|
+
end
|
166
|
+
|
167
|
+
it "url_for generates route using default values" do
|
168
|
+
url_for(:controller => :users).should == "/users"
|
169
|
+
end
|
170
|
+
|
171
|
+
it "nested resources generate routes using default values" do
|
172
|
+
routes.send(:author_books_path, 1).should == "/authors/1/books"
|
173
|
+
end
|
174
|
+
|
175
|
+
it "deep nested resources generate routes using default values" do
|
176
|
+
routes.send(:universes_path).should == "/universes"
|
177
|
+
routes.send(:universe_galaxies_path, 1).should == "/universes/1/galaxies"
|
178
|
+
routes.send(:universe_galaxy_planets_path, 1, 1).should == "/universes/1/galaxies/1/planets"
|
179
|
+
end
|
180
|
+
|
181
|
+
it "single resource should have by default the pluralized controller" do
|
182
|
+
nested_routes[:foo].defaults[:controller].should == 'foos'
|
183
|
+
end
|
184
|
+
|
185
|
+
it "scope with parameters should be respected" do
|
186
|
+
routes.send(:localized_root_path, I18n.locale).should == "/#{I18n.locale}"
|
187
|
+
end
|
188
|
+
|
189
|
+
it "scope with parameters should be respected when filled" do
|
190
|
+
routes.send(:about_with_locale_path, I18n.locale).should == "/#{I18n.locale}/about"
|
191
|
+
routes.send(:about_with_locale_with_sep_path, I18n.locale).should == "/#{I18n.locale}/about"
|
192
|
+
end
|
193
|
+
|
194
|
+
end
|
195
|
+
|
196
|
+
context "" do
|
197
|
+
|
198
|
+
before do
|
199
|
+
I18n.locale = :fr
|
200
|
+
end
|
201
|
+
|
202
|
+
it "scope with parameters should be respected" do
|
203
|
+
routes.send(:localized_root_path, I18n.locale).should == "/#{I18n.locale}"
|
204
|
+
end
|
205
|
+
|
206
|
+
it "scope with parameters should be respected when filled" do
|
207
|
+
routes.send(:about_with_locale_path, I18n.locale).should == "/#{I18n.locale}/#{I18n.t :about, :scope => :named_routes_path}"
|
208
|
+
routes.send(:about_with_locale_with_sep_path, I18n.locale).should == "/#{I18n.locale}/#{I18n.t :about, :scope => :named_routes_path}"
|
209
|
+
end
|
210
|
+
|
211
|
+
it "named_route generates route using localized values" do
|
212
|
+
routes.send(:about_path).should == "/#{I18n.t :about, :scope => :named_routes_path}"
|
213
|
+
end
|
214
|
+
|
215
|
+
it "named_route generated route from actual route name" do
|
216
|
+
I18n.locale = :en
|
217
|
+
routes.send(:welcome_path).should == "/#{I18n.t :welcome, :scope => :named_routes}"
|
218
|
+
I18n.locale = :fr
|
219
|
+
end
|
220
|
+
|
221
|
+
it "named_route generates route from route path when route name not available" do
|
222
|
+
routes.send(:welcome_path).should == "/#{I18n.t 'welcome/to/our/page', :scope => :named_routes_path}"
|
223
|
+
end
|
224
|
+
|
225
|
+
it "doesn't translate empty route" do
|
226
|
+
routes.send(:empty_path).should_not == "/#{I18n.t 'empty', :scope => :named_routes_path}"
|
227
|
+
routes.send(:empty_path).should == "/empty"
|
228
|
+
routes.send(:empty_resources_path).should_not == "/#{I18n.t 'empty', :scope => :named_routes_path}"
|
229
|
+
routes.send(:empty_resources_path).should == "/empty_resources"
|
230
|
+
nested_routes.keys.include?(:fr_empty__resources).should == false # Because translation is empty
|
231
|
+
nested_routes.keys.include?('fr_empty__resources').should == false # Because translation is empty
|
232
|
+
end
|
233
|
+
|
234
|
+
it "named_route generates route using localized values and I18n.locale as a string" do
|
235
|
+
o = I18n.locale
|
236
|
+
I18n.locale = "fr"
|
237
|
+
routes.send(:about_path).should == "/#{I18n.t :about, :scope => :named_routes_path}"
|
238
|
+
I18n.locale = o
|
239
|
+
end
|
240
|
+
|
241
|
+
it "resource generates routes using localized values" do
|
242
|
+
routes.send(:contact_path).should == "/#{I18n.t :contact, :scope => :resource}"
|
243
|
+
end
|
244
|
+
|
245
|
+
it "resources generates routes using localized values" do
|
246
|
+
routes.send(:users_path).should == "/#{I18n.t :as, :scope => :'routes.users'}"
|
247
|
+
end
|
248
|
+
|
249
|
+
it "url_for generates routes using localized values" do
|
250
|
+
url_for(:controller => :users).should == "/#{I18n.t :as, :scope => :'routes.users'}"
|
251
|
+
url_for(:controller => :about, :action => :show).should == "/#{I18n.t :about, :scope => :named_routes_path}"
|
252
|
+
end
|
253
|
+
|
254
|
+
if !rails3?
|
255
|
+
it "url_for generates routes for drones with path prefix" do
|
256
|
+
url_for(:controller => :drones).should == "#{I18n.t :path_prefix, :scope => :'routes.drones'}/#{I18n.t :as, :scope => :'routes.drones'}"
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
it "nested resources generate routes using localized values" do
|
261
|
+
routes.send(:author_books_path, 1).should == "/#{I18n.t :authors, :scope => :resources}/1/#{I18n.t :books, :scope => :resources}"
|
262
|
+
end
|
263
|
+
|
264
|
+
it "deep nested resources generate routes using localized values and translate routes even translated name is the same" do
|
265
|
+
routes.send(:universes_path).should == "/#{I18n.t :universes, :scope => :resources}"
|
266
|
+
routes.send(:universe_galaxies_path, 1).should == "/#{I18n.t :universes, :scope => :resources}/1/#{I18n.t :galaxies, :scope => :resources}"
|
267
|
+
routes.send(:universe_galaxy_planets_path, 1, 1).should == "/#{I18n.t :universes, :scope => :resources}/1/#{I18n.t :galaxies, :scope => :resources}/1/#{I18n.t :planets, :scope => :resources}"
|
268
|
+
routes.send(:universe_galaxy_planet_countries_path, 1, 1, 42).should == "/#{I18n.t :universes, :scope => :resources}/1/#{I18n.t :galaxies, :scope => :resources}/1/#{I18n.t :planets, :scope => :resources}/42/#{I18n.t :countries, :scope => :resources}"
|
269
|
+
end
|
270
|
+
|
271
|
+
context "with path_names" do
|
272
|
+
|
273
|
+
it "default translated path names" do
|
274
|
+
routes.send(:new_universe_path).should == "/#{I18n.t :universes, :scope => :resources}/#{I18n.t :new, :scope => :path_names}"
|
275
|
+
routes.send(:edit_universe_path, 42).should == "/#{I18n.t :universes, :scope => :resources}/42/#{I18n.t :edit, :scope => :path_names}"
|
276
|
+
end
|
277
|
+
|
278
|
+
it "custom translated path names" do
|
279
|
+
routes.send(:new_user_path).should == "/#{I18n.t :users, :scope => :resources}/#{I18n.t :new, :scope => :'routes.users.path_names'}"
|
280
|
+
routes.send(:edit_user_path, 42).should == "/#{I18n.t :users, :scope => :resources}/42/#{I18n.t :edit, :scope => :'routes.users.path_names'}"
|
281
|
+
end
|
282
|
+
|
283
|
+
end
|
284
|
+
|
285
|
+
context "with member and collection" do
|
286
|
+
|
287
|
+
it "custom member" do
|
288
|
+
I18n.locale = :en
|
289
|
+
routes.send(:level_user_path, 42).should == "/#{I18n.t :users, :scope => :resources}/42/level"
|
290
|
+
I18n.locale = :fr
|
291
|
+
routes.send(:level_user_path, 42).should == "/#{I18n.t :users, :scope => :resources}/42/#{I18n.t :level, :scope => :'routes.users.path_names'}"
|
292
|
+
routes.send(:one_user_path, 42).should == "/#{I18n.t :users, :scope => :resources}/42/#{I18n.t :one, :scope => :'routes.users.path_names'}"
|
293
|
+
routes.send(:two_user_path, 42).should == "/#{I18n.t :users, :scope => :resources}/42/#{I18n.t :two, :scope => :'routes.users.path_names'}"
|
294
|
+
end
|
295
|
+
|
296
|
+
it "custom collection" do
|
297
|
+
I18n.locale = :en
|
298
|
+
routes.send(:groups_users_path).should == "/#{I18n.t :users, :scope => :resources}/groups"
|
299
|
+
I18n.locale = :fr
|
300
|
+
routes.send(:groups_users_path).should == "/#{I18n.t :users, :scope => :resources}/#{I18n.t :groups, :scope => :'routes.users.path_names'}"
|
301
|
+
end
|
302
|
+
|
303
|
+
end
|
304
|
+
|
305
|
+
context "when nested" do
|
306
|
+
|
307
|
+
it "named routes should not be nil" do
|
308
|
+
nested_routes[:author_fr_books].should_not be_nil
|
309
|
+
end
|
310
|
+
|
311
|
+
context "in Rails #{Rails.version}" do
|
312
|
+
it "include the correct significant keys" do
|
313
|
+
v = !rails3? ? :significant_keys : :segment_keys
|
314
|
+
nested_routes[:author_books].send(v).should include(:author_id)
|
315
|
+
nested_routes[:author_fr_books].send(v).should include(:author_id)
|
316
|
+
end
|
317
|
+
end
|
318
|
+
|
319
|
+
end
|
320
|
+
|
321
|
+
context "when nested inside a singleton resource" do
|
322
|
+
|
323
|
+
it "named routes should have locale placed at correct position" do
|
324
|
+
nested_routes[:fr_foo_fr_bars].should be_nil
|
325
|
+
nested_routes[:foo_fr_bars].should_not be_nil
|
326
|
+
end
|
327
|
+
|
328
|
+
it "routes for the singleton resource alone should be translated correctly" do
|
329
|
+
routes.send(:foo_path).should == "/#{I18n.t :foo, :scope => :resource}"
|
330
|
+
end
|
331
|
+
|
332
|
+
it "routes should be translated correctly" do
|
333
|
+
routes.send(:foo_bars_path).should == "/#{I18n.t :foo, :scope => :resource}/#{I18n.t :bars, :scope => :resources}"
|
334
|
+
end
|
335
|
+
|
336
|
+
it "routes should be translated correctly also with deep nested singleton resource" do
|
337
|
+
routes.send(:foo_foofoo_bars_path).should == "/#{I18n.t :foo, :scope => :resource}/#{I18n.t :foofoo, :scope => :resource}/#{I18n.t :bars, :scope => :resources}"
|
338
|
+
end
|
339
|
+
|
340
|
+
end
|
341
|
+
|
342
|
+
context "when deeply nested" do
|
343
|
+
|
344
|
+
it "named routes should not be nil" do
|
345
|
+
nested_routes[:universe_galaxy_fr_planet].should_not be_nil
|
346
|
+
end
|
347
|
+
|
348
|
+
context "in Rails #{Rails.version}" do
|
349
|
+
it "include the correct significant keys" do
|
350
|
+
v = !rails3? ? :significant_keys : :segment_keys
|
351
|
+
nested_routes[:universe_galaxy_planet].send(v).should include(:universe_id)
|
352
|
+
nested_routes[:universe_galaxy_fr_planet].send(v).should include(:universe_id)
|
353
|
+
nested_routes[:universe_galaxy_planet].send(v).should include(:galaxy_id)
|
354
|
+
nested_routes[:universe_galaxy_fr_planet].send(v).should include(:galaxy_id)
|
355
|
+
end
|
356
|
+
end
|
357
|
+
end
|
358
|
+
|
359
|
+
it "nested resources do not deep translate with multi helpers" do
|
360
|
+
nested_routes.keys.should_not include(:fr_author_books) # Do not want fr_author_books
|
361
|
+
end
|
362
|
+
|
363
|
+
end
|
364
|
+
|
365
|
+
context 'locale with a dash (pt-br)' do
|
366
|
+
|
367
|
+
before do
|
368
|
+
I18n.locale = 'pt-BR'
|
369
|
+
end
|
370
|
+
|
371
|
+
it 'users resources' do
|
372
|
+
routes.send(:users_path).should == "/#{I18n.t :users, :scope => :'resources'}"
|
373
|
+
end
|
374
|
+
|
375
|
+
it "routes for the singleton resource alone should be translated correctly" do
|
376
|
+
routes.send(:foo_path).should == "/#{I18n.t :foo, :scope => :resource}"
|
377
|
+
end
|
378
|
+
|
379
|
+
it "named_route generates route using localized values" do
|
380
|
+
routes.send(:about_path).should == "/#{I18n.t :about, :scope => :named_routes_path}"
|
381
|
+
end
|
382
|
+
|
383
|
+
it "custom translated path names" do
|
384
|
+
routes.send(:new_user_path).should == "/#{I18n.t :users, :scope => :resources}/#{I18n.t :new, :scope => :'path_names'}"
|
385
|
+
end
|
386
|
+
|
387
|
+
end
|
388
|
+
|
389
|
+
# context "just output" do
|
390
|
+
# it "output all routes properly" do
|
391
|
+
# nested_routes.keys.collect(&:to_s).sort.each do |k|
|
392
|
+
# puts("%50s: %.80s" % [k, (nested_routes[k.to_sym].path rescue nested_routes[k.to_sym].to_s)])
|
393
|
+
# end
|
394
|
+
# end
|
395
|
+
# end
|
396
|
+
|
397
|
+
end
|
data/spec/locales/en.yml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
en:
|
2
|
+
resources:
|
3
|
+
users: members
|
4
|
+
authors: 'authors-en'
|
5
|
+
galaxies: 'galaxies-en'
|
6
|
+
planets: 'planets-en'
|
7
|
+
universes: 'universes-en'
|
8
|
+
bars: bars_en
|
9
|
+
resource:
|
10
|
+
foo: foo_en
|
11
|
+
contact: 'contact-us'
|
12
|
+
named_routes_path:
|
13
|
+
about: 'about-our-company'
|
14
|
+
named_routes:
|
15
|
+
welcome: 'welcome-to-our-page'
|
data/spec/locales/fr.yml
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
fr:
|
2
|
+
routes:
|
3
|
+
users:
|
4
|
+
as: utilisateurs
|
5
|
+
path_names:
|
6
|
+
level: 'niveau'
|
7
|
+
groups: 'groupe'
|
8
|
+
new: 'nouvel_utilisateur'
|
9
|
+
edit: 'edition_utilisateur'
|
10
|
+
one: 'un'
|
11
|
+
two: 'deux'
|
12
|
+
drones:
|
13
|
+
as: senord
|
14
|
+
path_prefix: '/senordelbuod/xirtaminu/orez'
|
15
|
+
resources:
|
16
|
+
users: utilisateurs
|
17
|
+
authors: 'auteurs'
|
18
|
+
books: 'livres'
|
19
|
+
galaxies: 'galaxies'
|
20
|
+
planets: 'planetes'
|
21
|
+
universes: 'univers'
|
22
|
+
countries: 'pays'
|
23
|
+
bars: bars_fr
|
24
|
+
empty_resources: ''
|
25
|
+
empty__resources: ''
|
26
|
+
resource:
|
27
|
+
foo: foo_fr
|
28
|
+
foofoo: froufrou
|
29
|
+
contact: 'contactez-nous'
|
30
|
+
named_routes_path:
|
31
|
+
about: 'a-propos'
|
32
|
+
'welcome/to/our/page': 'bienvenue/sur/notre/site' # no idea about french translation ;-) --R
|
33
|
+
empty: ''
|
34
|
+
path_names:
|
35
|
+
new: 'nouveau'
|
36
|
+
edit: 'edition'
|