Saturday 3 February 2018

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

Happy Year of the Dog, dear readers.

If you haven't already guessed it, this is where I present you the annual CNY web tutorial. This one's a doozy - it'll done in Rails.

Whoa! Rails?!

Yep. Almost the entirety of my free time in 2017, such as it was, was spent mucking around with Ruby, and its ubiquitous framework, Rails. Won't bore you with the details today, but it was a pretty sweet ride.

So yeah, for what it's worth, we're going to create a multi-lingual site, complete with language switching. And since it's the Chinese New Year, this will have a very festive dog theme!

Getting started...

Get your basic Rails setup here, and we'll just modify a few files. For those of you new to the whole MVC thing, here's some further reading. I'm going to provide a little bit of background anyway.

Ruby On Rails is an MVC framework. It uses Ruby as the underlying language, and favors "Convention over Configuration". Basically, that means a lot of the default settings are hugely sensible and there's very little you actually need to configure for most cases.

Let's begin with the Models...

Within the app folder, open up the models folder. Create a new file, welcome.rb. This is gonna be the default page. First, we'll create the Welcome class.

welcome.rb
class Welcome

end


Now define the lang_content object as a property of the Welcome class. We'll get to why later.

welcome.rb
class Welcome
        def self.lang_content
        {

        }
        end
end


Do the same for new files fortune.rb, trait.rb and year.rb.

fortune.rb
class Fortune
        def self.lang_content
        {

        }
        end
end


trait.rb
class Trait
        def self.lang_content
        {

        }
        end
end


year.rb
class Year
        def self.lang_content
        {

        }
        end
end


Got all that? Now, we'll need to do the whole Model-Controller-View thing incrementally for maximum clarity. So let's leave the Models alone for now...

On to the Controllers!

In the app folder, open up the controllers folder and modify application_controller.rb. This would do fine if we were planning for some CRUD functions. But since we're not...

application_controller.rb
class ApplicationRecord < ActiveRecord::Base
        self.abstract_class = true
end


...alter the code.

application_controller.rb
class ApplicationRecord < ActionController::Base
        self.abstract_class = true
end


Now create welcome_controller.rb. Create the WelcomeController class and make it a subclass of ApplicationController. This allows the WelcomeController class, as a subclass of ApplicationController, to inherit ApplicationController's properties and behavior.

welcome_controller.rb
class WelcomeController < ApplicationController

end


Next, create the index property within the WelcomeController class, which will serve as a controller action.

welcome_controller.rb
class WelcomeController < ApplicationController
          def index

          end
end


Rinse and repeat for files fortune_controller.rb, trait_controller.rb and year_controller.rb.

fortune_controller.rb
class FortuneController < ApplicationController
          def index

          end
end


traits_controller.rb
class TraitsController < ApplicationController
          def index

          end
end


year_controller.rb
class YearController < ApplicationController
          def index

          end
end


All cool so far? Let's get on with...

The Views

These are basically html files with the extension of ".erb". This is an acronym for "Embedded Ruby". First, open up the views folder, then the layouts folder. Open application.html.erb. This is a master template file. The stylesheet, JavaScript and CSRF meta tag codes are already in. Don't mess with those; they're there for a reason. You don't absolutely need the csrf_meta_tag for what we're doing today, but it can't hurt. stylesheet_link_tag and javascript_include_tag link to the stylesheets and JavaScript respectively. You don't want to change these.

The yield variable is the content that will go into the HTML template. For now, just change the title tag.

application.html.erb
<!DOCTYPE html>
<html>
    <head>
        <title>Welcome to the Year of the Dog!</title>
        <%= csrf_meta_tags %>

        <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
        <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
    </head>

    <body>
        <%= yield %>
    </body>
</html>


Create the welcome folder in the views folder. Inside the welcome folder, create index.html.erb. Just put in a h1 tag for now. Not terribly subtle, but we're doing it for testing purposes.

welcome\index.html.erb
<h1>WELCOME</h1>


Do the same with fortune, traits and years.

fortune\index.html.erb
<h1>FORTUNE</h1>


traits\index.html.erb
<h1>TRAITS</h1>


fortune\index.html.erb
<h1>YEARS</h1>


OK, now you've got the Models, Controllers and Views set, and there's one final detail. Routes!

Go to the config folder and open up the routes folder. Open up routes.rb and make this change. The first line basically says, that if you add a "/welcome" to your root URL, it directs you to the index action of the Welcome controller. And so on, and so forth, for the others.

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


This next line specifies that the default action is the index action of the Welcome controller.

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

    root "welcome#index"
end


Time to test your code! Run the browser and get to the root. This is what you should see, because the index action of the Welcome controller is your default. And this, of course, generates a HTML page using application.html.erb with welcome\index.html.erb embedded within.



Try it with "/welcome/". Things should stay the same.


Try it with "/fortune/". The page should change!


