Skip to content

jbox-web/route_translator

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

65 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

RouteTranslator

GitHub license GitHub release CI

RouteTranslator is a gem to allow you to manage the translations of your Rails application routes with a simple dictionary format.

It started as a rewrite of the awesome route_translator plugin by Geremia Taglialatela to keep support of Rails engines.

Right now it works with Rails 5.2 and Rails 6.x.

Installation

Put this in your Gemfile :

git_source(:github){ |repo_name| "https://github.com/#{repo_name}.git" }

gem 'route_translator', github: 'jbox-web/route_translator', tag: '1.0.0'

then run bundle install.

Usage

  1. First configure RouteTranslator in Rails application
module Dummy
  class Application < Rails::Application
    # Extend application class to add .add_route_translator_for method
    extend RouteTranslator::Railtie::Localized

    # Declare our locales as usual
    config.i18n.available_locales = %i[fr en es pt]
    config.i18n.default_locale    = :fr
    config.i18n.fallbacks         = [:fr, { en: %i[en fr], es: %i[es fr], pt: %i[pt es fr] }]

    # Configure RouteTranslator
    add_route_translator_for(:main_site, {
      default_locale:    :fr,
      available_locales: %i[fr es pt en],
    })
  end
end

Here :main_site is just an ID to store RouteTranslator config for the current Rails application.

It's mainly useful when you have Rails engines in your application (see below), but still, you have to give one.

  1. Configure your ApplicationController
class ApplicationController < ActionController::Base
  # Prevent CSRF attacks by raising an exception.
  # For APIs, you may want to use :null_session instead.
  protect_from_forgery with: :exception

  # Configure RouteTranslator
  localized :main_site
end
  1. Localize your routes
Rails.application.routes.draw do
  root 'welcome#index'

  resources :posts

  localized(:main_site) do
    get 'about', to: 'pages#about', as: :about
  end

end
  1. And add the translations to your locale files, for example :
en:
  routes:
    about: about

fr:
  routes:
    about: a-propos
  1. Your routes are now translated! Here's the output of your bin/rails routes :

Before :

    Prefix Verb   URI Pattern                 Controller#Action
      root GET    /                           welcome#index
     posts GET    /posts(.:format)            posts#index
           POST   /posts(.:format)            posts#create
  new_post GET    /posts/new(.:format)        posts#new
 edit_post GET    /posts/:id/edit(.:format)   posts#edit
      post GET    /posts/:id(.:format)        posts#show
           PATCH  /posts/:id(.:format)        posts#update
           PUT    /posts/:id(.:format)        posts#update
           DELETE /posts/:id(.:format)        posts#destroy
     about GET    /about(.:format)            pages#about

After :

    Prefix Verb   URI Pattern                 Controller#Action
      root GET    /                           welcome#index
     posts GET    /posts(.:format)            posts#index
           POST   /posts(.:format)            posts#create
  new_post GET    /posts/new(.:format)        posts#new
 edit_post GET    /posts/:id/edit(.:format)   posts#edit
      post GET    /posts/:id(.:format)        posts#show
           PATCH  /posts/:id(.:format)        posts#update
           PUT    /posts/:id(.:format)        posts#update
           DELETE /posts/:id(.:format)        posts#destroy
  about_fr GET    /a-propos(.:format)         pages#about {:locale=>"fr"}
  about_es GET    /es/sobre(.:format)         pages#about {:locale=>"es"}
  about_pt GET    /pt/quem-e(.:format)        pages#about {:locale=>"pt"}
  about_en GET    /en/about(.:format)         pages#about {:locale=>"en"}

Note that only the routes inside a localized block are translated.

Options

Accepted options for add_route_translator_for :

Options Default value Description
:default_locale I18n.default_locale RouteTranslator adds the locale to all generated route paths, except for the default locale.
:available_locales I18n.available_locales Limits the locales for which URLs should be generated for. Accepts an array of strings or symbols.
:locale_param_key :locale The param key used to set the locale to the newly generated routes.
:disable_fallback false Creates routes only for locales that have translations. For example, if we have /examples and a translation is not provided for es, the route helper of examples_es will not be created.

I18n

If you want to set I18n.locale from the url parameter locale, add the following line in your ApplicationController :

around_action :set_locale_from_params

Note : you might be tempted to use before_action instead of around_action : just don't. That could lead to thread-related issues.

If you use engines don't forget to add it in your engine ApplicationController (See: rails/rails#34356 (comment))

With Rails engines

It's the same procedure that applies for Rails engine :

  1. First configure RouteTranslator in your Rails engine
module Bar
  class Engine < ::Rails::Engine
    isolate_namespace Bar
    # Extend application class to add .add_route_translator_for method
    extend RouteTranslator::Railtie::Localized

    # Configure RouteTranslator
    add_route_translator_for(:bar_engine, {
      default_locale:    :es,
      available_locales: %i[es pt en],
    })
  end
