drago-ex / translator
Lightweight translator for Nette Framework using NEON files, supporting global and module-specific translations.
Requires
- php: >=8.3 <9
- nette/application: ^3.1
- nette/caching: ^3.4
- nette/di: ^3.1
- nette/utils: ^4.0
- tracy/tracy: ^2.10
Requires (Dev)
- nette/bootstrap: ^3.1
- nette/tester: ^2.5
- phpstan/phpstan-nette: ^2.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
Lightweight translator for Nette Framework using NEON files, supporting global and module-specific translations.
Requirements
- PHP >= 8.3
- Nette Framework
- Composer
Installation
composer require drago-ex/translator
Extension Registration
Register the DI extension in your NEON configuration.
extensions: translator: Drago\Localization\DI\TranslatorExtension(%appDir%, %tempDir%)
Optional configuration
translator: autoFinder: false translateDirs: - %appDir%/First/Translate - %appDir%/Second/Translate exclude: - %appDir%/Temp - %appDir%/Legacy
Translator Behavior
- All directories listed in translateDirs are loaded in order.
- Later directories override translations from earlier ones.
- If autoFinder is enabled, the entire application directory is scanned for NEON files.
- Directories listed in exclude are skipped during automatic scanning.
Translation files must be named by language code:
cs.neon
en.neon
Translation File Format
"Hello, world!": "Hello, world!" "Hello, %s!": "Ahoj, %s!" "You have %d items in your cart.": "V košíku máte %d položek."
Parameters in Translations
Translations can contain sprintf-style placeholders. Pass their values after the message key; the translator inserts them in order using PHP's vsprintf():
$translator->translate('Hello, %s!', 'Jane'); // Ahoj, Jane! $translator->translate('You have %d items in your cart.', 3); // V košíku máte 3 položek.
The same works with the translator registered in Latte:
{_'Hello, %s!', $name} {_'You have %d items in your cart.', $itemCount}
Use a matching placeholder for each argument, in the same order. Common placeholders include %s for text, %d for an integer, and %.2f for a decimal number with two digits after the decimal point. When no translation exists, the original message is used and its placeholders are formatted in the same way.
Using Translator in Presenters
Add the TranslatorAdapter trait to your presenter:
use Drago\Localization\TranslatorAdapter;
The trait provides:
- persistent language parameter ($lang)
- automatic translator initialization
- template integration
Accessing the Current Language
You can access the currently set language using the following property:
$this->lang;
Getting Translator Instance
To get the initialized translator for the current language:
$this->getTranslator()
Using Translations in Templates
The translator is automatically registered in templates. Example usage in Latte:
{_"Hello, world!"} {$label|translate}
Using Translator in Forms
To enable translations in forms, set the translator explicitly:
$form->setTranslator($this->getTranslator());
Routing for Language Switching
To support language prefixes, configure your routes accordingly:
$router->addRoute('[<lang=en cs|en>/]<presenter>/<action>', 'Presenter:action');
Switching Languages in Templates
You can switch languages by passing the lang parameter:
<a n:href="this, lang => cs">Czech</a> <a n:href="this, lang => en">English</a>
Language Switch Widget
The package provides a reusable Latte widget for language switching.
When project file copying is handled by drago-ex/project-tools, the widget is copied to:
app/Presentation/Accessory/Widget/@lang-switch.latte
Import the widget in your layout:
{import 'path/to/@lang-switch.latte'}
Render language links:
{include lang-switch, lang: 'cs', name: 'Czech'} <span class="small ps-1 pe-1 text-secondary">|</span> {include lang-switch, lang: 'en', name: 'English'}
The current language link automatically receives the current class.
Available options:
lang- target language code.name- visible translated label.class- optional class added to the link.tag- optional wrapper tag:li,div, orspan.tagClass- optional class added to the wrapper tag.
Use class when the link needs a custom class:
{include lang-switch, lang: 'cs', name: 'Czech', class: 'nav-link'}
Use tag when the link must be wrapped, for example in a dropdown menu:
{include lang-switch, lang: 'cs', name: 'Czech', tag: 'li'} {include lang-switch, lang: 'en', name: 'English', tag: 'li'}
Use tagClass when the wrapper needs styling:
{include lang-switch, lang: 'cs', name: 'Czech', tag: 'li', tagClass: 'item-wrapper'}
Notes
- Translator loads translations lazily on first use
- Translations are loaded once per request
- Missing keys return the original message