# Content

# Setup

Require package:

composer require contributte/translation
1

Register extension:

extensions:
	translation: Contributte\Translation\DI\TranslationExtension
1
2

# Configuration

Basic configuration:

translation:
	locales:
		whitelist: [en, cs, sk]
		default: en
		fallback: [en]
	dirs:
		- %appDir%/lang
	returnOriginalMessage: true # to not translate undefined messages, default is true
1
2
3
4
5
6
7
8

Note: The fallback configuration values should always reflect the locale code used in the file you wish to fallback to (e.g. en_US for messages.en_US.neon, or en for messages.en.neon).

# Locale resolvers

This configuration instructs the extension how to resolve the locale and the order in which it will do so:

translation:
	localeResolvers:
		- Contributte\Translation\LocalesResolvers\Router
1
2
3

Available resolvers:

  • Contributte\Translation\LocalesResolvers\Router
  • Contributte\Translation\LocalesResolvers\Header (HTTP header)
  • Contributte\Translation\LocalesResolvers\Parameter (Get parameter)
  • Contributte\Translation\LocalesResolvers\Session

By default the Router, Parameter and Session resolvers expect the name of the parameter/key to be locale.

# Examples

# Presenter

<?php declare(strict_types = 1);

namespace App;

use Nette;
use Contributte;

class BasePresenter extends Nette\Application\UI\Presenter
{

	/** @var Nette\Localization\ITranslator @inject */
	public $translator;

	/** @var Contributte\Translation\LocalesResolvers\Session @inject */
	public $translatorSessionResolver;


	public function handleChangeLocale(string $locale): void
	{
		$this->translatorSessionResolver->setLocale($locale);
		$this->redirect('this');
	}


	public function renderDefault(): void
	{
		$this->translator->translate('domain.message');
		$prefixedTranslator = $this->translator->createPrefixedTranslator('domain');
		$prefixedTranslator->translate('message');
	}

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

# Model

<?php declare(strict_types = 1);

namespace App\Model;

use Nette;

class Model
{

	/** @var Nette\Localization\ITranslator */
	private $translator;


	public function __construct(Nette\Localization\ITranslator $translator)
	{
		$this->translator = $translator;
	}

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# Latte

How to use on frontend.

{_domain.message}
{_domain.message, $count}
{_domain.message, [name => "Ales"]}

{translator domain}
	{_message}
	{_message, $count}
	{_message, [name => "Ales"]}
{/translator}

{var $myMessage = 'domain.message'}
{$myMessage|translate}
1
2
3
4
5
6
7
8
9
10
11
12

# Neon

File name format:

        locale
          |
         /--\
messages.en_US.neon
\______/       \__/
   |            |
 domain     extension
1
2
3
4
5
6
7

File content format:

prefix:
	for: "message" # messages.prefix.for
1
2

# Parameters in messages

Sometimes it is convenient to include a dynamic parameter in the translation - as seen in the Latte examples above.

Neon:

user.name.taken: "Sorry, the username %name% is already taken, please try a different one."
1

Latte:

{_user.name.taken, [name => "Ales"]}
1

Presenter/Model:

$this->translator->translate('user.name.taken', [name => 'Ales']);
1

Note: When passing parameters to the translator, the parameter names must not be enclosed in % characters. This is done by Contributte/Translation automatically.

# Loaders

By default the extension will look for .neon files.

# File loaders

array: Symfony\Component\Translation\Loader\ArrayLoader
csv: Symfony\Component\Translation\Loader\CsvFileLoader
dat: Symfony\Component\Translation\Loader\IcuDatFileLoader
res: Symfony\Component\Translation\Loader\IcuResFileLoader
ini: Symfony\Component\Translation\Loader\IniFileLoader
json: Symfony\Component\Translation\Loader\JsonFileLoader
mo: Symfony\Component\Translation\Loader\MoFileLoader
php: Symfony\Component\Translation\Loader\PhpFileLoader
po: Symfony\Component\Translation\Loader\PoFileLoader
ts: Symfony\Component\Translation\Loader\QtFileLoader
xlf: Symfony\Component\Translation\Loader\XliffFileLoader
yml: Symfony\Component\Translation\Loader\YamlFileLoader
1
2
3
4
5
6
7
8
9
10
11
12

# Database loaders

Package includes database loaders for Doctrine 2 (opens new window) and Nette Database 3 (opens new window).

# Doctrine

You must create a file with specific format in scanned dirs such as messages.en_US.doctrine. All parameters are optional, but the file has to exist.

table: "My\Entity" # if you specify the entity key, "messages" from file name will be ignored
id: "id" # id column name, default is "id"
locale: "locale" # locale column name, default is "locale"
message: "message" # message column name, default is "message"
1
2
3
4

Add loader to translation configuration:

translation:
	loaders:
		doctrine: Contributte\Translation\Loaders\Doctrine
1
2
3

Entity example:

<?php declare(strict_types = 1);

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity
 * @ORM\Table(name="messages")
 */
class Messages
{

	/**
	 * @ORM\Id
	 * @ORM\Column(type="integer", nullable=false)
	 * @ORM\GeneratedValue
	 */
	public $messageId;

	/**
	 * @ORM\Column(type="string", nullable=false)
	 */
	public $id;

	/**
	 * @ORM\Column(type="string", nullable=false)
	 */
	public $locale;

	/**
	 * @ORM\Column(type="string", nullable=false)
	 */
	public $message;

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

# Nette Database

You must create a file with specific format in scanned dirs such as messages.en_US.nettedatabase. All parameters are optional, but the file has to exist.

table: "my_table" # if you specify table key, "messages" from file name will be ignored
id: "id" # id column name, default is "id"
locale: "locale" # locale column name, default is "locale"
message: "message" # message column name, default is "message"
1
2
3
4

Add loader to translation configuration:

translation:
	loaders:
		nettedatabase: Contributte\Translation\Loaders\NetteDatabase
1
2
3

DB table example:

CREATE TABLE `messages` (
    `id` varchar(191) NOT NULL,
    `locale` char(5) NOT NULL,
    `message` varchar(191) NOT NULL,
    UNIQUE KEY `id` (`id`),
    KEY `locale` (`locale`),
    KEY `message` (`message`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
1
2
3
4
5
6
7
8

# Features

# Wrappers

It is possible to pass pluralization to components without pre-translation and avoiding double translation.

$form = new Nette\Application\UI\Form;

$form->addText('mail', 'form.mail.label')
	->setOption('description', new Contributte\Translation\Wrappers\Message('form.mail.description', [...]);
1
2
3
4

Or pass the not translatable texts:

$form->addSelect('country', 'form.country.label')
	->setItems([
		new Contributte\Translation\Wrappers\NotTranslate('Czech republic'),
		new Contributte\Translation\Wrappers\NotTranslate('Slovak republic'),
	]);
1
2
3
4
5

# TranslationProviderInterface

It is possible to pass additional translation resources from your compiler extensions by implementing the TranslationProviderInterface.

use Nette\DI\CompilerExtension;
use Contributte\Translation\DI\TranslationProviderInterface;

class MyExtension extends CompilerExtension implements TranslationProviderInterface
{

 	public function getTranslationResources(): array
	{
		return [
			__DIR__ . '/../lang/',
		];
	}

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14