end
  1. Configure your Rails engine ApplicationController
module Bar
  class ApplicationController < ActionController::Base
    layout 'bar/application'

    # Configure RouteTranslator
    localized :bar_engine
  end
end
  1. Localize your routes
Bar::Engine.routes.draw do
  root 'welcome#index'

  localized(:bar_engine) do
    get 'about',   to: 'pages#about', as: :about
    get 'unnamed', to: 'pages#unnamed'

    get 'people.:format', to: 'people#index'

    resources :products
  end
end
  1. Mount your engine in Rails application :
Rails.application.routes.draw do
  root 'welcome#index'

  localized(:main_site) do
    get 'about', to: 'pages#about', as: :about
  end

  mount Bar::Engine, at: '/bar', as: 'bar_site'
end

Namespaces

You can translate a namespace route by either its name or path option :

  1. Wrap the namespaces that you want to translate inside a localized block:
Rails.application.routes.draw do
  localized(:main_site) do
    namespace :admin do
      resources :cars, only: :index
    end

    namespace :sold_cars, path: :sold do
      resources :cars, only: :index
    end
  end
end
  1. And add the translations to your locale files, for example:
es:
  routes:
    admin: administrador
    cars: coches
    new: nuevo
    sold: vendidos

fr:
  routes:
    admin: administrateur
    cars: voitures
    new: nouveau
    sold: vendues
  1. Your namespaces are translated! Here's the output of your bin/rails routes :
             Prefix Verb URI Pattern                           Controller#Action
      admin_cars_fr GET  /fr/administrateur/voitures(.:format) admin/cars#index {:locale=>"fr"}
      admin_cars_es GET  /es/administrador/coches(.:format)    admin/cars#index {:locale=>"es"}
      admin_cars_en GET  /admin/cars(.:format)                 admin/cars#index {:locale=>"en"}
  sold_cars_cars_fr GET  /fr/vendues/voitures(.:format)        sold_cars/cars#index {:locale=>"fr"}
  sold_cars_cars_es GET  /es/vendidos/coches(.:format)         sold_cars/cars#index {:locale=>"es"}
  sold_cars_cars_en GET  /sold/cars(.:format)                  sold_cars/cars#index {:locale=>"en"}

Inflections

At the moment inflections are not supported, but you can use the following workaround :

localized(:main_site) do
  resources :categories, path_names: { new: 'new_category' }
end
en:
  routes:
    category: category
    new_category: new

es:
  routes:
    category: categoria
    new_category: nueva
          Prefix Verb   URI Pattern                       Controller#Action
   categories_es GET    /es/categorias(.:format)          categories#index {:locale=>"es"}
   categories_en GET    /categories(.:format)             categories#index {:locale=>"en"}
                 POST   /es/categorias(.:format)          categories#create {:locale=>"es"}
                 POST   /categories(.:format)             categories#create {:locale=>"en"}
 new_category_es GET    /es/categorias/nueva(.:format)    categories#new {:locale=>"es"}
 new_category_en GET    /categories/new(.:format)         categories#new {:locale=>"en"}
edit_category_es GET    /es/categorias/:id/edit(.:format) categories#edit {:locale=>"es"}
edit_category_en GET    /categories/:id/edit(.:format)    categories#edit {:locale=>"en"}
     category_es GET    /es/categorias/:id(.:format)      categories#show {:locale=>"es"}
     category_en GET    /categories/:id(.:format)         categories#show {:locale=>"en"}
                 PATCH  /es/categorias/:id(.:format)      categories#update {:locale=>"es"}
                 PATCH  /categories/:id(.:format)         categories#update {:locale=>"en"}
                 PUT    /es/categorias/:id(.:format)      categories#update {:locale=>"es"}
                 PUT    /categories/:id(.:format)         categories#update {:locale=>"en"}
                 DELETE /es/categorias/:id(.:format)      categories#destroy {:locale=>"es"}
                 DELETE /categories/:id(.:format)         categories#destroy {:locale=>"en"}

Notes

Wrapping a mount within localized() is not supported.

IMHO doing this is a non-sense (unless you explain why I'm wrong with a real life example), so don't do it.

Rails.application.routes.draw do
  root 'welcome#index'

  localized(:main_site) do
    get 'about', to: 'pages#about', as: :about
    mount Bar::Engine, at: '/bar', as: 'bar_site'
  end
end

Development

The specs embeds a dummy application with some real life example.

To test it :

$ echo "127.0.0.1 main-domain.local foo-domain.local bar-domain.local" >> /etc/hosts
$ bundle install
$ cd spec/dummy
$ bin/rails s

Open your navigator on :