From aed3e1ec745ec01d4a7cf2375e07c32cbaa48ef1 Mon Sep 17 00:00:00 2001 From: DeeDeeG Date: Thu, 16 Apr 2020 10:06:12 -0400 Subject: [PATCH] Add a locale switcher (#620) * application_controller.rb: Adjust set_locale logic Adds a :locale parameter (which should come from the URL, e.g.: `refugerestrooms.org/?locale=en` or something like that.) * application_controller.rb: set up default_url_options Allows URLs auto-generated by Rails to automatically be expanded to include "?locale=xyz" or "&locale=xyz" See: https://guides.rubyonrails.org/v5.2.4/i18n.html#setting-the-locale-from-url-params For example, this affects URLs made with ActionView URL helpers ('button_to', 'link_to', etc.) See: https://api.rubyonrails.org/v5.2.4/classes/ActionView/Helpers/UrlHelper.html (Hard-coded URLS will generally not get the parameter added.) * header: Use link_to helper for homepage link Use a link_to helper to dynamically create the homepage link, because URL helpers now automatically include the 'locale=' parameter. * header: Un-hard-code the api docs path Use the 'api_docs_path' helper, rather than hard-coding '/api/docs'. (This is for the navigation header, under the "Resources" drop-down.) * config/routes.rb: Add (optional) locale scope to all pages Adds an optional locale prefix for almost every page in the app. See: https://guides.rubyonrails.org/v5.2.4/i18n.html#setting-the-locale-from-url-params You can now visit e.g. '/es/restrooms/new' and you will see the "Submit a New Restroom" page in Spanish. All links in the app auto-generate this locale prefix, so users can specify a locale via visiting a specific locale prefix, and the links in the app will not misdirect them into another locale. (You can still visit URLs without a locale prefix, like '/restrooms/new', and the app will simply auto-detect the locale based on the preferred languages in your browser settings.) This preserves the existing URLs in working order, and any links out there on the web, or in people's bookmarks, will still work.) The home page does not always get the prefix: - The home page link in nav is just '/?locale=[I18n.locale]' - You can visit '/?locale=es' to see the homepage in Spanish. - The homepage link in the nav are auto-generated as '/?locale=[I18n.locale]'; This is equivalent in functionality to the locale prefixes (e.g. '/es/'). - The homepage links in the footer are auto-generated as '/[I18n.locale]/'. - You can visit '/es/' to see the homepage in Spanish. * _footer.html.haml: Add locale switcher links Adds locale switcher links in the footer, which displays at the bottom of every page. These links dynamically link to the current page the user is viewing, but with the current locale overridden with a specific, new locale. Uses the Rails API's "ActionDispatch::Request" feature to get a string containing the last requested page, (i.e. the page the user is currently viewing). This includes query parameters, such as "?lat=[num]&long=[num]" See: https://api.rubyonrails.org/v5.2.4/classes/ActionDispatch/Request.html#method-i-GET (Parameters can also be derived from the URL, such as the "es/" in "/es/restrooms/new", if routed properly.) See: https://guides.rubyonrails.org/routing.html See these StackOverflow answers/this Wikipedia article for details: - https://stackoverflow.com/questions/3762430/rails-preserving-get-query-string-parameters-in-link-to - https://stackoverflow.com/questions/6885990/rails-params-explained - https://en.wikipedia.org/wiki/Query_string * CSS: Better styling of the locale-switcher links Spaced out the links a bit, and added bullet-point separators. * spec: Fix a path construction, test passes now Passing the whole array of restroom data was causing the whole array to be erroneously interpreted as if it was the :locale prefix in the path. Explicitly pass :id, and only :id, to the `restroom_path` route helper for this test. (We only need the :id from the newly-constructed test restroom in order to visit the correct path. Other restroom data isn't needed here anyhow.) --- app/assets/stylesheets/components/common.scss | 4 ++++ app/controllers/application_controller.rb | 6 ++++- app/views/layouts/_footer.html.haml | 18 ++++++++++++++- app/views/layouts/_navigation.html.haml | 4 ++-- config/routes.rb | 23 +++++++++++++------ spec/features/contacts_spec.rb | 2 +- 6 files changed, 45 insertions(+), 12 deletions(-) diff --git a/app/assets/stylesheets/components/common.scss b/app/assets/stylesheets/components/common.scss index 020bf413..07854368 100644 --- a/app/assets/stylesheets/components/common.scss +++ b/app/assets/stylesheets/components/common.scss @@ -145,3 +145,7 @@ footer { color: #BE1E2D; } } + +.locale_link { + margin: 0px 5px; +} diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 103cf92c..d0ee37ba 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -10,7 +10,11 @@ def mobile_filter_header end def set_locale - I18n.locale = http_accept_language.language_region_compatible_from(I18n.available_locales) + I18n.locale = params[:locale] || http_accept_language.language_region_compatible_from(I18n.available_locales) end + def default_url_options + { locale: I18n.locale } + end + end diff --git a/app/views/layouts/_footer.html.haml b/app/views/layouts/_footer.html.haml index 422b5898..2266faef 100644 --- a/app/views/layouts/_footer.html.haml +++ b/app/views/layouts/_footer.html.haml @@ -16,4 +16,20 @@ %a{:href => "https://patreon.com/refugerestrooms"} #{t('.on-patreon')} %br/ = "\© #{t('.copyleft')} #{Date.today.year} #{t('.refuge-restrooms')}".html_safe - + %br/ + %br/ + = link_to 'English', request.query_parameters.merge({:locale => 'en'}), class: "locale_link" + • + = link_to 'Español', request.query_parameters.merge({:locale => 'es'}), class: "locale_link" + • + = link_to 'Filipino/Tagalog', request.query_parameters.merge({:locale => 'fil'}), class: "locale_link" + • + = link_to 'Français', request.query_parameters.merge({:locale => 'fr'}), class: "locale_link" + • + = link_to 'हिन्दी', request.query_parameters.merge({:locale => 'hi'}), class: "locale_link" + • + = link_to 'Italiano', request.query_parameters.merge({:locale => 'it'}), class: "locale_link" + • + = link_to 'polski', request.query_parameters.merge({:locale => 'pl'}), class: "locale_link" + • + = link_to 'Português do Brasil', request.query_parameters.merge({:locale => 'pt-BR'}), class: "locale_link" diff --git a/app/views/layouts/_navigation.html.haml b/app/views/layouts/_navigation.html.haml index af1795d1..84a91d27 100644 --- a/app/views/layouts/_navigation.html.haml +++ b/app/views/layouts/_navigation.html.haml @@ -4,7 +4,7 @@ %nav.nav.navbar-default{:role => "navigation"} / Brand and toggle get grouped for better mobile display .navbar-header - %a#logo.toiletLogo{:href => "/"} + = link_to root_path, id: "logo", class: "toiletLogo" do .navbar-brand Refuge Restrooms %button.navbar-toggle{"data-target" => "#bs-example-navbar-collapse-1", "data-toggle" => "collapse", :type => "button"} %span.sr-only= t('.toggle-navigation-button-label') @@ -21,5 +21,5 @@ %b.caret %ul.dropdown-menu %li= link_to t('.download-unisex-restroom-signs-hyperlink-label'), page_path('signs') - %li= link_to t('.public-api-hyperlink-label'), '/api/docs/' + %li= link_to t('.public-api-hyperlink-label'), api_docs_path / /.navbar-collapse diff --git a/config/routes.rb b/config/routes.rb index 47a7974f..273d8d6b 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -2,18 +2,27 @@ # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html devise_for :admin_users, ActiveAdmin::Devise.config + get '/:locale' => 'pages#index' + root 'pages#index' + ActiveAdmin.routes(self) - resources :restrooms, except: [:edit, :destroy] + scope "(:locale)" do + resources :restrooms, except: [:edit, :destroy] + end namespace :api do - resources :docs, only: [:index] + scope "(:locale)" do + resources :docs, only: [:index] + end end mount API::Base => '/api' + scope "(:locale)" do + get '/contact', to: 'contacts#new' + get "/*id" => 'pages#show', as: :page, format: false + end - get '/contact', to: 'contacts#new' - get "/*id" => 'pages#show', as: :page, format: false - root 'pages#index' - - resources "contacts", only: [:new, :create] + scope "(:locale)" do + resources "contacts", only: [:new, :create] + end end diff --git a/spec/features/contacts_spec.rb b/spec/features/contacts_spec.rb index 3752214c..3a53d8cc 100644 --- a/spec/features/contacts_spec.rb +++ b/spec/features/contacts_spec.rb @@ -4,7 +4,7 @@ it 'should show a generic contact when contact is not from restroom form' do restroom = create(:restroom, name: "Mission Creek Cafe") - visit restroom_path restroom + visit restroom_path(:id => restroom.id) click_link 'Contact' expect(page).to_not have_content('Mission Creek Cafe')