bedita/i18n

Internationalization plugin for BEdita 4 & CakePHP

Maintainers

Details

github.com/bedita/i18n

Source

Issues

Installs: 88 306

Dependents: 9

Suggesters: 0

Security: 0

Stars: 3

Watchers: 7

Forks: 1

Open Issues: 1

Type:cakephp-plugin

v4.4.3 2023-11-03 07:20 UTC

README

Github Actions codecov phpstan Scrutinizer Code Quality image image

Installation

You can install this BEdita4/CakePHP plugin using composer like this:

composer require bedita/i18n

Setup

In order to use the plugin you have to load it in your Application::bootstrap() using

$this->addPlugin('BEdita/I18n');

Middleware and Helper

First of all you need to setup an I18n configuration in your application config/bootstrap.php (or if you prefer in config/app_local.php)

/*
 * I18n configuration.
 */
Configure::write('I18n', [
    // list of locales supported
    // locale => primary language code for that locale
    'locales' => [
        'en_US' => 'en',
        'it_IT' => 'it',
    ],
    // default primary language code
    'default' => 'en',
    // list of languages supported
    // primary language code => humanized language
    'languages' => [
        'en' => 'English',
        'it' => 'Italiano',
    ],

    /** Middleware specific conf **/
    // array of URL paths, if there's an exact match rule is applied
    'match' => ['/'],
    // array of URL paths, if current URL path starts with one of these rule is applied
    'startWith' => ['/help', '/about'],
    //reserved URL (for example `/lang`) used to switch language and redirect to referer URL.
    'switchLangUrl' => '/lang',
    // array for cookie that keeps the locale value. By default no cookie is used.
    'cookie' => [
         'name' =>  'i18n-lang', //cookie name
         'create' => true, // set to `true` if the middleware is responsible of cookie creation
         'expire' => '+1 year', // used when `create` is `true` to define when the cookie must expire
    ],
    // session key where store the locale. Set null to disable (default)
    'sessionKey' => 'i18n-session-locale',
]);

I18nMiddleware

Adding BEdita/I18n plugin in app Application::bootstrap() method, the I18nMiddleware will be added in middleware queue just before RoutingMiddleware.

I18n configuration will be used to setup middleware configuration.

namespace App;

use Cake\Http\BaseApplication;

/**
 * Application setup class.
 */
class Application extends BaseApplication
{
    /**
     * {inheritDoc}
     */
    public function bootstrap(): void
    {
        parent::bootstrap();

        $this->addPlugin('BEdita/I18n');
    }

    // other stuff here
}

You can also decide to not add I18nMiddleware since your app doesn't need it or to programmatically add it in your application:

namespace App;

use BEdita\I18n\Middleware\I18nMiddleware;
use Cake\Http\BaseApplication;
use Cake\Error\Middleware\ErrorHandlerMiddleware;
use Cake\Http\MiddlewareQueue;
use Cake\Routing\Middleware\AssetMiddleware;
use Cake\Routing\Middleware\RoutingMiddleware;

/**
 * Application setup class.
 */
class Application extends BaseApplication
{
    /**
     * {inheritDoc}
     */
    public function bootstrap(): void
    {
        parent::bootstrap();

        // Do not add I18nMiddleware automatically
        $this->addPlugin('BEdita/I18n', ['middleware' => false]);
    }

    /**
     * {@inheritDoc}
     */
    public function middleware($middlewareQueue) : MiddlewareQueue
    {
        $middlewareQueue
            ->add(ErrorHandlerMiddleware::class)
            ->add(AssetMiddleware::class)

            // Add programmatically I18n middleware.
            ->add(new I18nMiddleware())

            ->add(new RoutingMiddleware($this));

        return $middlewareQueue;
    }
}

In this way the middleware just takes care of setup the right locale using the URI path and a configuration. For example navigating to http://example.com/it/page/one the middleware setup locale to it_IT using the above configuration example.

You can configure the middleware to redirect some urls to their i18n versions

$middlewareQueue->add(new I18nMiddleware([
    'match' => ['/'],
    'startWith' => ['/help/', '/about/'],
]));

All URI paths matching exactly something in 'match' key or starting with one entry in 'startWith' will be redirect to the same URL but with the detected language as prefix, for example /it/help.

You can also configure the middleware to use a cookie to store the locale

$middlewareQueue->add(new I18nMiddleware([
    'cookie' =>[
        'name' => 'I18nLocale',
        'create' => true, // the middleware will create the cookie (default false)
        'expire' => '+1 month', // cookie expiring time (default +1 year)
    ],
]));

I18nRoute

I18nRoute class can be used to simplify the way you write and match routing rules. For example

$routes->connect(
    '/pages',
    [
        'controller' => 'Pages',
        'action' => 'index',
    ],
    [
        '_name' => 'pages:index',
        'routeClass' => 'BEdita/I18n.I18nRoute',
    ]
);

maps to /:lang/pages and the language code defined in I18n.languages configuration will be used as route patterns on :lang param.

So the above rule is the same of

$routes->connect(
    '/:lang/pages',
    [
        'controller' => 'Pages',
        'action' => 'index',
    ],
    ['_name' => 'pages:index']
)
->setPatterns(['lang' => 'it|en']);

If the current language is it you can obtain the localized url as

// default
$url = \Cake\Routing\Router::url(['_name' => 'pages:index']);
echo $url; // prints /it/pages

// get url with another supported lang
$url = \Cake\Routing\Router::url([
    '_name' => 'pages:index',
    'lang' => 'en',
]);
echo $url; // prints /en/pages

I18nHelper

In order to use the helper you need to initialize it in your AppView::initialize() method

public function initialize() : void
{
    parent::initialize();

    $this->loadHelper('BEdita/I18n.I18n');
}

Gettext command

gettext command provides a method to update I18N locale files in BEdita apps and plugins.

A working msgmerge binary on your system is necessary. In most Linux systems this is provided via gettext package.

By simply typing

bin/cake gettext

your code inside /src and /config is parsed and gettext strings are extracted looking for __('Some string') expressions. Then:

  • resources/locales/default.pot gettext master file is created or updated, same for optional domain files like mydomain.pot
  • all locale files like resources/locales/{locale}/default.po and other optional domain files like mydomain.po are also created or updated - where {locale} is the usual locale expression like en-US, de-DE or fr-FR.

Command options:

--help, -h      Display this help.
--quiet, -q     Enable quiet output.
--verbose, -v   Enable verbose output.
--app, -a       The app path, for i18n update.
--plugin, -p    The plugin path, for i18n update.
--plugins       Apply on all plugins.

You may invoke this command on a different application or plugin path via --app or --plugin options.