Getting Started with Laravel and TML

In this post we will create a very simple PHP application using the Laravel framework and translate it to a few languages using TML for PHP.

To learn about how to install and setup Laravel, please visit Laravel’s website:

http://laravel.com/docs/master/installation

Let’s create a one page site, called “Welp”. On the site we will have a few restaurant reviews and a search form.

laravel_welp_english

At the end of this guide, you will see how to use Translation Exchange tools to quickly and easily translate the app to any number of languages.

laravel_language_selector

To activate translation mode, click on “Help Us Translate” link.

laravel_inline_mode

The source code for this post can be found at:

https://github.com/translationexchange/blog/tree/master/getting-started-with-php-laravel-and-tml/welp

Let’s begin by creating a new Laravel project:

[shell]
$ laravel new welp
$ cd welp
[/shell]

Add TML library reference by editing “composer.json” file:

[js title=”composer.json” class=”lang:json”]
“require”: {

“translationexchange/tml”: “3.0.3”
}
[/js]

To install the library, run:

[shell]
$ composer update
[/shell]

Add a new “Tml.php” middleware file under “app/Http/Middleware/Tml.php” and paste the following code:

[php title=”app/Http/Middleware/Tml.php” class=”lang:php”]
“YOUR_APPLICATION_KEY”
));
return $next($request);
}

public function terminate($request, $response) {
tml_complete_request();
}
}

To get your application key, please visit https://dashboard.translationexchange.com and register a new application. At the end of the registration process you will see your application key and token. If you already have an application, click on the “Integration” link on the left menu to get your key from there.

Let’s create our “app/Http/Controllers/WelpController.php” controller and use the following code:

 $this->getRestaurants()]);
    }

    private function getRestaurants() {
        return [
            [
                "name"          => "Ricky's Fish Tacos",
                "rating"        =>  4,
                "review_count"  =>  14,
                "last_comment"  => "Luckily, the perfect hot day food is a fish taco."
            ],
            [
                "name"          => "Genwa Korean Bbq",
                "rating"        =>  3,
                "review_count"  =>  567,
                "last_comment"  => "I love love love the fact that you get 25 side dishes."
            ],
            [
                "name"          => "Kang Hodong Baekjeong",
                "rating"        =>  2,
                "review_count"  =>  1,
                "last_comment"  => "Thick slices of juicy pastrami on rye hits the spot every time."
            ],
            [
                "name"          => "Guisados",
                "rating"        =>  1,
                "review_count"  =>  14,
                "last_comment"  => "I can't wait to introduce more people to these orgasmic tacos."
            ]
        ];
    }
}

To make things simple, we are just going to hardcode some restaurant reviews as an array structure and then use them in the view.

And finally, let’s add our view. We will use Blade templates and create a separate file for layout first:




Welp




@include('layouts.navigation')

@yield('content')




[/php]

All of our navigation will be stored in the "navigation.blade.php" template. Let's add it as well:

[php title="resources/views/layouts/navigation.blade.php" class="lang:php" mark="1,8,21-25,29,33,36,37,44"]
{{ tml_begin_source("navigation") }}

{{ tml_finish_source() }}
[/php]

We want to group all strings related to the navigation into a single source. If you have multiple pages that use the navigation bar, instead of having all navigation elements to be linked to each page source, the navigation elements will only be linked to the navigation source and only the elements of the page will be linked to the page source. Notice that we open a source group on line 1 and close it on line 44. You can create any number os groups/sources, and nest them within each other.

Notice that on line 29, we add a default language selector that will show all the languages enabled/published for your application. To publish a new language, you simply need to add the language to your application from Translation Exchange dashboard, and it will be immediately visible to your translators. To make the language available to all users, publish your most recent changes through the dashboard and the latest translations and languages will be visible to everyone else.

Now we can add the actual view that uses the main layout:

[php title="resources/views/index.blade.php" class="lang:php" mark="12,15,24-33,37,43,47,63,64,72,86,89,94,97,101,109,118-122,125,128,132,133,141,145,149"]
@extends('layouts.application')

@section('content')

{!! tr("Welp {city}", ["city" => tr("Los Angeles")]) !!}