Excellent. You have basic MVC and routing up. Now, let's add a little content to the site. Get back to the models folder in your app folder. Open up welcome.rb. Remember we defined lang_content earlier? Time to work on that! Inside the lang_content object, we define four properties - header, p1, p2 and p3. I've put some sample text as values, but feel free to do what you like.

welcome.rb
class Welcome
    def self.lang_content
        {
            "header" => "Happy New Year",
            "p1" => "2018 is the Year of the Dog!",
            "p2" => "Please click through the links above to find out more",
            "p3" => "We wish you a happy and smooth-sailing New Year!"
        }
      end
end


Now go to welcome_controller.rb in the controllers folder. We'll set four variables, conveniently named header, p1, p2 and p3. And set each one to their corresponding property in the lang_content object of the Welcome class!

welcome_controller.rb
class WelcomeController < ApplicationController
      def index
          @header = Welcome.lang_content["header"]
          @p1 = Welcome.lang_content["p1"]
          @p2 = Welcome.lang_content["p2"]
          @p3 = Welcome.lang_content["p3"]
      end
end


Now, go to your views folder, open up the welcome folder and open index.html.rb. Put the placeholders for each variable defined in the index action of the welcome controller.

welcome\index.html.rb
<h1>WELCOME</h1>
<%=@header %> <br />
<%=@p1 %> <br />
<%=@p2 %> <br />
<%=@p3 %> <br />


There you go! You're probably thinking this is unnecessarily convoluted. Sure, it would seem that way if you're not into MVC frameworks. But this entire separation of presentation from back-end logic is entirely deliberate and very useful in certain cases. For something as simple as what we're doing right now, maybe not so much.


Let's do a little bit more work on the view. First, let's ensure that the following four images of cute dogs are in the images folder of your assets folder, which is in turn inside your app folder. You can download them from here!

00.png
01.png
02.png
03.png


Now, what's about to happen here is that we placed the content in different divs - one styled with class left and the other right. Don't worry about styling yet - we'll get to the CSS in a jiffy. Notice the link_to and image_tag helpers? You just need to specify the file name of the image and it'll return the relative link to those images in the images folder!

welcome\index.html.rb
<h1>WELCOME</h1>

<div class="left">
    <%=@header %> <br />
    <%=@p1 %> <br />
    <%=@p2 %> <br />
    <%=@p3 %> <br />
</div>

<div class="right">
    <%= link_to image_tag("00.png");%>
</div>


Cool, right?


The CSS

As promised, let's style this sucker. Go to the app folder, open up the assets folder and then the stylesheets folder. In there, open up application.css. As stated in the comments, this is actually meant for CSS reference links rather than actual CSS, but for the purposes of this scope, it's all right. Just paste the CSS here. Don't worry so much about the CSS itself - this is just for flavor.

stylesheets\application.css
/*
 * This is a manifest file that'll be compiled into application.css, which will include all the files
 * listed below.
 *
 * Any CSS and SCSS file within this folder, lib/assets/stylesheets, or any plugin's
 * vendor/assets/stylesheets folder can be referenced here using a relative path.
 *
 * You're free to add application-wide styles to this file and they'll appear at the bottom of the
 * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
 * files in this folder. Styles in this file should be added after the last require_* statement.
 * It is generally better to create a new file per style scope.
 *
 *= require_tree .
 *= require_self
 */

body, html
{
    background-color:#FF0000;
    color:#FFFF00;
    font-size:16px;
    font-family:arial,sans-serif;
    margin:0px;
    padding:0px;
    height:100%;
}

.container
{
    width:700px;
    height:100%;
    margin:0 auto 0 auto;
    position:relative;
    padding:5px;
    background-color:rgba(0,0,0,0.5);
    border-left:3px double #444400;
    border-right:3px double #444400;
}

.content
{
    width:550px;
    height:550px;
    border-radius:50%;
    background-color:rgba(255,100,0,0.3);
    margin:10% auto 0 auto;
}

.content .left
{
    width:60%;
    margin:10% -5% 0 -5%;
}

.content .right
{
    width:40%;
    margin:10% -5% 0 -5%;
}

.header
{
    width:100%;
}

.nav, .headertext
{
    width:48%;
}

.nav
{
    text-align:right;
}

.headertext
{
    font-size:2.5em;
    font-weight:bold;
}

.footer
{
    font-size:0.8em;
    position:absolute;
    top:95%;
    left:5%;
}

.lang
{
    font-size:0.8em;
}

