Spiral Translate component utilizes Symfony\Translation interface and message formatter but changes the logic of how locale and domains work.
interface TranslatorInterface extends \Symfony\Component\Translation\TranslatorInterface
{
/**
* Default set of braces to be used in classes or views for indication of translatable content.
*/
const I18N_PREFIX = '[[';
const I18N_POSTFIX = ']]';
/**
* Resolve domain name for given bundle.
*
* @param string $bundle
*
* @return string
*/
public function resolveDomain(string $bundle): string;
/**
* Get list of supported locales.
*
* @return array
*/
public function getLocales(): array;
}
The main implementation difference is how spiral process fallback locales and domains:
Classical usage of TranslatorInterface might looks like:
public function indexAction(TranslatorInterface $translator)
{
echo $translator->trans('Hello, {name}!', [
'name' => $this->faker->name
]);
}
You can also use transChoice
method of translator, same way as it was designed in original interface:
public function indexAction(TranslatorInterface $translator)
{
$count = mt_rand(0, 10);
echo $translator->transChoice(
'{0} There are no apples|{1} There is one apple|]1,Inf[ There are {count} apples',
$count,
compact('count')
);
}
The Translator ships with two IoC scope specific methods l
and p
which work as bridge to
translator->trans
and translator->transChoice
accordingly:
public function indexAction()
{
echo l('hello world1');
$count = mt_rand(0, 10);
echo p(
'{0} There are no apples|{1} There is one apple|]1,Inf[ There are {count} apples',
$count,
compact('count')
);
}
To add more locates to your application, simply create a folder inside your `app/resources/locales' directory.
For example file "app/resources/locales/ru/views.ru.po" will represent "views" bundle for russian language.
public function indexAction()
{
dump($this->translator->getLocales());
}
Translator will cache list of available locates for performance reasons, to flush this cache run:
spiral i18n:reload
.
Inside your locale directory you only need to place domain specific localization file in one of allowed formats defined in translator config:
'loaders' => [
'php' => Translation\Loader\PhpFileLoader::class,
'csv' => Translation\Loader\CsvFileLoader::class,
'po' => Translation\Loader\PoFileLoader::class,
/*{{loaders}}*/
],
One of the most important parts of any translation process is actual translation, let's try to export our locale messages in a user friendly format using command i18n:dump
:
> spiral i18n:dump ru russian
Dump successfully completed using Symfony\Component\Translation\Dumper\PhpFileDumper
Output directory: /var/www/sample.dev/russian
Use -d
options to select alternative dumper:
> spiral i18n:dump ru russian -d po
Dump successfully completed using Symfony\Component\Translation\Dumper\PoFileDumper
Output directory: /var/www/sample.dev/russian
msgid ""
msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: ru\n"
msgid "Hello world!"
msgstr "Привет мир!"
Read how to index and capture all i18n messages of your application in indexation section.
You are able to change your application locate at any moment by calling method setLocate
of translator:
public function indexAction()
{
$this->translator->setLocale('ru');
}
Alternative way might include middleware approach:
class LocaleDetector extends Service implements MiddlewareInterface
{
/**
* {@inheritdoc}
*/
public function __invoke(Request $request, Response $response, callable $next)
{
$supported = $this->translator->getLocales();
foreach ($this->fetchLocales($request) as $locale) {
if (in_array($locale, $supported)) {
$this->translator->setLocale($locale);
break;
}
}
return $next(
$request->withAttribute('locale', $this->translator->getLocale()),
$response
);
}
/**
* @param Request $request
*
* @return \Generator
*/
public function fetchLocales(Request $request)
{
$header = $request->getHeaderLine('accept-language');
foreach (explode(',', $header) as $value) {
if (strpos($value, ';') !== false) {
yield substr($value, 0, strpos($value, ';'));
}
yield $value;
}
}
}
If you experiencing issues with translator seeing your locations files, try run spiral configure
to
rebuild your project.