{!! trh("

The best way to find local businesses

Search for everything from the city's tastiest burger to the most renowned cardiologist.
What will you uncover in your neighborhood?

Create your free account

") !!}

{!! tr("Best of Welp: {city}", ["city" => tr("Los Angeles")]) !!}



{!! tr("See More", "A link to view more restaurants") !!}

{!! tr("Restaurants") !!}

@foreach ($restaurants as $index => $restaurant)


{{ $index + 1 }}.
{{ $restaurant["name"] }}

{!! tr("{count || Review}", ["count" => $restaurant["review_count"]]) !!}

{!! tr($restaurant["last_comment"]) !!}

@endforeach




{!! tr("Review of the day") !!}


{!! tr("{user} reviewed [link: {restaurant}]", [
"user" => ["object" => ["gender" => "female", "name" => "Jane Smith"], "attribute" => "name"],
"restaurant" => "Ricky's Fish Tacos",
"link" => function($text) { return "$text"; } ]
) !!}


{!! tr("{count || Review}", ["count" => 234]) !!}

{!! tr("You can't beat flavorful crunchy tacos, free chips and delicious salsa, yummy burritos and enchiladas.") !!}
{!! tr("Read More") !!}


{!! tr("Welp on the go") !!}

{!! tr("Get the Welp app on your mobile phone. It's free and helps you find great, local businesses on the go!") !!}

@endsection
[/php]

Let's look at some of the code from the above view. On line 12, we have:

[php]
{!! tr("More Cities", "A link to view more cities") !!}
[/php]

We use {!! instead of {{ because we want the ability to enable inline translation mode that generates HTML wrapper tags. When you pass a token value to a tr method, you should escape it yourself, by using htmlspecialchars function.

On line 15 we use data token name city. Notice that we translate the value of the token as well. This is an example of a nested translation.

On lines 24-33, we wrap an entire HTML section with a trh function. The content will automatically be split into individual segments and translated using SDK.

On line 63, we see how a trl method is used. In this case, we deliberately don't want to ever use an inline translator, because a translation key is used inside of a title attribute of the image tag.

[php]

[/php]

It also shows how numeric context rules can be used. The line the follows also shows the numeric rules in action.

[php]
{!! tr("{count || Review}", ["count" => $restaurant["review_count"]]) !!}
[/php]

Lines 118-122 show a more advanced use of TML where we want the sentence to be translated based on the gender of user token. We also use a custom function for the "link" decoration token.

[php]
{!! tr("{user} reviewed [link: {restaurant}]", [
"user" => ["object" => [
"gender" => "female", "name" => "Jane Smith"
], "attribute" => "name"],
"restaurant" => "Ricky's Fish Tacos",
"link" => function($text) { return "$text"; } ]
) !!}
[/php]

Let's start the server by running the following command:

[shell]
$ php artisan serve
$ open "http://locahost:8000"
[/shell]

You should now be able to view the application, change languages, activate translation mode and contribute more translations. You can invite your own translators or order professional translations through the Translation Exchange platform.

To learn more about TML, please visit:

https://translationexchange.com/docs/tml/basics

Caching Translations

For optimal performance, translations should be cached in the application. There are two main ways to cache translations by either using static, local files based cache, or by using a shared dynamic cache, like Memcache or Redis.

The file cache must be generated and deployed with the application. When changes are made to translations or new languages are added, the cache must be updated locally, checked in with the application and deploy to the servers.

Dynamic cache can be generated and deployed without restarting the application.

In this example, we will use Memcache as our dynamic cache. To add cache to your app, update you Tml middleware to include the following directive:

[php title="app/Http/Middleware/Tml.php"]
"YOUR_APPLICATION_KEY",
"token" => "YOUR_APPLICATION_TOKEN",
"cache" => array(
"enabled" => true,
"adapter" => "memcache",
"host" => "localhost",
"port" => 11211
)
));
return $next($request);
}

public function terminate($request, $response) {
tml_complete_request();
}
}
[/php]

Now when we restart our application, the translations will be cached in our Memcache and our application will share them across all PHP servers. But, in our case we only have one.

To invalidate the cache, we can use the following code anywhere from within our application:

[php title="Cache Invalidation" class="lang:php"]
get("access_token") == tml_application()->access_token)
Cache::invalidateVersion();
return redirect('/');
}

[/php]

This will allow us to release new translation versions or add new languages without ever needing to restart our servers.

To learn more about cache options, please visit:

https://translationexchange.com/docs/sdk/php

Get Started Today!

Create an account to get started now! No credit card required.

Get Started