a:visited, a:link {color:#FFFF00;text-decoration: none;}
a:hover, a:active {color:#FF4400;text-decoration: none;}

.left {float:left;}
.right {float:right;}
.clearfix {clear:both;}


Reload... and voila! OK, it's looking far from perfect, but we'll be rectifying this soon. What happened here was that the stylesheet_link_tag helper in application.html.erb referenced the application.css file, and thus applied the styles.



Next, let's open up application.html.erb.

application.html.erb.
<!DOCTYPE html>
<html>
    <head>
        <title>Welcome to the Year of the Dog!</title>
        <%= csrf_meta_tags %>

        <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
        <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
    </head>

    <body>
        <div class="container">
            <div class="header">
                <div class="headertext left">

                </div>
                <div class="nav right">

                </div>
                <div class="clearfix"></div>
            </div>

            <div class="content">
                <%= yield %>
                <div class="clearfix"></div>
            </div>

            <div class="footer">

            </div>
        </div>
    </body>
</html>


Now we're talking.


Let's make a little bitty change to the welcome page view. It was all right before getting styled, but now proper paragraph tags are in order.

welcome\index.html.rb
<h1>WELCOME</h1>

<div class="left">
    <p><%=@header %> </p>
    <p><%=@p1 %> </p>
    <p><%=@p2 %> </p>
    <p><%=@p3 %> </p>
</div>

<div class="right">
    <%= link_to image_tag("00.png");%>
</div>


Ah, there we go.


We should, of course, do the same for all the other pages. Starting with the models. All that mumbo-jumbo in fortune.rb was looted from a Chinese zodiac website. So was all the stuff in trait.rb. year.rb has been left empty because we don't need to define any data for it. You'll see why soon!

fortune.rb
class Fortune
        def self.lang_content
        {
             "p1" => "According to traditional Chinese prediction, they will face several challenges in career and wealth. Although they may get enviable developments with rapid progress, they still need to keep modest all the time. Otherwise, the tense interpersonal relationship will likely do harm to their work and money.",
            "p2" => "Most of them are suitable to become group leaders. Their insistent and active personal traits will help them catch development opportunities. In the Year of the Dog, they are advised to do several investments related to cultural project or thermal power project. They are accustomed to earning profits by using strategy or even extreme methods.",
            "p3" => "They should not be too self-willed and extreme in ordinary life. Staying calm down, thinking much and speaking little will bring good effects to their health situation. In addition, it is suggested to avoid some exploration activities such as climbing mountains, drifting and bungee jumping. Villa resort near river and forest is a wonderful place to take a holiday."
        }
        end
end


trait.rb
class Trait
        def self.lang_content
        {
             "candid" => "candid",
             "loyal" => "loyal",
             "intelligent" "intelligent",
             "cool-headed" "cool-headed",
             "persistent" "persistent",
             "active" => "active",
             "impatient" => "impatient",
             "conservative" => "conservative",
             "anxious" => "anxious"  
        }
        end
end


year.rb
class Year
        def self.lang_content
        {

        }
        end
end


Now for the controllers! This is basically repeating what we did for the Welcome controller. Again, the Year controller has been left alone. Patience, I'll tell you why soon.

fortune_controller.rb
class FortuneController < ApplicationController
      def index
          @p1 = Fortune.lang_content["p1"]
          @p2 = Fortune.lang_content["p2"]
          @p3 = Fortune.lang_content["p3"]
      end
end


traits_controller.rb
class TraitsController < ApplicationController
      def index
        @candid = Trait.lang_content["candid"]
        @loyal = Trait.lang_content["loyal"]
        @intelligent = Trait.lang_content["intelligent"]
        @coolheaded = Trait.lang_content["cool-headed"]
        @persistent = Trait.lang_content["persistent"]
        @active = Trait.lang_content["active"]
        @impatient = Trait.lang_content["impatient"]
        @conservative = Trait.lang_content["conservative"]
        @anxious = Trait.lang_content["anxious"]
      end
end


year_controller.rb
class YearController < ApplicationController
      def index

      end
end


Now let's do the views. We do what we did for the Welcome page, except that each of these views uses a different image file. Also, with the Years page, notice we directly put the content in the HTML instead of making it go through the Model and Controller. This is because the content is numbers, and numbers look the same no matter what language they're in. Remember we're going to make this language-switchable?

Is this not making sense? Worry not, it should in the next part of this tutorial.

fortune\index.html.erb
<h1>FORTUNE</h1>

<div class="left">
    <p><%=@p1 %> </p>
    <p><%=@p2 %> </p>
    <p><%=@p3 %> </p>
</div>

<div class="right">
    <%= link_to image_tag("01.png");%>
</div>


traits\index.html.erb
<h1>TRAITS</h1>

<div class="left">
    <p><%=@candid %> </p>
    <p><%=@loyal %> </p>
    <p><%=@intelligent %> </p>
    <p><%=@coolheaded %> </p>
    <p><%=@persistent %> </p>
    <p><%=@active %> </p>
    <p><%=@impatient %> </p>
    <p><%=@conservative %> </p>
    <p><%=@anxious %> </p>
</div>

<div class="right">
    <%= link_to image_tag("02.png");%>
</div>


fortune\index.html.erb
<h1>YEARS</h1>

<div class="left">
    <h2>1982</h2>
    <h2>1994</h2>
    <h2>2006</h2>
    <h2>2018</h2>
    <h2>2030</h2>
</div>

<div class="right">
    <%= link_to image_tag("03.png");%>
</div>


This is how the other pages should look like.








Next

You're going great. Coming up after this, a look at multi-lingual content... and a nav bar!

No comments:

Post a Comment