Я себе реализовал так:
$L->some_phrase; //Строка перевода, если перевод отсутствует - возвращается "Some phrase"
$L->mail_body($site_name, $username); //Так работают переводы, которые требуют подстановки пользовательских данных, сама строка перевода в формате функции printf(), конкретно тут используется vsprintf()
$L — это объект, который при создании или вызове метода смены языка загружает переводы с JSON файла. Так же есть возможность вместо строковых подстановок использовать замыкания (например, когда выводится время и нужно менять окончание слова). Вызовы несуществующих свойств и методов ловятся с помощью __get() и __call().
Если интересно, как это работает на практике — пишите в личку, покажу.