rails-translate-routes 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/Gemfile +12 -0
- data/Gemfile.lock +98 -0
- data/LICENSE.txt +20 -0
- data/README.rdoc +163 -0
- data/Rakefile +45 -0
- data/VERSION +1 -0
- data/lib/rails-translate-routes.rb +332 -0
- data/rails-translate-routes.gemspec +62 -0
- data/test/helper.rb +18 -0
- data/test/test_rails-translate-routes.rb +7 -0
- metadata +116 -0
data/.document
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
source "http://rubygems.org"
|
2
|
+
|
3
|
+
gem "rails", ">= 3.0"
|
4
|
+
|
5
|
+
# Add dependencies to develop your gem here.
|
6
|
+
# Include everything needed to run rake, tests, features, etc.
|
7
|
+
group :development do
|
8
|
+
gem "bundler", "~> 1.0.0"
|
9
|
+
gem "jeweler", "~> 1.6.4"
|
10
|
+
gem 'sqlite3'
|
11
|
+
gem "minitest"
|
12
|
+
end
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
actionmailer (3.1.3)
|
5
|
+
actionpack (= 3.1.3)
|
6
|
+
mail (~> 2.3.0)
|
7
|
+
actionpack (3.1.3)
|
8
|
+
activemodel (= 3.1.3)
|
9
|
+
activesupport (= 3.1.3)
|
10
|
+
builder (~> 3.0.0)
|
11
|
+
erubis (~> 2.7.0)
|
12
|
+
i18n (~> 0.6)
|
13
|
+
rack (~> 1.3.5)
|
14
|
+
rack-cache (~> 1.1)
|
15
|
+
rack-mount (~> 0.8.2)
|
16
|
+
rack-test (~> 0.6.1)
|
17
|
+
sprockets (~> 2.0.3)
|
18
|
+
activemodel (3.1.3)
|
19
|
+
activesupport (= 3.1.3)
|
20
|
+
builder (~> 3.0.0)
|
21
|
+
i18n (~> 0.6)
|
22
|
+
activerecord (3.1.3)
|
23
|
+
activemodel (= 3.1.3)
|
24
|
+
activesupport (= 3.1.3)
|
25
|
+
arel (~> 2.2.1)
|
26
|
+
tzinfo (~> 0.3.29)
|
27
|
+
activeresource (3.1.3)
|
28
|
+
activemodel (= 3.1.3)
|
29
|
+
activesupport (= 3.1.3)
|
30
|
+
activesupport (3.1.3)
|
31
|
+
multi_json (~> 1.0)
|
32
|
+
arel (2.2.1)
|
33
|
+
builder (3.0.0)
|
34
|
+
erubis (2.7.0)
|
35
|
+
git (1.2.5)
|
36
|
+
hike (1.2.1)
|
37
|
+
i18n (0.6.0)
|
38
|
+
jeweler (1.6.4)
|
39
|
+
bundler (~> 1.0)
|
40
|
+
git (>= 1.2.5)
|
41
|
+
rake
|
42
|
+
json (1.6.4)
|
43
|
+
mail (2.3.0)
|
44
|
+
i18n (>= 0.4.0)
|
45
|
+
mime-types (~> 1.16)
|
46
|
+
treetop (~> 1.4.8)
|
47
|
+
mime-types (1.17.2)
|
48
|
+
minitest (2.10.0)
|
49
|
+
multi_json (1.0.4)
|
50
|
+
polyglot (0.3.3)
|
51
|
+
rack (1.3.6)
|
52
|
+
rack-cache (1.1)
|
53
|
+
rack (>= 0.4)
|
54
|
+
rack-mount (0.8.3)
|
55
|
+
rack (>= 1.0.0)
|
56
|
+
rack-ssl (1.3.2)
|
57
|
+
rack
|
58
|
+
rack-test (0.6.1)
|
59
|
+
rack (>= 1.0)
|
60
|
+
rails (3.1.3)
|
61
|
+
actionmailer (= 3.1.3)
|
62
|
+
actionpack (= 3.1.3)
|
63
|
+
activerecord (= 3.1.3)
|
64
|
+
activeresource (= 3.1.3)
|
65
|
+
activesupport (= 3.1.3)
|
66
|
+
bundler (~> 1.0)
|
67
|
+
railties (= 3.1.3)
|
68
|
+
railties (3.1.3)
|
69
|
+
actionpack (= 3.1.3)
|
70
|
+
activesupport (= 3.1.3)
|
71
|
+
rack-ssl (~> 1.3.2)
|
72
|
+
rake (>= 0.8.7)
|
73
|
+
rdoc (~> 3.4)
|
74
|
+
thor (~> 0.14.6)
|
75
|
+
rake (0.9.2.2)
|
76
|
+
rdoc (3.12)
|
77
|
+
json (~> 1.4)
|
78
|
+
sprockets (2.0.3)
|
79
|
+
hike (~> 1.2)
|
80
|
+
rack (~> 1.0)
|
81
|
+
tilt (~> 1.1, != 1.3.0)
|
82
|
+
sqlite3 (1.3.5)
|
83
|
+
thor (0.14.6)
|
84
|
+
tilt (1.3.3)
|
85
|
+
treetop (1.4.10)
|
86
|
+
polyglot
|
87
|
+
polyglot (>= 0.3.1)
|
88
|
+
tzinfo (0.3.31)
|
89
|
+
|
90
|
+
PLATFORMS
|
91
|
+
ruby
|
92
|
+
|
93
|
+
DEPENDENCIES
|
94
|
+
bundler (~> 1.0.0)
|
95
|
+
jeweler (~> 1.6.4)
|
96
|
+
minitest
|
97
|
+
rails (>= 3.0)
|
98
|
+
sqlite3
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2012 Francesc Pla
|
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.rdoc
ADDED
@@ -0,0 +1,163 @@
|
|
1
|
+
= rails-translate-routes
|
2
|
+
|
3
|
+
Rails 3.x routes translations based on Raul's translate_routes (https://github.com/raul/translate_routes).
|
4
|
+
|
5
|
+
It's currently a stripped down version of the forked gem, adding some bugfixes for rails 3.1 and features I needed for my project. See doc below to see what it can do.
|
6
|
+
|
7
|
+
translate_routes & i18n_routes seems to be unmaintained projects so I decided to start a fork of the first one for my own projects, I can't promise high dedication but I'll to maintain it for my own use and take care all patches & bugs submitted, help is welcome!
|
8
|
+
|
9
|
+
== Installation
|
10
|
+
|
11
|
+
Add it to your Gemfile:
|
12
|
+
|
13
|
+
gem 'rails-translate-routes'
|
14
|
+
|
15
|
+
== Basic usage
|
16
|
+
|
17
|
+
Let's imagine you have a SampleApp with products and a contact page. A typical 'routes.rb' file should look like:
|
18
|
+
|
19
|
+
SampleApp::Application.routes.draw do
|
20
|
+
resources :products
|
21
|
+
match 'contact', :to => 'pages#contact'
|
22
|
+
end
|
23
|
+
|
24
|
+
Running 'rake routes' we have:
|
25
|
+
|
26
|
+
products GET /products(.:format) {:action=>"index", :controller=>"products"}
|
27
|
+
POST /products(.:format) {:action=>"create", :controller=>"products"}
|
28
|
+
new_product GET /products/new(.:format) {:action=>"new", :controller=>"products"}
|
29
|
+
edit_product GET /products/:id/edit(.:format) {:action=>"edit", :controller=>"products"}
|
30
|
+
product GET /products/:id(.:format) {:action=>"show", :controller=>"products"}
|
31
|
+
PUT /products/:id(.:format) {:action=>"update", :controller=>"products"}
|
32
|
+
DELETE /products/:id(.:format) {:action=>"destroy", :controller=>"products"}
|
33
|
+
contact /contact(.:format) {:action=>"contact", :controller=>"pages"}
|
34
|
+
|
35
|
+
We want to have them in two languages english and spanish, to accomplish this with rails-translate-routes:
|
36
|
+
|
37
|
+
1) We have to activate the translations appending this line to the end of 'routes.rb'
|
38
|
+
|
39
|
+
ActionDispatch::Routing::Translator.translate_from_file('config/locales/routes.yml')
|
40
|
+
|
41
|
+
2) Now we can write translations on a standard YAML file (e.g: in config/locales/routes.yml), including all the locales and their translations:
|
42
|
+
|
43
|
+
en:
|
44
|
+
# you can leave empty locales, for example the default one
|
45
|
+
es:
|
46
|
+
products: productos
|
47
|
+
contact: contacto
|
48
|
+
new: crear
|
49
|
+
|
50
|
+
3) Include this filter in your ApplicationController:
|
51
|
+
|
52
|
+
before_filter :set_locale_from_url
|
53
|
+
|
54
|
+
Also remember to include language detection to your app, a simple example of an ApplicationController
|
55
|
+
|
56
|
+
class ApplicationController < ActionController::Base
|
57
|
+
protect_from_forgery
|
58
|
+
|
59
|
+
before_filter :set_locale
|
60
|
+
before_filter :set_locale_from_url
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def set_locale
|
65
|
+
I18n.locale = params[:locale] || ((lang = request.env['HTTP_ACCEPT_LANGUAGE']) && lang[/^[a-z]{2}/])
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
And that's it! Now if we execute 'rake routes':
|
70
|
+
|
71
|
+
products_en GET /products(.:format) {:action=>"index", :controller=>"products"}
|
72
|
+
products_es GET /es/productos(.:format) {:action=>"index", :controller=>"products"}
|
73
|
+
POST /products(.:format) {:action=>"create", :controller=>"products"}
|
74
|
+
POST /es/productos(.:format) {:action=>"create", :controller=>"products"}
|
75
|
+
new_product_en GET /products/new(.:format) {:action=>"new", :controller=>"products"}
|
76
|
+
new_product_es GET /es/productos/new(.:format) {:action=>"new", :controller=>"products"}
|
77
|
+
edit_product_en GET /products/:id/edit(.:format) {:action=>"edit", :controller=>"products"}
|
78
|
+
edit_product_es GET /es/productos/:id/edit(.:format) {:action=>"edit", :controller=>"products"}
|
79
|
+
product_en GET /products/:id(.:format) {:action=>"show", :controller=>"products"}
|
80
|
+
product_es GET /es/productos/:id(.:format) {:action=>"show", :controller=>"products"}
|
81
|
+
PUT /products/:id(.:format) {:action=>"update", :controller=>"products"}
|
82
|
+
PUT /es/productos/:id(.:format) {:action=>"update", :controller=>"products"}
|
83
|
+
DELETE /products/:id(.:format) {:action=>"destroy", :controller=>"products"}
|
84
|
+
DELETE /es/productos/:id(.:format) {:action=>"destroy", :controller=>"products"}
|
85
|
+
contact_en /contact(.:format) {:action=>"contact", :controller=>"pages"}
|
86
|
+
contact_es /es/contacto(.:format) {:action=>"contact", :controller=>"pages"}
|
87
|
+
|
88
|
+
|
89
|
+
The application recognizes the different routes and sets the 'I18n.locale' value in controllers, but what about the routes generation? As you can see on the previous rake routes execution, the 'contact_es_path' and 'contact_en_path' routing helpers have been generated and are available in your controllers and views. Additionally, a 'contact_path' helper has been generated, which generates the routes according to the current request's locale. 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.
|
90
|
+
|
91
|
+
<b>URL structure options</b>
|
92
|
+
|
93
|
+
As you can see by default it generates the following url structure:
|
94
|
+
|
95
|
+
/
|
96
|
+
/es
|
97
|
+
/products/
|
98
|
+
/es/productos/
|
99
|
+
/contact/
|
100
|
+
/es/contactos/
|
101
|
+
|
102
|
+
In case you want the default languages to be scoped resulting in the following structure:
|
103
|
+
|
104
|
+
/en
|
105
|
+
/es
|
106
|
+
/en/products/
|
107
|
+
/es/productos/
|
108
|
+
/en/contact/
|
109
|
+
/es/contactos/
|
110
|
+
|
111
|
+
You can specify the following option:
|
112
|
+
|
113
|
+
ActionDispatch::Routing::Translator.translate_from_file('config/locales/routes.yml', { :prefix_on_default_locale => true })
|
114
|
+
|
115
|
+
If you use the 'prefix_on_default_locale' you will have to make the proper redirect on your root controller from http://www.sampleapp.com/ to http://www.sampleapp.com/en or http://www.sampleapp.com/es rails-translate-routes adds an extra unstranslated root path:
|
116
|
+
|
117
|
+
root_en /en {:controller=>"pages", :action=>"index"}
|
118
|
+
root_es /es {:controller=>"pages", :action=>"index"}
|
119
|
+
root / {:controller=>"pages", :action=>"index"}
|
120
|
+
|
121
|
+
A simple example of a redirection to user locale in index method:
|
122
|
+
|
123
|
+
def index
|
124
|
+
unless params[ :locale]
|
125
|
+
# it takes I18n.locale from the previous example set_locale as before_filter in application controller
|
126
|
+
redirect_to eval("root_#{I18n.locale}_path
|
127
|
+
end
|
128
|
+
|
129
|
+
# rest of the controller logic ...
|
130
|
+
end
|
131
|
+
|
132
|
+
== TODO
|
133
|
+
|
134
|
+
Help is welcome ;)
|
135
|
+
|
136
|
+
* make basic testing
|
137
|
+
* support for rails 3.2
|
138
|
+
|
139
|
+
== Credits
|
140
|
+
|
141
|
+
Thanks to:
|
142
|
+
|
143
|
+
* Main development of forked gem:
|
144
|
+
* Raul Murciano (http://github.com/raul)
|
145
|
+
|
146
|
+
* Contributors of forked gem:
|
147
|
+
* Aitor Garay-Romero (http://github.com/aitorgr)
|
148
|
+
* Christian Hølmer (http://github.com/hoelmer)
|
149
|
+
* Nico Ritsche (https://github.com/ncri)
|
150
|
+
* Cedric Darricau (http://github.com/devsigner)
|
151
|
+
* Olivier Gonzalez (http://github.com/gonzoyumo)
|
152
|
+
* Kristian Mandrup (http://github.com/kristianmandrup)
|
153
|
+
* Pieter Visser (http://github.com/pietervisser)
|
154
|
+
* Marian Theisen (http://github.com/cice)
|
155
|
+
* Enric Lluelles (http://github.com/enriclluelles)
|
156
|
+
* Jaime Iniesta (http://github.com/jaimeiniesta)
|
157
|
+
|
158
|
+
== Similar projects
|
159
|
+
|
160
|
+
There are other two projects for translating routes in Rails (which I know of), both of them are unfortunately unmaintained but you may want to check them out if you use Rails 2 or have different needs.
|
161
|
+
|
162
|
+
* translate_routes (https://github.com/raul/translate_routes)
|
163
|
+
* i18n_routing (https://github.com/kwi/i18n_routing)
|
data/Rakefile
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'bundler'
|
5
|
+
begin
|
6
|
+
Bundler.setup(:default, :development)
|
7
|
+
rescue Bundler::BundlerError => e
|
8
|
+
$stderr.puts e.message
|
9
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
10
|
+
exit e.status_code
|
11
|
+
end
|
12
|
+
require 'rake'
|
13
|
+
|
14
|
+
require 'jeweler'
|
15
|
+
Jeweler::Tasks.new do |gem|
|
16
|
+
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
|
17
|
+
gem.name = "rails-translate-routes"
|
18
|
+
gem.homepage = "http://github.com/francesc/rails-translate-routes"
|
19
|
+
gem.license = "MIT"
|
20
|
+
gem.summary = %Q{Simple gem to translate routes in Rails 3.x}
|
21
|
+
gem.description = %Q{Simple gem to translate routes in Rails 3.x based on translate_routes}
|
22
|
+
gem.email = "francesc@francesc.net"
|
23
|
+
gem.authors = ["Francesc Pla"]
|
24
|
+
# dependencies defined in Gemfile
|
25
|
+
end
|
26
|
+
Jeweler::RubygemsDotOrgTasks.new
|
27
|
+
|
28
|
+
require 'rake/testtask'
|
29
|
+
Rake::TestTask.new(:test) do |test|
|
30
|
+
test.libs << 'lib' << 'test'
|
31
|
+
test.pattern = 'test/**/test_*.rb'
|
32
|
+
test.verbose = true
|
33
|
+
end
|
34
|
+
|
35
|
+
task :default => :test
|
36
|
+
|
37
|
+
require 'rake/rdoctask'
|
38
|
+
Rake::RDocTask.new do |rdoc|
|
39
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
40
|
+
|
41
|
+
rdoc.rdoc_dir = 'rdoc'
|
42
|
+
rdoc.title = "rails-translate-routes #{version}"
|
43
|
+
rdoc.rdoc_files.include('README*')
|
44
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
45
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.1
|
@@ -0,0 +1,332 @@
|
|
1
|
+
# coding: UTF-8
|
2
|
+
|
3
|
+
# This class knows nothing
|
4
|
+
# about Rails.root or Rails.application.routes, and therefor is easier to
|
5
|
+
# test without an Rails App.
|
6
|
+
class RailsTranslateRoutes
|
7
|
+
TRANSLATABLE_SEGMENT = /^(\w+)(\()?/.freeze
|
8
|
+
LOCALE_PARAM_KEY = :locale.freeze
|
9
|
+
ROUTE_HELPER_CONTAINER = [
|
10
|
+
ActionController::Base,
|
11
|
+
ActionView::Base,
|
12
|
+
ActionMailer::Base,
|
13
|
+
ActionDispatch::Routing::UrlFor
|
14
|
+
].freeze
|
15
|
+
|
16
|
+
# Attributes
|
17
|
+
|
18
|
+
attr_accessor :dictionary
|
19
|
+
|
20
|
+
def available_locales
|
21
|
+
@available_locales ||= I18n.available_locales.map(&:to_s)
|
22
|
+
end
|
23
|
+
|
24
|
+
def available_locales= locales
|
25
|
+
@available_locales = locales.map(&:to_s)
|
26
|
+
end
|
27
|
+
|
28
|
+
def default_locale
|
29
|
+
@default_locale ||= I18n.default_locale.to_s
|
30
|
+
end
|
31
|
+
|
32
|
+
def default_locale= locale
|
33
|
+
@default_locale = locale.to_s
|
34
|
+
end
|
35
|
+
|
36
|
+
def default_locale? locale
|
37
|
+
default_locale == locale.to_s
|
38
|
+
end
|
39
|
+
|
40
|
+
def prefix_on_default_locale
|
41
|
+
@prefix_on_default_locale ||= I18n.default_locale.to_s
|
42
|
+
end
|
43
|
+
|
44
|
+
def prefix_on_default_locale= locale
|
45
|
+
@prefix_on_default_locale = locale.to_s
|
46
|
+
end
|
47
|
+
|
48
|
+
class << self
|
49
|
+
# Default locale suffix generator
|
50
|
+
def locale_suffix locale
|
51
|
+
locale.to_s.underscore
|
52
|
+
end
|
53
|
+
|
54
|
+
# Creates a RailsTranslateRoutes instance, using I18n dictionaries of
|
55
|
+
# your app
|
56
|
+
def init_with_i18n *wanted_locales
|
57
|
+
new.tap do |t|
|
58
|
+
t.init_i18n_dictionary *wanted_locales
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# Creates a RailsTranslateRoutes instance and evaluates given block
|
63
|
+
# with an empty dictionary
|
64
|
+
def init_with_yield &block
|
65
|
+
new.tap do |t|
|
66
|
+
t.yield_dictionary &block
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# Creates a RailsTranslateRoutes instance and reads the translations
|
71
|
+
# from a specified file
|
72
|
+
def init_from_file file_path
|
73
|
+
new.tap do |t|
|
74
|
+
t.load_dictionary_from_file file_path
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
module DictionaryManagement
|
80
|
+
# Resets dictionary and yields the block wich can be used to manually fill the dictionary
|
81
|
+
# with translations e.g.
|
82
|
+
# route_translator = RailsTranslateRoutes.new
|
83
|
+
# route_translator.yield_dictionary do |dict|
|
84
|
+
# dict['en'] = { 'people' => 'people' }
|
85
|
+
# dict['de'] = { 'people' => 'personen' }
|
86
|
+
# end
|
87
|
+
def yield_dictionary &block
|
88
|
+
reset_dictionary
|
89
|
+
yield @dictionary
|
90
|
+
set_available_locales_from_dictionary
|
91
|
+
end
|
92
|
+
|
93
|
+
# Resets dictionary and loads translations from specified file
|
94
|
+
# config/locales/routes.yml:
|
95
|
+
# en:
|
96
|
+
# people: people
|
97
|
+
# de:
|
98
|
+
# people: personen
|
99
|
+
# routes.rb:
|
100
|
+
# ... your routes ...
|
101
|
+
# ActionDispatch::Routing::Translator.translate_from_file
|
102
|
+
# or, to specify a custom file
|
103
|
+
# ActionDispatch::Routing::Translator.translate_from_file 'config', 'locales', 'routes.yml'
|
104
|
+
def load_dictionary_from_file file_path
|
105
|
+
reset_dictionary
|
106
|
+
add_dictionary_from_file file_path
|
107
|
+
end
|
108
|
+
|
109
|
+
# Add translations from another file to the dictionary.
|
110
|
+
def add_dictionary_from_file file_path
|
111
|
+
yaml = YAML.load_file(file_path)
|
112
|
+
yaml.each_pair do |locale, translations|
|
113
|
+
merge_translations locale, translations
|
114
|
+
end
|
115
|
+
set_available_locales_from_dictionary
|
116
|
+
end
|
117
|
+
|
118
|
+
# Merge translations for a specified locale into the dictionary
|
119
|
+
def merge_translations locale, translations
|
120
|
+
locale = locale.to_s
|
121
|
+
if translations.blank?
|
122
|
+
@dictionary[locale] ||= {}
|
123
|
+
return
|
124
|
+
end
|
125
|
+
@dictionary[locale] = (@dictionary[locale] || {}).merge(translations)
|
126
|
+
end
|
127
|
+
|
128
|
+
# Init dictionary to use I18n to translate route parts. Creates
|
129
|
+
# a hash with a block for each locale to lookup keys in I18n dynamically.
|
130
|
+
def init_i18n_dictionary *wanted_locales
|
131
|
+
wanted_locales = available_locales if wanted_locales.blank?
|
132
|
+
reset_dictionary
|
133
|
+
wanted_locales.each do |locale|
|
134
|
+
@dictionary[locale] = Hash.new do |hsh, key|
|
135
|
+
hsh[key] = I18n.translate key, :locale => locale #DISCUSS: caching or no caching (store key and translation in dictionary?)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
@available_locales = @dictionary.keys.map &:to_s
|
139
|
+
end
|
140
|
+
|
141
|
+
private
|
142
|
+
def set_available_locales_from_dictionary
|
143
|
+
@available_locales = @dictionary.keys.map &:to_s
|
144
|
+
end
|
145
|
+
|
146
|
+
# Resets dictionary
|
147
|
+
def reset_dictionary
|
148
|
+
@dictionary = { default_locale => {}}
|
149
|
+
end
|
150
|
+
end
|
151
|
+
include DictionaryManagement
|
152
|
+
|
153
|
+
module Translator
|
154
|
+
# Translate a specific RouteSet, usually Rails.application.routes, but can
|
155
|
+
# be a RouteSet of a gem, plugin/engine etc.
|
156
|
+
def translate route_set
|
157
|
+
Rails.logger.info "Translating routes (default locale: #{default_locale})" if defined?(Rails) && defined?(Rails.logger)
|
158
|
+
|
159
|
+
# save original routes and clear route set
|
160
|
+
original_routes = route_set.routes.dup # Array [routeA, routeB, ...]
|
161
|
+
original_routes.delete_if{|r| r.path == '/assets'}
|
162
|
+
original_named_routes = route_set.named_routes.routes.dup # Hash {:name => :route}
|
163
|
+
|
164
|
+
reset_route_set route_set
|
165
|
+
|
166
|
+
original_routes.each do |original_route|
|
167
|
+
translations_for(original_route).each do |translated_route_args|
|
168
|
+
route_set.add_route *translated_route_args
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
original_named_routes.each_key do |route_name|
|
173
|
+
route_set.named_routes.helpers.concat add_untranslated_helpers_to_controllers_and_views(route_name)
|
174
|
+
end
|
175
|
+
|
176
|
+
if root_route = original_named_routes[:root]
|
177
|
+
add_root_route root_route, route_set
|
178
|
+
end
|
179
|
+
|
180
|
+
end
|
181
|
+
|
182
|
+
# Add unmodified root route to route_set
|
183
|
+
def add_root_route root_route, route_set
|
184
|
+
if @prefix_on_default_locale
|
185
|
+
root_route.conditions[:path_info] = root_route.conditions[:path_info].dup
|
186
|
+
route_set.set.add_route *root_route
|
187
|
+
route_set.named_routes[root_route.name] = root_route
|
188
|
+
route_set.routes << root_route
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
# Add standard route helpers for default locale e.g.
|
193
|
+
# I18n.locale = :de
|
194
|
+
# people_path -> people_de_path
|
195
|
+
# I18n.locale = :fr
|
196
|
+
# people_path -> people_fr_path
|
197
|
+
def add_untranslated_helpers_to_controllers_and_views old_name
|
198
|
+
['path', 'url'].map do |suffix|
|
199
|
+
new_helper_name = "#{old_name}_#{suffix}"
|
200
|
+
|
201
|
+
ROUTE_HELPER_CONTAINER.each do |helper_container|
|
202
|
+
helper_container.send :define_method, new_helper_name do |*args|
|
203
|
+
send "#{old_name}_#{locale_suffix(I18n.locale)}_#{suffix}", *args
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
new_helper_name.to_sym
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
# Generate translations for a single route for all available locales
|
212
|
+
def translations_for route
|
213
|
+
available_locales.map do |locale|
|
214
|
+
translate_route route, locale
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
# Generate translation for a single route for one locale
|
219
|
+
def translate_route route, locale
|
220
|
+
conditions = { :path_info => translate_path(route.path, locale) }
|
221
|
+
conditions[:request_method] = parse_request_methods route.conditions[:request_method] if route.conditions.has_key? :request_method
|
222
|
+
requirements = route.requirements.merge LOCALE_PARAM_KEY => locale
|
223
|
+
defaults = route.defaults.merge LOCALE_PARAM_KEY => locale
|
224
|
+
new_name = "#{route.name}_#{locale_suffix(locale)}" if route.name
|
225
|
+
|
226
|
+
[route.app, conditions, requirements, defaults, new_name]
|
227
|
+
end
|
228
|
+
|
229
|
+
# Add prefix for all non-default locales
|
230
|
+
def add_prefix? locale
|
231
|
+
if !default_locale?(locale) || @prefix_on_default_locale
|
232
|
+
true
|
233
|
+
else
|
234
|
+
false
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
# Translates a path and adds the locale prefix.
|
239
|
+
def translate_path path, locale
|
240
|
+
final_optional_segments = path.match(/(\(.+\))$/)[1] rescue nil # i.e: (.:format)
|
241
|
+
path_without_optional_segments = final_optional_segments ? path.gsub(final_optional_segments,'') : path
|
242
|
+
path_segments = path_without_optional_segments.split("/")
|
243
|
+
new_path = path_segments.map{ |seg| translate_path_segment(seg, locale) }.join('/')
|
244
|
+
new_path = "/#{locale.downcase}#{new_path}" if add_prefix?(locale)
|
245
|
+
new_path = '/' if new_path.blank?
|
246
|
+
final_optional_segments ? new_path + final_optional_segments : new_path
|
247
|
+
end
|
248
|
+
|
249
|
+
# Tries to translate a single path segment. If the path segment
|
250
|
+
# contains sth. like a optional format "people(.:format)", only
|
251
|
+
# "people" will be translated, if there is no translation, the path
|
252
|
+
# segment is blank or begins with a ":" (param key), the segment
|
253
|
+
# is returned untouched
|
254
|
+
def translate_path_segment segment, locale
|
255
|
+
return segment if segment.blank? or segment.starts_with?(":")
|
256
|
+
|
257
|
+
match = TRANSLATABLE_SEGMENT.match(segment)[1] rescue nil
|
258
|
+
|
259
|
+
(translate_string(match, locale) || segment).downcase
|
260
|
+
end
|
261
|
+
|
262
|
+
def translate_string str, locale
|
263
|
+
@dictionary[locale.to_s][str.to_s]
|
264
|
+
end
|
265
|
+
|
266
|
+
private
|
267
|
+
def reset_route_set route_set
|
268
|
+
route_set.clear!
|
269
|
+
remove_all_methods_in route_set.named_routes.module
|
270
|
+
end
|
271
|
+
|
272
|
+
def remove_all_methods_in mod
|
273
|
+
mod.instance_methods.each do |method|
|
274
|
+
mod.send :remove_method, method
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
# expects methods regexp to be in a format: /^GET$/ or /^GET|POST$/ and returns array ["GET", "POST"]
|
279
|
+
def parse_request_methods methods_regexp
|
280
|
+
methods_regexp.source.gsub(/\^([a-zA-Z\|]+)\$/, "\\1").split("|")
|
281
|
+
end
|
282
|
+
end
|
283
|
+
include Translator
|
284
|
+
|
285
|
+
def locale_suffix locale
|
286
|
+
self.class.locale_suffix locale
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
290
|
+
# Adapter for Rails 3 Apps
|
291
|
+
module ActionDispatch
|
292
|
+
module Routing
|
293
|
+
module Translator
|
294
|
+
class << self
|
295
|
+
def translate &block
|
296
|
+
RailsTranslateRoutes.init_with_yield(&block).translate Rails.application.routes
|
297
|
+
end
|
298
|
+
|
299
|
+
def translate_from_file(file_path, options = {})
|
300
|
+
file_path = %w(config locales routes.yml) if file_path.blank?
|
301
|
+
r = RailsTranslateRoutes.init_from_file(File.join(Rails.root, file_path))
|
302
|
+
r.prefix_on_default_locale = true if options && options[:prefix_on_default_locale] == true
|
303
|
+
r.translate Rails.application.routes
|
304
|
+
end
|
305
|
+
|
306
|
+
def i18n *locales
|
307
|
+
RailsTranslateRoutes.init_with_i18n(*locales).translate Rails.application.routes
|
308
|
+
end
|
309
|
+
end
|
310
|
+
end
|
311
|
+
end
|
312
|
+
end
|
313
|
+
|
314
|
+
# Add set_locale_from_url to controllers
|
315
|
+
ActionController::Base.class_eval do
|
316
|
+
private
|
317
|
+
# called by before_filter
|
318
|
+
def set_locale_from_url
|
319
|
+
I18n.locale = params[RailsTranslateRoutes::LOCALE_PARAM_KEY]
|
320
|
+
default_url_options = {RailsTranslateRoutes::LOCALE_PARAM_KEY => I18n.locale}
|
321
|
+
end
|
322
|
+
end
|
323
|
+
|
324
|
+
# Add locale_suffix to controllers, views and mailers
|
325
|
+
RailsTranslateRoutes::ROUTE_HELPER_CONTAINER.each do |klass|
|
326
|
+
klass.class_eval do
|
327
|
+
private
|
328
|
+
def locale_suffix locale
|
329
|
+
RailsTranslateRoutes.locale_suffix locale
|
330
|
+
end
|
331
|
+
end
|
332
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = "rails-translate-routes"
|
8
|
+
s.version = "0.0.1"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Francesc Pla"]
|
12
|
+
s.date = "2012-01-04"
|
13
|
+
s.description = "Simple gem to translate routes in Rails 3.x based on translate_routes"
|
14
|
+
s.email = "francesc@francesc.net"
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE.txt",
|
17
|
+
"README.rdoc"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
".document",
|
21
|
+
"Gemfile",
|
22
|
+
"Gemfile.lock",
|
23
|
+
"LICENSE.txt",
|
24
|
+
"README.rdoc",
|
25
|
+
"Rakefile",
|
26
|
+
"VERSION",
|
27
|
+
"lib/rails-translate-routes.rb",
|
28
|
+
"rails-translate-routes.gemspec",
|
29
|
+
"test/helper.rb",
|
30
|
+
"test/test_rails-translate-routes.rb"
|
31
|
+
]
|
32
|
+
s.homepage = "http://github.com/francesc/rails-translate-routes"
|
33
|
+
s.licenses = ["MIT"]
|
34
|
+
s.require_paths = ["lib"]
|
35
|
+
s.rubygems_version = "1.8.10"
|
36
|
+
s.summary = "Simple gem to translate routes in Rails 3.x"
|
37
|
+
|
38
|
+
if s.respond_to? :specification_version then
|
39
|
+
s.specification_version = 3
|
40
|
+
|
41
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
42
|
+
s.add_runtime_dependency(%q<rails>, [">= 3.0"])
|
43
|
+
s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
|
44
|
+
s.add_development_dependency(%q<jeweler>, ["~> 1.6.4"])
|
45
|
+
s.add_development_dependency(%q<sqlite3>, [">= 0"])
|
46
|
+
s.add_development_dependency(%q<minitest>, [">= 0"])
|
47
|
+
else
|
48
|
+
s.add_dependency(%q<rails>, [">= 3.0"])
|
49
|
+
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
50
|
+
s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
|
51
|
+
s.add_dependency(%q<sqlite3>, [">= 0"])
|
52
|
+
s.add_dependency(%q<minitest>, [">= 0"])
|
53
|
+
end
|
54
|
+
else
|
55
|
+
s.add_dependency(%q<rails>, [">= 3.0"])
|
56
|
+
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
57
|
+
s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
|
58
|
+
s.add_dependency(%q<sqlite3>, [">= 0"])
|
59
|
+
s.add_dependency(%q<minitest>, [">= 0"])
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
data/test/helper.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
# coding: UTF-8
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'bundler'
|
5
|
+
begin
|
6
|
+
Bundler.setup(:default, :development)
|
7
|
+
rescue Bundler::BundlerError => e
|
8
|
+
$stderr.puts e.message
|
9
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
10
|
+
exit e.status_code
|
11
|
+
end
|
12
|
+
|
13
|
+
require 'minitest/autorun'
|
14
|
+
require 'active_record'
|
15
|
+
|
16
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
17
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
18
|
+
require 'rails-translate-routes'
|
metadata
ADDED
@@ -0,0 +1,116 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rails-translate-routes
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Francesc Pla
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-01-04 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rails
|
16
|
+
requirement: &70118983572120 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '3.0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *70118983572120
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: bundler
|
27
|
+
requirement: &70118983571560 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ~>
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 1.0.0
|
33
|
+
type: :development
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *70118983571560
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: jeweler
|
38
|
+
requirement: &70118983570720 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ~>
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 1.6.4
|
44
|
+
type: :development
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *70118983570720
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: sqlite3
|
49
|
+
requirement: &70118983570020 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
type: :development
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *70118983570020
|
58
|
+
- !ruby/object:Gem::Dependency
|
59
|
+
name: minitest
|
60
|
+
requirement: &70118983592020 !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ! '>='
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '0'
|
66
|
+
type: :development
|
67
|
+
prerelease: false
|
68
|
+
version_requirements: *70118983592020
|
69
|
+
description: Simple gem to translate routes in Rails 3.x based on translate_routes
|
70
|
+
email: francesc@francesc.net
|
71
|
+
executables: []
|
72
|
+
extensions: []
|
73
|
+
extra_rdoc_files:
|
74
|
+
- LICENSE.txt
|
75
|
+
- README.rdoc
|
76
|
+
files:
|
77
|
+
- .document
|
78
|
+
- Gemfile
|
79
|
+
- Gemfile.lock
|
80
|
+
- LICENSE.txt
|
81
|
+
- README.rdoc
|
82
|
+
- Rakefile
|
83
|
+
- VERSION
|
84
|
+
- lib/rails-translate-routes.rb
|
85
|
+
- rails-translate-routes.gemspec
|
86
|
+
- test/helper.rb
|
87
|
+
- test/test_rails-translate-routes.rb
|
88
|
+
homepage: http://github.com/francesc/rails-translate-routes
|
89
|
+
licenses:
|
90
|
+
- MIT
|
91
|
+
post_install_message:
|
92
|
+
rdoc_options: []
|
93
|
+
require_paths:
|
94
|
+
- lib
|
95
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
96
|
+
none: false
|
97
|
+
requirements:
|
98
|
+
- - ! '>='
|
99
|
+
- !ruby/object:Gem::Version
|
100
|
+
version: '0'
|
101
|
+
segments:
|
102
|
+
- 0
|
103
|
+
hash: -1794154583192669933
|
104
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
requirements: []
|
111
|
+
rubyforge_project:
|
112
|
+
rubygems_version: 1.8.10
|
113
|
+
signing_key:
|
114
|
+
specification_version: 3
|
115
|
+
summary: Simple gem to translate routes in Rails 3.x
|
116
|
+
test_files: []
|