ساخت یک وب‌سایت دوزبانه با Laravel فقط به معنی ترجمه چند متن در فایل‌های زبان نیست. یک وب‌سایت چندزبانه که قرار است در محیط واقعی و در مقیاس تولید (Production) اجرا شود، به معماری مشخصی برای Routing، ذخیره‌سازی محتوا، SEO و تجربه کاربری نیاز دارد.

زمانی که کاربران فارسی و انگلیسی از یک پلتفرم مشترک استفاده می‌کنند، توسعه‌دهندگان با چالش‌هایی مانند URLهای چندزبانه، پشتیبانی از RTL، تگ‌های hreflang، متادیتای ترجمه‌شده و مدیریت محتوای چندزبانه روبه‌رو می‌شوند.

در این مقاله معماری‌ای را بررسی می‌کنیم که در پروژه‌های واقعی Laravel و Livewire برای ساخت وب‌سایت‌های فارسی–انگلیسی استفاده می‌کنم؛ معماری‌ای که بدون نیاز به نگهداری دو Codebase مجزا، امکان توسعه و نگهداری آسان‌تر پروژه را فراهم می‌کند.


Routing مبتنی بر Locale

  استفاده از Prefix زبان در URLها یکی از مهم‌ترین تصمیمات در معماری وب‌سایت‌های چندزبانه است. به‌عنوان مثال، مسیرهای /en/projects و /fa/projects می‌توانند از یک Controller یا Livewire Component مشترک استفاده کنند.

  

// routes/web.php Route::prefix('{locale}') ->where(['locale' => 'en|fa']) ->middleware('setLocale') ->group(function () { Route::get('/projects', ProjectsPage::class) ->name('projects.index'); Route::get('/blog/{slug}', BlogPostPage::class) ->name('blog.show'); });

استفاده از Locale در URL باعث می‌شود آدرس صفحات قابل پیش‌بینی، قابل اشتراک‌گذاری و کاملاً سازگار با موتورهای جستجو باشد.

همچنین قرار گرفتن زبان فعال در URL این امکان را فراهم می‌کند که هر صفحه به‌صورت مستقل Bookmark، Index و Share شود.

نگهداری Locale صرفاً در Session یا Cookie، فرآیند ایندکس شدن صفحات توسط موتورهای جستجو را با مشکل مواجه می‌کند و معمولاً برای پروژه‌های چندزبانه توصیه نمی‌شود.

نمونه Middleware برای تعیین زبان

class SetLocale { public function handle($request, Closure $next) { $locale = $request->segment(1); if (! in_array($locale, ['en', 'fa'])) { $locale = config('app.fallback_locale'); } app()->setLocale($locale); return $next($request); } }

مدل داده برای Translation

کی از رایج‌ترین سوالات هنگام طراحی سیستم چندزبانه این است که از JSON Column استفاده کنیم یا جدول مجزای ترجمه؟

برای موجودیت‌هایی مانند پروژه‌ها، مقالات بلاگ و صفحات ثابت، استفاده از جدول اختصاصی Translation معمولاً انتخاب بهتری است.

Schema::create('project_translations', function (Blueprint $table) { $table->id(); $table->foreignId('project_id') ->constrained() ->cascadeOnDelete(); $table->string('locale', 2); $table->string('title'); $table->text('excerpt')->nullable(); $table->longText('body'); $table->timestamps(); $table->unique(['project_id', 'locale']); });

زمانی که تیم تولید محتوا بزرگ‌تر می‌شود، جدول‌های Translation نسبت به JSON Column مقیاس‌پذیری بسیار بهتری دارند.

علاوه بر این، این ساختار امکانات زیر را فراهم می‌کند:

  • اعتبارسنجی محتوا قبل از انتشار
  • جستجوی اختصاصی برای هر زبان
  • ذخیره مستقل اطلاعات SEO برای هر زبان
  • ساده‌تر شدن پنل مدیریت محتوا

  معمولاً فیلدهایی مانند slug، status و published_at در مدل اصلی ذخیره می‌شوند و فقط داده‌های ترجمه‌شده در جدول Translation قرار می‌گیرند.

  

روابط Eloquent و استراتژی Fallback

در Laravel می‌توان روابط ترجمه را به سادگی با Eloquent پیاده‌سازی کرد.

public function translations() { return $this->hasMany(ProjectTranslation::class); } public function translation() { return $this->hasOne(ProjectTranslation::class) ->where('locale', app()->getLocale()); }

اما در پروژه‌های واقعی همیشه ممکن است ترجمه یک زبان هنوز تکمیل نشده باشد. به همین دلیل بهتر است یک مکانیزم Fallback در نظر بگیریم تا در صورت نبود ترجمه، نسخه انگلیسی نمایش داده شود.

public function currentTranslation() { return $this->translations() ->where('locale', app()->getLocale()) ->first() ?? $this->translations() ->where('locale', 'en') ->first(); }

