Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Translate Laravel Package

mouyong/translate

A Laravel/PHP translation package that simplifies adding multilingual support. It offers configurable translation services and a clean API for translating text or language files, making localization easy to integrate into existing applications.

View on GitHub
Deep Wiki
Context7

Getting Started

  1. Install via Composer:

    composer require mouyong/translate
    

    Laravel's package discovery should register the service provider and facade automatically. If not (or on older Laravel), add them manually to config/app.php.

  2. Publish the config so you can wire credentials:

    php artisan vendor:publish --tag=translate-config
    

    Confirm the actual tag in the README — some releases only ship a translate.php config with no publish tag, in which case you copy it manually.

  3. Fill credentials. Each driver needs different fields, so expect a config shape like:

    // config/translate.php
    'default' => env('TRANSLATE_DRIVER', 'baidu'),
    'drivers' => [
        'baidu'  => ['appid' => env('BAIDU_TRANSLATE_APPID'),  'key' => env('BAIDU_TRANSLATE_KEY')],
        'youdao' => ['appid' => env('YOUDAO_TRANSLATE_APPID'), 'key' => env('YOUDAO_TRANSLATE_KEY')],
        'google' => ['key' => env('GOOGLE_TRANSLATE_KEY')], // API-key based
        'jinshan'=> ['appid' => env('JINSHAN_APPID'), 'key' => env('JINSHAN_KEY')],
    ],
    

    Put the secrets in .env, never in the tracked config file.

  4. First use case — translate a single string from a controller or artisan tinker:

    use Mouyong\Translate\Facades\Translate; // verify the exact facade FQCN in the docs
    
    $text = Translate::translate('Hello world', 'en', 'zh-CN');
    

    And language detection:

    $lang = Translate::detect('你好世界');
    

Where to look first: the package's README.md on GitHub. It is the only reliable source for the exact facade namespace, driver keys, and whether the detection and translation methods share a driver or are separate. After that, open config/translate.php and the src/ provider classes to see how each driver builds HTTP requests — that tells you which language codes it expects and which errors it throws.

Reasonable first real feature: auto-detect the visitor's language and translate a handful of dynamic labels (not the whole UI) using the cheapest driver you have credentials for.

Implementation Patterns

Driver selection per call vs. globally. Most of the value comes from being able to pick a provider at runtime. Use the default for generic content and override where quality or cost differs:

Translate::driver('youdao')->translate($text, 'en', 'zh');

Fallback chain. Providers go down. Wrap calls in a small resolver that tries the configured default, then a secondary, and logs which one succeeded:

foreach (config('translate.fallback') as $driver) {
    try {
        return Translate::driver($driver)->translate($text, $from, $to);
    } catch (\Throwable $e) {
        report($e);
    }
}
throw new RuntimeException('All translation drivers failed.');

This is also the cleanest way to spread load if a provider's free tier is exhausted.

Detect-then-translate. For user-generated content, detect the source language first and skip translation when it already matches the target. Cheap guard, big quota saver:

$src = Translate::detect($text);
if (str_starts_with(strtolower($src), strtolower($target))) {
    return $text;
}

Cache aggressively. Translation is deterministic per (text, from, to, driver). Cache on a normalized hash:

$key = 'tr:'.sha1($driver.'|'.$from.'|'.$to.'|'.$text);
return Cache::remember($key, now()->addDays(30), fn () => Translate::driver($driver)->translate($text, $from, $to));

Without this, a listing page with per-row translation will burn through quota in a single afternoon.

Batch and queue. For backfills or multi-language product catalogs, do not translate inline. Dispatch a job per language pair, respect each provider's per-request character limit (Baidu and Youdao cap request length; split on sentence boundaries, not bytes), and persist translations in a dedicated translations table keyed by (model_id, field, locale).

Integrating with Laravel localization. If you want dynamic content in the UI, hook this into a HasTranslations trait or an accessor on the model rather than calling the facade from Blade. Keep the API call in a service class and inject it so you can swap it for a stub in tests:

class LocalizedContent
{
    public function __construct(private TranslateManager $translate) {}
    public function for(string $text, string $locale): string { /* cache + call */ }
}

Eloquent cast for translated attributes. A custom cast that resolves $value through the translation cache is convenient; just make sure it also supports writing (storing the source text) so you don't create an infinite loop where saving retranslates.

Config-driven provider in tests. Bind the driver to a fake in your test suite's service container so CI never hits a paid endpoint — see gotchas below.

Gotchas and Tips

  • Language codes are not unified. Baidu uses zh, en, jp, kor; Google uses zh-CN, zh-TW, ja, ko; Youdao has its own codes. The package may or may not normalize them. Assume it passes your string straight through — build a small mapper in your own code and test each driver's output for a couple of locales before shipping.

  • Google's endpoint may be unreachable from mainland China, and its free tier is a separate Cloud Translation API project with billing enabled. If your servers are in China, default to Baidu or Youdao and treat Google as a fallback.

  • Per-driver credentials differ in shape. Baidu and Youdao use (appid + secret key) with signing; Google uses a single API key. Don't assume one env variable name works everywhere — check the driver source.

  • Rate limits and character quotas are per-provider and not handled for you. Most of these APIs return an HTTP 200 with an error code in the JSON body (e.g. Baidu's error_code). The package may surface that as an exception — verify. If it silently returns the source string or empty, wrap every call and inspect the result.

  • Debugging tip: if a call returns confusing results, dd() the raw response by temporarily hitting the driver's underlying client, or enable HTTP client logging (Http::withOptions(...) / Guzzle middleware) via the service container. The library layers over Guzzle, so Http::macro or a fake will also intercept calls in tests.

  • Use Laravel's HTTP fake in tests. Since the package relies on Laravel's HTTP client (or Guzzle), Http::fake() will short-circuit real requests. Fake the response shape of each driver you use rather than one generic payload — the parsing differs.

  • php artisan config:cache will freeze your driver list. If you swap TRANSLATE_DRIVER at runtime based on tenant or region, don't rely on env() inside config; read from DB/config at runtime and call the driver explicitly.

  • License note: LGPL-3.0 means linking is fine, but if you fork and modify the library itself you must publish those changes under LGPL. Keep your own app code in a separate namespace/package to stay clearly on the "use" side.

  • Extension points: the manager pattern usually exposes Translate::extend('name', fn () => new MyDriver(...)). If the vendor you need (DeepL, Azure) isn't supported, implementing the driver interface is usually a ~30-line class — cleaner than forking.

  • Pin the version ("mouyong/translate": "^1.0" — check the actual released tag) and run a smoke test after upgrades. Last release is July 2024, so breaking changes to config keys or provider signatures are plausible in minor bumps.

  • Don't translate user HTML blindly. Markup gets mangled and character counts balloon. Translate text nodes or strip tags first, then reassemble — or use the provider's HTML mode if the driver supports it.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
skyraptor/chatter
edlugz/sasapay
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource