Laravel多客户端差异化英文文本定制方案咨询
Got it, let's tackle this problem—you're running a multi-client platform where you need per-client localized text, and Laravel's default __()/t() helpers don't cut it because they're built for language-based localization, not client-specific variations. Here are a few solid approaches I've used in similar projects, each tailored to different use cases:
This is the simplest approach if your client texts are static and don't change often. The idea is to extend Laravel's default language file structure with client-specific directories, then create a custom helper that checks for client-specific translations first before falling back to the default.
Step 1: Organize Your Language Files
Set up your resources/lang directory like this:
resources/ └── lang/ ├── en/ │ └── metrics.php # Default text: ['today' => 'todays metrics'] ├── client-a/ │ └── en/ │ └── metrics.php # Client A text: ['today' => 'todays metrics'] └── client-b/ └── en/ └── metrics.php # Client B text: ['today' => 'your statics']
Step 2: Create a Custom Helper Function
Add this to your app/helpers.php file (make sure it's autoloaded in composer.json):
function client_t(string $key, array $replace = [], ?string $locale = null): string { // Get the current client (adjust this based on how you identify clients—header, auth, etc.) $client = request()->header('X-Client-Id') ?? config('app.default_client'); $locale = $locale ?? app()->getLocale(); // Check if the client-specific translation exists $clientKey = "{$client}.{$locale}.{$key}"; if (Lang::has($clientKey)) { return __($clientKey, $replace); } // Fallback to the default translation return __($key, $replace); }
Usage
Now you can use client_t('metrics.today') in your views or controllers—it'll pull the right text based on the current client.
If you need client texts to be editable via a backend (or have frequent changes), storing translations in the database makes sense. This lets you override default text per client, locale, and key.
Step 1: Create a Migration
Schema::create('client_translations', function (Blueprint $table) { $table->id(); $table->unsignedInteger('client_id'); // Link to your clients table $table->string('key'); // e.g., 'metrics.today' $table->string('locale'); // e.g., 'en' $table->text('value'); // The client-specific text $table->timestamps(); });
Step 2: Create a Model and Helper
// app/Models/ClientTranslation.php class ClientTranslation extends Model { protected $fillable = ['client_id', 'key', 'locale', 'value']; public static function get(string $key, int $clientId, string $locale): ?string { return self::where('client_id', $clientId) ->where('key', $key) ->where('locale', $locale) ->value('value'); } } // Update your client_t helper function client_t(string $key, array $replace = [], ?string $locale = null): string { // Get current client ID (adjust based on your auth setup) $clientId = auth()->user()?->client_id ?? config('app.default_client_id'); $locale = $locale ?? app()->getLocale(); // Check for database override $customText = ClientTranslation::get($key, $clientId, $locale); if ($customText) { // Handle variable replacements (same as Laravel's __() function) foreach ($replace as $placeholder => $value) { $customText = str_replace(":{$placeholder}", $value, $customText); } return $customText; } // Fallback to default language files return __($key, $replace); }
If you want to keep using Laravel's default __() helper instead of creating a new one, you can extend Laravel's localization loader to automatically prioritize client-specific translations. This integrates seamlessly with existing code.
Step 1: Create a Custom Loader Class
// app/Localization/ClientLoader.php namespace App\Localization; use Illuminate\Contracts\Translation\Loader; use Illuminate\Translation\FileLoader; class ClientLoader implements Loader { protected $fileLoader; protected $client; public function __construct(FileLoader $fileLoader) { $this->fileLoader = $fileLoader; // Get current client (adjust as needed) $this->client = request()->header('X-Client-Id') ?? config('app.default_client'); } public function load($locale, $group, $namespace = null) { // Load client-specific translations first $clientTranslations = $this->fileLoader->load($locale, $group, "client-{$this->client}"); // Load default translations and merge—client ones override defaults $defaultTranslations = $this->fileLoader->load($locale, $group, $namespace); return array_merge($defaultTranslations, $clientTranslations); } // Delegate other required methods to the default FileLoader public function addNamespace($namespace, $hint) { $this->fileLoader->addNamespace($namespace, $hint); } public function namespaces() { return $this->fileLoader->namespaces(); } public function addJsonPath($path) { $this->fileLoader->addJsonPath($path); } public function jsonPaths() { return $this->fileLoader->jsonPaths(); } public function loadLines($locale, $group, $namespace = null) { return $this->fileLoader->loadLines($locale, $group, $namespace); } }
Step 2: Register the Loader in AppServiceProvider
// app/Providers/AppServiceProvider.php use Illuminate\Contracts\Translation\Loader; use App\Localization\ClientLoader; use Illuminate\Translation\FileLoader; public function register() { $this->app->bind(Loader::class, function ($app) { $fileLoader = new FileLoader($app['files'], $app['path.lang']); // Add a namespace for client translations $fileLoader->addNamespace('client', $app['path.lang'].'/clients'); return new ClientLoader($fileLoader); }); }
Directory Structure
resources/ └── lang/ ├── en/ │ └── metrics.php └── clients/ ├── client-a/ │ └── en/ │ └── metrics.php └── client-b/ └── en/ └── metrics.php
Usage
Now you can just use __('metrics.today') as usual—the loader will automatically pull the client-specific text if it exists.
Which to Choose?
- Option 1: Best for static, infrequent changes. Easy to set up and maintain.
- Option 2: Perfect if clients need to edit their own texts via a dashboard.
- Option 3: Great if you want to keep using Laravel's default helpers without changing existing code.
内容的提问来源于stack exchange,提问作者Merijndk