استفاده از Fallback مناسب باعث می‌شود کاربران هیچ‌گاه با صفحات خالی یا خطاهای غیرمنتظره مواجه نشوند و تجربه کاربری به شکل قابل توجهی بهبود پیدا کند.

SEO برای اپلیکیشن‌های چندزبانه Laravel

  موتورهای جستجو باید متوجه شوند که آدرس‌های /fa/about و /en/about دو نسخه معادل از یک صفحه برای مخاطبان متفاوت هستند.

در صورتی که SEO چندزبانه به‌درستی پیاده‌سازی نشود، گوگل ممکن است صفحات را محتوای تکراری (Duplicate Content) تشخیص دهد.

نمونه استفاده از hreflang  

<link rel="alternate"
      hreflang="en"
      href="https://example.com/en/about">

<link rel="alternate"
      hreflang="fa"
      href="https://example.com/fa/about">

<link rel="alternate"
      hreflang="x-default"
      href="https://example.com/en/about">

همچنین بهتر است برای هر صفحه Canonical اختصاصی تعریف شود.

<link rel="canonical"
      href="{{ url()->current() }}">

برای داشتن یک ساختار SEO استاندارد در پروژه‌های چندزبانه، موارد زیر را فراموش نکنید:

  • برای هر زبان URL مجزا ایجاد کنید.
  • Sitemap اختصاصی برای صفحات چندزبانه تولید کنید.
  • در تمام صفحات از تگ hreflang استفاده کنید.
  • عنوان و توضیحات متا را برای هر زبان جداگانه ذخیره کنید.
  • متادیتای Open Graph را ترجمه کنید.
  • از ترجمه ماشینی بدون بازبینی انسانی استفاده نکنید.

تولید Sitemap چندزبانه

برای اینکه موتورهای جستجو بتوانند تمام صفحات چندزبانه را شناسایی کنند، بهتر است نسخه‌های مختلف هر صفحه در Sitemap ثبت شوند.

foreach ($posts as $post) { foreach (['en', 'fa'] as $locale) { $urls[] = url("/{$locale}/blog/{$post->slug}"); } }

ثبت URLهای محلی‌سازی شده در Sitemap باعث می‌شود صفحات سریع‌تر ایندکس شوند و پوشش بهتری در نتایج جستجو داشته باشند.

پشتیبانی از RTL بدون نگهداری دو فایل CSS

پشتیبانی از زبان فارسی تنها با اضافه کردن dir="rtl" به صفحه تمام نمی‌شود.

کامپوننت‌هایی مانند Sliderها، Dropdownها، Animationها، Carouselها، جداول، Chartها و حتی Code Blockها معمولاً نیاز به مدیریت اختصاصی دارند.

خوشبختانه Tailwind CSS با ارائه Utilityهای منطقی (Logical Properties) نگهداری پروژه‌های RTL را بسیار ساده‌تر کرده است.

نمونه پیشنهادی

<div class="ps-6 pe-6 ms-auto"> ... </div>

نمونه نامناسب

<div class="pl-6 pr-6 ml-auto">

نمونه استاندارد

<div class="ps-6 pe-6 ms-auto">

  استفاده از کلاس‌هایی مانند start، end، ps، pe، ms و me باعث می‌شود بدون نیاز به نگهداری دو Stylesheet مجزا، رابط کاربری در هر دو جهت LTR و RTL به‌درستی کار کند.  

اشتباهات رایج در پروژه‌های چندزبانه

برخی اشتباهات رایج که در بسیاری از پروژه‌ها مشاهده می‌شود عبارت‌اند از:

  1. نگهداری زبان فقط در Session
  2. ترجمه کردن URLهای پنل مدیریت
  3. استفاده کامل از ترجمه ماشینی بدون بازبینی
  4. فراموش کردن تگ‌های hreflang
  5. ذخیره تمام داده‌ها در JSON Column
  6. تست نکردن رابط کاربری در حالت RTL
  7. استفاده از Slugهای متفاوت بدون تعریف Redirect مناسب

اجتناب از این اشتباهات در آینده زمان زیادی را برای تیم توسعه ذخیره خواهد کرد.

جمع‌بندی

پیاده‌سازی یک وب‌سایت دوزبانه با Laravel نیازمند برنامه‌ریزی دقیق از همان ابتدای پروژه است.

پیشنهاد می‌شود ابتدا معماری URLها، ساختار Translation و زیرساخت SEO را طراحی کنید و سپس به سراغ انیمیشن‌ها و جزئیات ظاهری بروید.

یک معماری استاندارد برای وب‌سایت‌های چندزبانه نه‌تنها نگهداری پروژه را ساده‌تر می‌کند، بلکه باعث بهبود رتبه سایت در موتورهای جستجو و ارائه تجربه کاربری بهتر برای مخاطبان فارسی و بین‌المللی خواهد شد.