Wednesday 7 February 2018

Web Tutorial: Multilingual CNY Website (Part 3/3)

For the next part, you're gonna want to reverse the changes we made in application_controller.rb.

application_controller.rb
class ApplicationController < ActionController::Base
    protect_from_forgery with: :exception

    before_action :get_langs

    def get_langs
        if cookies[:lang] == nil
        cookies[:lang] =
        {
            :value => "en",
            :expires => 1.year.from_now
        }
        end
    end
end


Now, in the Langs Controller, do this. This is an If statement that checks for the parameter lang's value in the languages property of the Lang Model's allowedVals object. Remember the hash only contains "en" and "cn" as keys, so this condition only kicks in if you try the route "langs/index/en" or "langs/index/cn".

langs_controller.rb
class LangsController < ApplicationController
      def index
            if Lang.allowedVals["languages"].include? params[:lang]

            else
   
            end
      end
end


So if there's a value passed in as an argument, either "en" or "cn", a cookie lang is created with the argument as a value. If not, the cookie lang's value is "en" by default. Basically, this means that we use a cookie to track what language the site is currently in.

langs_controller.rb
class LangsController < ApplicationController
      def index
            if Lang.allowedVals["languages"].include? params[:lang]
                  cookies[:lang] =
                  {
                   :value => params[:lang],
                   :expires => 1.year.from_now
                  }
            else
                  cookies[:lang] =
                  {
                   :value => "en",
                   :expires => 1.year.from_now
                  }       
            end
      end
end


Go to routes.rb in the config folder. Add two more lines. This will ensure that there are two more possible routes - "langs/index", and "langs/index" with a language passed in as an argument.

routes.rb
Rails.application.routes.draw do
        get "langs/index" => "langs#index"
        get "langs/index/:lang" => "langs#index"
        get "welcome/" => "welcome#index"
        get "traits/" => "traits#index"
        get "years/" => "years#index"
        get "fortune/" => "fortune#index"

        root "welcome#index"
end


Now try the route "/langs/index/en". What happens? And then try "/langs/index/cn". Does the language change? What if you tried any other argument, such as "langs/index/" or "/langs/index/esp"? Does it change back to English?

Cool. Of course, we're not going to hit that URL manually every time we want to change the language, so let's create a form element for that. In your application View, create a drop-down list. Set it to run the changeLang() function if the value is changed. We'll create that later.

layouts\application.html.erb

<div class="nav right">
        <span class="lang">
            <select name="ddlLang" onchange="changeLang(this.value)">

            </select>
        </span>
        <br />
        <%=link_to Lang.labels["dogyears"][cookies[:lang]], controller: "years" %> |
        <%=link_to Lang.labels["dogtraits"][cookies[:lang]], controller: "traits" %> |
        <%=link_to Lang.labels["dogfortune"][cookies[:lang]], controller: "fortune" %>
</div>


Create a label for it using the properties of the labels object in the Lang Model.

layouts\application.html.erb
<div class="nav right">
        <span class="lang">
            <%=Lang.labels["language"][cookies[:lang]]%>
            <select name="ddlLang" onchange="changeLang(this.value)">

            </select>
        </span>
        <br />
        <%=link_to Lang.labels["dogyears"][cookies[:lang]], controller: "years" %> |
        <%=link_to Lang.labels["dogtraits"][cookies[:lang]], controller: "traits" %> |
        <%=link_to Lang.labels["dogfortune"][cookies[:lang]], controller: "fortune" %>
</div>


Now, we iterate through the allowedVals property of the Lang Model's labels object and set options based on those.

layouts\application.html.erb
<div class="nav right">
        <span class="lang">
            <%=Lang.labels["language"][cookies[:lang]]%>
            <select name="ddlLang" onchange="changeLang(this.value)">
                <% Lang.allowedVals["languages"].each do |key, value|%>
                    <option value="<%= key %>"><%= value %></option>
                <% end %>
            </select>
        </span>
        <br />
        <%=link_to Lang.labels["dogyears"][cookies[:lang]], controller: "years" %> |
        <%=link_to Lang.labels["dogtraits"][cookies[:lang]], controller: "traits" %> |
        <%=link_to Lang.labels["dogfortune"][cookies[:lang]], controller: "fortune" %>
</div>


Here's the drop-down list. But take a look at the screenshots below and see if you can spot the problem. Yep, no matter what language you specify in the URL, the drop-down list always has "English" selected. Let's fix that!










For this, we'll use a Helper. Call it selectedLang(), and pass key (which is either "en" or "cn") into it.

layouts\application.html.erb
            <select name="ddlLang" onchange="changeLang(this.value)">
                <% Lang.allowedVals["languages"].each do |key, value|%>
                    <option value="<%= key %>" <%= selectedLang(key) %>><%= value %></option>
                <% end %>
            </select>


Open up the application_helper.rb file in the helpers folder. In it, define selectedLang() as a function which accepts the parameter lang, and returns the string "selected" only if lang is equal to the current value of the lang cookie.

application_helper.rb
module ApplicationHelper
        def selectedLang(lang)
                "selected" if lang == cookies[:lang]
        end
end


Now when you specify that the language is "cn", you should see the correct value in the drop-down list!



OK, enough side-tracking...

...back to the changeLang() function, yeah?

Open up the assets folder, then the javascripts folder, and finally the application.js file. Ignore the preachy comment section and create the changeLang() function.

application.js
// This is a manifest file that'll be compiled into application.js, which will include all the files
// listed below.
//
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, or any plugin's
// vendor/assets/javascripts directory can be referenced here using a relative path.
//
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// compiled file. JavaScript code in this file should be added after the last require_* statement.
//
// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
// about supported directives.
//
//= require rails-ujs
//= require turbolinks
//= require_tree .

function changeLang(lang)
{

}


Here, let's do a bit of AJAX. Set your AJAX block to access the "langs/index" route and pass in lang as an argument. You already know what that route does - it'll set the lang cookie's value based on whatever argument you pass in.

application.js
function changeLang(lang)
{
    var xmlhttp = new XMLHttpRequest();
    xmlhttp.onreadystatechange = function() {
        if (this.readyState == 4 && this.status == 200) {

        }
    };
    xmlhttp.open("GET", "../../langs/index/" + lang, true);
    xmlhttp.send();
}


And once that route is accessed and the code executed, reload the page!

application.js
function changeLang(lang)
{
    var xmlhttp = new XMLHttpRequest();
    xmlhttp.onreadystatechange = function() {
        if (this.readyState == 4 && this.status == 200) {
            location.reload();
        }
    };
    xmlhttp.open("GET", "../../langs/index/" + lang, true);
    xmlhttp.send();
}


Now, try changing the value of the drop-down list. Does it reload the page and display the language you selected? Groovy, baby.

That's all! Happy Chinese New Year!

Thank you very much for your time. Do enjoy the Year of the Dog.

Sonofabitch, one hell of a tutorial, eh?
T___T

No comments:

Post a Comment