danil-kashin / localization
A PHP localization package for managing translations
Requires
- php: >=8.5
Requires (Dev)
- phpunit/phpunit: ^12.0
README
A lightweight PHP localization package for managing translations. Instantiate a Translator with a language and a path to your JSON translation files, and wire it up however your application requires.
Requirements
- PHP 8.5+
Installation
composer require danil-kashin/localization
Quick start
Create a JSON translation file for each language you support:
translations/
ru.json
de.json
{
"Hello": "Привет",
"Goodbye": "До свидания"
}
Instantiate a Translator and call translate():
use DanilKashin\Localization\Translator; use DanilKashin\Localization\Language; $translator = new Translator( language: 'ru', translationsPath: __DIR__ . '/translations', ); echo $translator->translate('Hello'); // Привет echo $translator->translate('Goodbye'); // До свидания echo $translator->translate('Missing'); // Missing (falls back to original text)
Translations are loaded lazily on the first call to translate().
Languages
The Language class contains constants for all 184 ISO 639-1 language codes:
use DanilKashin\Localization\Language; new Translator(Language::RU, __DIR__ . '/translations'); new Translator(Language::DE, __DIR__ . '/translations'); new Translator(Language::ZH, __DIR__ . '/translations');
The default language is Language::EN. If you need codes beyond ISO 639-1, extend the class:
class MyLanguage extends Language { const string ZH_TW = 'zh-TW'; // Traditional Chinese }
Normalizing language codes
Language::fromCode() normalizes arbitrary codes (e.g. from Accept-Language headers or Telegram's language_code) to a 2-character lowercase string:
Language::fromCode('en-US'); // 'en' Language::fromCode('RU'); // 'ru'
Default language
The default language is Language::EN ('en'). Translating in the default language always returns the original text unchanged — no file is loaded and no missing-key tracking occurs.
You can change the default:
$translator = new Translator( language: 'de', translationsPath: __DIR__ . '/translations', defaultLanguage: 'de', ); $translator->isDefaultLanguage(); // true $translator->translate('Hello'); // 'Hello' (no translation attempted)
Tracking missing translations
Pass a MissingTranslationHandlerInterface to be notified whenever a key has no translation. The built-in JsonFileMissingTranslationHandler appends missing keys to a JSON file:
use DanilKashin\Localization\JsonFileMissingTranslationHandler; $handler = new JsonFileMissingTranslationHandler(__DIR__ . '/missing.json'); $translator = new Translator( language: 'ru', translationsPath: __DIR__ . '/translations', missingHandler: $handler, ); $translator->translate('An untranslated string'); // missing.json → { "ru": ["An untranslated string"] }
The file is created if it does not exist. Duplicate keys are never written twice.
Custom handler
Implement the interface to handle missing keys your own way (logging, alerting, etc.):
use DanilKashin\Localization\MissingTranslationHandlerInterface; class LoggingHandler implements MissingTranslationHandlerInterface { public function handle(string $language, string $text): void { // log or alert } }
Dependency injection
Translator implements TranslatorInterface, so you can type-hint against the interface in your own code:
use DanilKashin\Localization\TranslatorInterface; class MyService { public function __construct(private readonly TranslatorInterface $translator) {} }
License
BSD-3-Clause. See LICENSE.