# I18n

Internationalization is always tricky as it involves several layers,
from routing to controller logic and view outputs to URL building and redirecting.

## Basics
Set up a default language in your configs:
```php
	'Config' => [
		'language' => 'de',
	],
```
Any `Configure::read('Config.language')` or `I18n::locale()` call should return that default language.


## Detecting the user language
To detect and switch based on language, you can leverage the Language class.
Either you manually use `findMatches()` to sort through, or you use the convenience method `findFirstMatch()`:
```php
use Tools\Utility\Language;

$language = Language::findFirstMatch(['de', 'en']);
```
It will use the language with the highest weight supported by the user agent data provided.

Note: When you have intl installed, you can also try to use the CakePHP core LocaleSelectorMiddleware.


## Session based language switch
In your AppController you can now do:
```php
	/**
	 * @return void
	 */
	public function initialize() {
		parent::initialize();

		// First check the session
		$language = $this->request->session()->read('Config.language');
		// Then check the browser preference for the whitelisted languages
		if (!$language) {
			$language = Language::findFirstMatch(Configure::read('Config.supportedLanguages'));
		}
		// Overwrite the system default
		if ($language) {
			Configure::write('Config.language', substr($language, 0, 2));
			I18n::locale($language);
		}
```

You then just need a switch on the website that allows the other to change the language (by writing it into the session):
```php
<?php if (Configure::read('Config.language') === 'de') {
	echo $this->Html->image('flag_de.png', ['title' => __('German')]);
} else {
	echo $this->Form->postLink($this->Html->image('flag_de.png'), ['prefix' => false, 'plugin' => 'Tools', 'controller' => 'ShuntRequest', 'action' => 'language', 'de'], ['block' => true, 'escape' => false, 'title' => __('German')]);
} ?>
<?php if (Configure::read('Config.language') === 'en') {
	echo $this->Html->image('flag_en.png', ['title' => __('English')]);
} else {
	echo $this->Form->postLink($this->Html->image('flag_en.png'), ['prefix' => false, 'plugin' => 'Tools', 'controller' => 'ShuntRequest', 'action' => 'language', 'en'], ['block' => true, 'escape' => false, 'title' => __('English')]);
}?>
```

Make sure you included the routes for the Tools plugin for this to work or set them up manually in the `src/Config/routes.php` file.


## Using language in URLs
Instead of the "easy" session-based way you might want to use URLs like `domain.tld/de/controller/action` instead for the other languages of the website.
This can however affect also your view layer as you will have to overwrite the URL generation there to always include the 
new `language` param.
 
Switch out the above session check then with
```php
$language = $this->request->getParam('language');
```
(before CakePHP 3.4+ it would be `param()`)

And make sure your routes are all adjusted to accept and parse the language param:
```php
Router::scope('/', function (RouteBuilder $routes) {
	$routes->connect('/', ['controller' => 'Pages', 'action' => 'display', 'home']);

	$routes->connect(
		'/:language/:controller/:action/*',
		[],
		['language' => 'de']
	);
	
	...
}
```

In this case only `/de/...` is a language param, since `/...` (without any) would continue to use the default language (English).

You can of course also make the regexp here `'language' => 'de|en'` for all languages to be a param in the URL. 
Only the root `/` would then be allowed to fallback to the default one.
In this case you should have a canonical (pointed to the root) on that action to avoid it being treated as duplicate content.

Now you just have to overwrite `Controller::redirect()` for the controller redirects and `HtmlHelper::link()`/`UrlHelper::build()` etc for the view level URLs generated.

For a more sophisticated approach on that routing topic you might want to look into [the I18n plugin](https://github.com/ADmad/cakephp-i18n).


## Language vs Locale
A locale is a combination of language and region (usually a country).

Most would not use locales here for the switch, but languages. 
The locales are merely used internally for the presentation details.

Examples for Germany/German:
- `de_DE`/`de_AT` are some of the possible locale codes
- `de` is the language (iso code) and internally uses one of those two locales

Examples for USE/English:
- `en_US`/`en_GB` are some of the possible locale codes
- `en` is the language (iso code) and internally uses one of those two locales

See [here](http://sandbox.dereuromark.de/export/) for a list of possible languages and their codes.
