rainlab/translate-plugin
RainLab Translate adds multilingual support to October CMS sites. Translate CMS pages, menus, static content, and model records with per-locale fields, language switching, and a straightforward workflow for building and managing localized websites.
This is not a vanilla Laravel package. rainlab/translate-plugin is an October CMS plugin (namespace RainLab\Translate) built on october/rain. Don't composer require it into a plain Laravel app — it wires into October's plugin registry, backend controllers, CMS Twig runtime and migration system.
Minimal path:
composer require rainlab/translate-plugin
php artisan plugin:enable RainLab.Translate
php artisan october:migrate # creates rainlab_translate_messages / _attributes / _indexes
Then, in the backend:
en, fr, de), set the default and fallback locale, and choose whether the URL carries a locale prefix.|_ filter.|_:class Post extends Model
{
use \RainLab\Translate\Traits\Translatable;
public $translatable = ['title', 'content'];
}
<h1>{{ 'Latest news'|_ }}</h1>
The first realistic use case is a two-locale brochure site: add fr, set /fr/... prefixes, translate CMS pages (Static Pages integration adds per-locale tabs automatically), translate a couple of plugin models, and drop {% component 'localePicker' %} into your layout.
Model attribute translation. Read through the current locale; write through a locale-scoped proxy:
$post->title = 'Hello';
$post->save();
$post->translate('fr')->title = 'Bonjour';
$post->translate('fr')->content = '...';
$post->translate('fr')->save(); // save the proxy, not the parent
Frontend string translation. Three tiers, in fallback order: theme/plugin lang files, the DB-backed message catalogue, then the literal key.
{{ 'Add to cart'|_ }}
{{ 'Hello :name'|_({ name: 'Sam' }) }}
use RainLab\Translate\Models\Message;
echo Message::trans('Hello :name', ['name' => 'Sam']);
The backend Messages screen is the day-to-day workflow for non-developers: they see the source English string, type the target, and the value is stored in rainlab_translate_messages. Import/export there is the practical way to ship translations between environments.
CMS/Static Pages integration. Page titles, content, metadata, and menu item labels get locale tabs in the editor. Translated URLs are generated per locale when the prefix setting is on, so /about and /fr/a-propos can coexist. Pages are resolved by the locale-aware router rather than a hand-rolled middleware.
Locale plumbing. The plugin's middleware resolves locale from the URL prefix (or session, if configured) and calls App::setLocale(). For SEO, include the built-in alternate-hreflang component in your <head>:
{% component 'alternateHrefLangElements' %}
Programmatic switching in components/console code:
use RainLab\Translate\Classes\Translator;
Translator::instance()->setLocale('fr');
Keep that call at the top of any job/command that writes translated data.
$translatable are translated. A missing entry doesn't error — it just returns the base value, which is easy to miss in review.$post->translate('fr')->title = ... and then calling $post->save() won't persist. Save the translated model instance.Sluggable-style generation per locale plus route rebuilds. After changing page URLs or locale prefixes: clear the October cache (php artisan cache:clear) and rebuild the CMS route cache, or you'll chase phantom 404s.'Add to cart'|_ is keyed on the literal string. Editing the English word orphans the translation. For anything long-lived, use dot-keyed messages ('shop.cart.add') instead of prose.app.locale, not the request locale. A job that translates models without setting the locale will happily overwrite the default-language values.Traits/Translatable.php when a value appears to round-trip incorrectly.rainlab_translate_messages directly or via seeder, flush the cache or you'll debug a translation that "is in the DB but not showing".Message::extend() and model events on RainLab\Translate\Models\Message are the natural hooks for custom catalogue loading (e.g. pulling strings from an external translation service); the localePicker component and hreflang component can be overridden in your theme/plugin.NOASSERTION — read the LICENSE file before commercial use. The last tagged release is October 2022, so test against your October version rather than assuming current-version parity.How can I help you explore Laravel packages today?