Building a multilingual website with Mojolicious

For a long time there was the MojoX::Locale::Maketext module. But it is currently deprecated since Mojolicious has Mojolicious::Plugin::I18n in its core. Today we will try to use it to create a multilingual website.

At first we setup charset plugin so unicode data is correctly displayed:

    $self->plugin(charset => {charset => 'utf8'});

Then we create lexicon files for every language we want to have. Let en be the default one.

    package MyApp::I18N::en;

    use base 'MyApp::I18N';

    our %Lexicon = ( _AUTO => 1); 

    1;

    package MyApp::I18N::ru;

    use base 'MyApp::I18N';

    # Don't forget if we have unicode symbols in package file
    use utf8;

    our %Lexicon = ( 
        'Add'    => 'Добавить',
        'Remove' => 'Удалить'
    );

    1;

Then setup i18n plugin:

    $self->plugin(i18n => {namespace => 'MyApp::I18N'});

In templates now we have l helper:

    <%=l 'Add' %>

Mojolicious will guess what language user wants looking into Accept headers.

That could be it. But it would be better if we had prefixed urls for every language.

    /en/welcome
    /ru/welcome

Without using a bridge we set up a after_static_dispatch hook that will cut the language tag and set it as the current language.

       $self->plugins->add_hook(after_static_dispatch => sub {
            my ($self, $c) = @_; 

            # We don't want to parse static files urls
            return if $c->res->code;

            if (my $path = $c->tx->req->url->path) {
                my $part = $path->parts->[0];

                if ($part && grep { $part eq $_ } @{$config->{languages}}) {
                    shift @{$path->parts};

                    $c->app->log->debug("Found language $part in url");

                    $c->stash->{i18n}->languages($part);
                }
            }
        }
    ); 

Also we want url_for to build the correct urls on behalf of the current language. In our Mojolicious controller we overwrite url_for method:

    sub url_for {
        my $self = shift;

        my $url = $self->SUPER::url_for(@_);

        my $language = $self->stash->{i18n}->languages;

        unshift @{$url->path->parts}, $language;

        return $url;
    }

Now we have automatic language detection and language urls that will point to the right translation if you want to share a link in a specific language.

Comments

blog comments powered by Disqus