تعريب Laravel خطوة بخطوة [الدليل]

تعريب Laravel خطوة بخطوة [الدليل]
جدول المحتويات

Laravel أداة قوية تمكن المطورين من إنشاء مواقع ويب متعددة اللغات. من خلال تنفيذ توطين الويب في Laravel ، يمكنك توفير تجربة مستخدم مخصصة للزائرين من خلفيات لغوية مختلفة، مما يؤدي في النهاية إلى توسيع نطاق وصولك وتحسين مشاركة المستخدم.

سنرشدك خلال عملية تنفيذ الترجمة في تطبيق Laravel الخاص بك ونقدم لك أداة يمكنها تبسيط جهود الترجمة الخاصة بك وتعزيزها!

لماذا يجب عليك توطين موقع Laravel ؟

تعريب Laravel خطوة بخطوة [الدليل]

فيما يلي بعض الأسباب المهمة التي تدفعك إلى توطين موقع Laravel الإلكتروني الخاص بك.

  • الوصول إلى جمهور عالمي: من خلال توطين Laravel ، يمكنك توسيع مدى وصول تطبيقك إلى جمهور عالمي. يتيح ذلك للمستخدمين من مختلف البلدان والخلفيات اللغوية فهم المحتوى الخاص بك والتفاعل معه.
  • تحسين تجربة المستخدم: يتيح التعريب للمستخدمين التفاعل مع التطبيق بلغتهم الأصلية، مما يحسن تجربة المستخدم بشكل كبير. يمكن أن يؤدي ذلك إلى زيادة معدلات المشاركة وتقليل معدلات الارتداد وزيادة التحويلات.
  • الميزة التنافسية: في السوق العالمية التنافسية، يمكن أن يوفر تقديم التطبيقات بلغات متعددة ميزة كبيرة على المنافسين. إنه يوضح التزامك بالأسواق الدولية ويمكن أن يساعدك على دخول أسواق جديدة بشكل أكثر فعالية.
  • تحسين محركات البحث: تميل مواقع الويب ذات الترجمة الجيدة إلى الحصول على تصنيف أفضل في محركات البحث لعمليات البحث بلغة معينة. يمكن أن يؤدي ذلك إلى زيادة عدد زيارات مدونتك وإمكانية ظهورك عبر الإنترنت في الأسواق المختلفة من خلال الترجمة متعددة اللغات.

متطلبات توطين Laravel متعدد اللغات

تعريب Laravel خطوة بخطوة [الدليل]

هناك بعض المتطلبات والخطوات التي يجب مراعاتها عند تنفيذ الترجمة متعددة اللغات في Laravel.

  • للحصول على أحدث ميزات الترجمة، تأكد من أنك تستخدم أحدث إصدار من Laravel (على سبيل المثال، الإصدار 10.x).
  • سيكون الفهم الأساسي لـ PHP وإطار عمل Laravel مفيدًا في عملية التنفيذ.
  • قم بإعداد بيئة تطوير محلية أو خادم يدعم Laravel، بما في ذلك خادم الويب وقاعدة البيانات.
  • حدد اللغات التي سيدعمها تطبيقك منذ البداية.

ترجمات Laravel بسيطة

تعريب Laravel خطوة بخطوة [الدليل]

بعد فهم المتطلبات التي يجب استيفاؤها قبل ترجمة تطبيق Laravel أو الويب، سنقدم بعض الخطوات لترجمة Laravel ببساطة.

للقيام بذلك، افتح ملف العرض الذي تريد تعريبه، على سبيل المثال، Resources/views/welcome.blade.php. ثم استبدل علامة الجسم بالكود التالي.

				
					<body class="antialiased">
    <div class="relative flex items-top justify-center min-h-screen bg-gray-100 sm:items-center py-4 sm:pt-0">
        <div class="max-w-6xl mx-auto sm:px-6 lg:px-8">
            <div class="flex justify-center pt-8 sm:justify-start sm:pt-0">
                Welcome to Linguise website!
            </div>
        </div>
    </div> <script data-no-optimize="1">!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).LazyLoad=e()}(this,function(){"use strict";function e(){return(e=Object.assign||function(t){for(var e=1;e<arguments.length;e++){var n,a=arguments[e];for(n in a)Object.prototype.hasOwnProperty.call(a,n)&&(t[n]=a[n])}return t}).apply(this,arguments)}function i(t){return e({},it,t)}function o(t,e){var n,a="LazyLoad::Initialized",i=new t(e);try{n=new CustomEvent(a,{detail:{instance:i}})}catch(t){(n=document.createEvent("CustomEvent")).initCustomEvent(a,!1,!1,{instance:i})}window.dispatchEvent(n)}function l(t,e){return t.getAttribute(gt+e)}function c(t){return l(t,bt)}function s(t,e){return function(t,e,n){e=gt+e;null!==n?t.setAttribute(e,n):t.removeAttribute(e)}(t,bt,e)}function r(t){return s(t,null),0}function u(t){return null===c(t)}function d(t){return c(t)===vt}function f(t,e,n,a){t&&(void 0===a?void 0===n?t(e):t(e,n):t(e,n,a))}function _(t,e){nt?t.classList.add(e):t.className+=(t.className?" ":"")+e}function v(t,e){nt?t.classList.remove(e):t.className=t.className.replace(new RegExp("(^|\\s+)"+e+"(\\s+|$)")," ").replace(/^\s+/,"").replace(/\s+$/,"")}function g(t){return t.llTempImage}function b(t,e){!e||(e=e._observer)&&e.unobserve(t)}function p(t,e){t&&(t.loadingCount+=e)}function h(t,e){t&&(t.toLoadCount=e)}function n(t){for(var e,n=[],a=0;e=t.children[a];a+=1)"SOURCE"===e.tagName&&n.push(e);return n}function m(t,e){(t=t.parentNode)&&"PICTURE"===t.tagName&&n(t).forEach(e)}function a(t,e){n(t).forEach(e)}function E(t){return!!t[st]}function I(t){return t[st]}function y(t){return delete t[st]}function A(e,t){var n;E(e)||(n={},t.forEach(function(t){n[t]=e.getAttribute(t)}),e[st]=n)}function k(a,t){var i;E(a)&&(i=I(a),t.forEach(function(t){var e,n;e=a,(t=i[n=t])?e.setAttribute(n,t):e.removeAttribute(n)}))}function L(t,e,n){_(t,e.class_loading),s(t,ut),n&&(p(n,1),f(e.callback_loading,t,n))}function w(t,e,n){n&&t.setAttribute(e,n)}function x(t,e){w(t,ct,l(t,e.data_sizes)),w(t,rt,l(t,e.data_srcset)),w(t,ot,l(t,e.data_src))}function O(t,e,n){var a=l(t,e.data_bg_multi),i=l(t,e.data_bg_multi_hidpi);(a=at&&i?i:a)&&(t.style.backgroundImage=a,n=n,_(t=t,(e=e).class_applied),s(t,ft),n&&(e.unobserve_completed&&b(t,e),f(e.callback_applied,t,n)))}function N(t,e){!e||0<e.loadingCount||0<e.toLoadCount||f(t.callback_finish,e)}function C(t,e,n){t.addEventListener(e,n),t.llEvLisnrs[e]=n}function M(t){return!!t.llEvLisnrs}function z(t){if(M(t)){var e,n,a=t.llEvLisnrs;for(e in a){var i=a[e];n=e,i=i,t.removeEventListener(n,i)}delete t.llEvLisnrs}}function R(t,e,n){var a;delete t.llTempImage,p(n,-1),(a=n)&&--a.toLoadCount,v(t,e.class_loading),e.unobserve_completed&&b(t,n)}function T(o,r,c){var l=g(o)||o;M(l)||function(t,e,n){M(t)||(t.llEvLisnrs={});var a="VIDEO"===t.tagName?"loadeddata":"load";C(t,a,e),C(t,"error",n)}(l,function(t){var e,n,a,i;n=r,a=c,i=d(e=o),R(e,n,a),_(e,n.class_loaded),s(e,dt),f(n.callback_loaded,e,a),i||N(n,a),z(l)},function(t){var e,n,a,i;n=r,a=c,i=d(e=o),R(e,n,a),_(e,n.class_error),s(e,_t),f(n.callback_error,e,a),i||N(n,a),z(l)})}function G(t,e,n){var a,i,o,r,c;t.llTempImage=document.createElement("IMG"),T(t,e,n),E(c=t)||(c[st]={backgroundImage:c.style.backgroundImage}),o=n,r=l(a=t,(i=e).data_bg),c=l(a,i.data_bg_hidpi),(r=at&&c?c:r)&&(a.style.backgroundImage='url("'.concat(r,'")'),g(a).setAttribute(ot,r),L(a,i,o)),O(t,e,n)}function D(t,e,n){var a;T(t,e,n),a=e,e=n,(t=It[(n=t).tagName])&&(t(n,a),L(n,a,e))}function V(t,e,n){var a;a=t,(-1<yt.indexOf(a.tagName)?D:G)(t,e,n)}function F(t,e,n){var a;t.setAttribute("loading","lazy"),T(t,e,n),a=e,(e=It[(n=t).tagName])&&e(n,a),s(t,vt)}function j(t){t.removeAttribute(ot),t.removeAttribute(rt),t.removeAttribute(ct)}function P(t){m(t,function(t){k(t,Et)}),k(t,Et)}function S(t){var e;(e=At[t.tagName])?e(t):E(e=t)&&(t=I(e),e.style.backgroundImage=t.backgroundImage)}function U(t,e){var n;S(t),n=e,u(e=t)||d(e)||(v(e,n.class_entered),v(e,n.class_exited),v(e,n.class_applied),v(e,n.class_loading),v(e,n.class_loaded),v(e,n.class_error)),r(t),y(t)}function $(t,e,n,a){var i;n.cancel_on_exit&&(c(t)!==ut||"IMG"===t.tagName&&(z(t),m(i=t,function(t){j(t)}),j(i),P(t),v(t,n.class_loading),p(a,-1),r(t),f(n.callback_cancel,t,e,a)))}function q(t,e,n,a){var i,o,r=(o=t,0<=pt.indexOf(c(o)));s(t,"entered"),_(t,n.class_entered),v(t,n.class_exited),i=t,o=a,n.unobserve_entered&&b(i,o),f(n.callback_enter,t,e,a),r||V(t,n,a)}function H(t){return t.use_native&&"loading"in HTMLImageElement.prototype}function B(t,i,o){t.forEach(function(t){return(a=t).isIntersecting||0<a.intersectionRatio?q(t.target,t,i,o):(e=t.target,n=t,a=i,t=o,void(u(e)||(_(e,a.class_exited),$(e,n,a,t),f(a.callback_exit,e,n,t))));var e,n,a})}function J(e,n){var t;et&&!H(e)&&(n._observer=new IntersectionObserver(function(t){B(t,e,n)},{root:(t=e).container===document?null:t.container,rootMargin:t.thresholds||t.threshold+"px"}))}function K(t){return Array.prototype.slice.call(t)}function Q(t){return t.container.querySelectorAll(t.elements_selector)}function W(t){return c(t)===_t}function X(t,e){return e=t||Q(e),K(e).filter(u)}function Y(e,t){var n;(n=Q(e),K(n).filter(W)).forEach(function(t){v(t,e.class_error),r(t)}),t.update()}function t(t,e){var n,a,t=i(t);this._settings=t,this.loadingCount=0,J(t,this),n=t,a=this,Z&&window.addEventListener("online",function(){Y(n,a)}),this.update(e)}var Z="undefined"!=typeof window,tt=Z&&!("onscroll"in window)||"undefined"!=typeof navigator&&/(gle|ing|ro)bot|crawl|spider/i.test(navigator.userAgent),et=Z&&"IntersectionObserver"in window,nt=Z&&"classList"in document.createElement("p"),at=Z&&1<window.devicePixelRatio,it={elements_selector:".lazy",container:tt||Z?document:null,threshold:300,thresholds:null,data_src:"src",data_srcset:"srcset",data_sizes:"sizes",data_bg:"bg",data_bg_hidpi:"bg-hidpi",data_bg_multi:"bg-multi",data_bg_multi_hidpi:"bg-multi-hidpi",data_poster:"poster",class_applied:"applied",class_loading:"litespeed-loading",class_loaded:"litespeed-loaded",class_error:"error",class_entered:"entered",class_exited:"exited",unobserve_completed:!0,unobserve_entered:!1,cancel_on_exit:!0,callback_enter:null,callback_exit:null,callback_applied:null,callback_loading:null,callback_loaded:null,callback_error:null,callback_finish:null,callback_cancel:null,use_native:!1},ot="src",rt="srcset",ct="sizes",lt="poster",st="llOriginalAttrs",ut="loading",dt="loaded",ft="applied",_t="error",vt="native",gt="data-",bt="ll-status",pt=[ut,dt,ft,_t],ht=[ot],mt=[ot,lt],Et=[ot,rt,ct],It={IMG:function(t,e){m(t,function(t){A(t,Et),x(t,e)}),A(t,Et),x(t,e)},IFRAME:function(t,e){A(t,ht),w(t,ot,l(t,e.data_src))},VIDEO:function(t,e){a(t,function(t){A(t,ht),w(t,ot,l(t,e.data_src))}),A(t,mt),w(t,lt,l(t,e.data_poster)),w(t,ot,l(t,e.data_src)),t.load()}},yt=["IMG","IFRAME","VIDEO"],At={IMG:P,IFRAME:function(t){k(t,ht)},VIDEO:function(t){a(t,function(t){k(t,ht)}),k(t,mt),t.load()}},kt=["IMG","IFRAME","VIDEO"];return t.prototype={update:function(t){var e,n,a,i=this._settings,o=X(t,i);{if(h(this,o.length),!tt&&et)return H(i)?(e=i,n=this,o.forEach(function(t){-1!==kt.indexOf(t.tagName)&&F(t,e,n)}),void h(n,0)):(t=this._observer,i=o,t.disconnect(),a=t,void i.forEach(function(t){a.observe(t)}));this.loadAll(o)}},destroy:function(){this._observer&&this._observer.disconnect(),Q(this._settings).forEach(function(t){y(t)}),delete this._observer,delete this._settings,delete this.loadingCount,delete this.toLoadCount},loadAll:function(t){var e=this,n=this._settings;X(t,n).forEach(function(t){b(t,e),V(t,n,e)})},restoreAll:function(){var e=this._settings;Q(e).forEach(function(t){U(t,e)})}},t.load=function(t,e){e=i(e);V(t,e)},t.resetStatus=function(t){r(t)},Z&&function(t,e){if(e)if(e.length)for(var n,a=0;n=e[a];a+=1)o(t,n);else o(t,e)}(t,window.lazyLoadOptions),t});!function(e,t){"use strict";function a(){t.body.classList.add("litespeed_lazyloaded")}function n(){console.log("[LiteSpeed] Start Lazy Load Images"),d=new LazyLoad({elements_selector:"[data-lazyloaded]",callback_finish:a}),o=function(){d.update()},e.MutationObserver&&new MutationObserver(o).observe(t.documentElement,{childList:!0,subtree:!0,attributes:!0})}var d,o;e.addEventListener?e.addEventListener("load",n,!1):e.attachEvent("onload",n)}(window,document);</script><script data-no-optimize="1">var litespeed_vary=document.cookie.replace(/(?:(?:^|.*;\s*)_lscache_vary\s*\=\s*([^;]*).*$)|^.*$/,"");litespeed_vary||fetch("/wp-content/plugins/litespeed-cache/guest.vary.php",{method:"POST",cache:"no-cache",redirect:"follow"}).then(e=>e.json()).then(e=>{console.log(e),e.hasOwnProperty("reload")&&"yes"==e.reload&&(sessionStorage.setItem("litespeed_docref",document.referrer),window.location.reload(!0))});</script><script data-optimized="1" type="litespeed/javascript" data-src="https://www.linguise.com/wp-content/litespeed/js/435d0eaada3b593adf726e5cdfb5dd43.js?ver=0e199"></script><script>const litespeed_ui_events=["mouseover","click","keydown","wheel","touchmove","touchstart"];var urlCreator=window.URL||window.webkitURL;function litespeed_load_delayed_js_force(){console.log("[LiteSpeed] Start Load JS Delayed"),litespeed_ui_events.forEach(e=>{window.removeEventListener(e,litespeed_load_delayed_js_force,{passive:!0})}),document.querySelectorAll("iframe[data-litespeed-src]").forEach(e=>{e.setAttribute("src",e.getAttribute("data-litespeed-src"))}),"loading"==document.readyState?window.addEventListener("DOMContentLoaded",litespeed_load_delayed_js):litespeed_load_delayed_js()}litespeed_ui_events.forEach(e=>{window.addEventListener(e,litespeed_load_delayed_js_force,{passive:!0})});async function litespeed_load_delayed_js(){let t=[];for(var d in document.querySelectorAll('script[type="litespeed/javascript"]').forEach(e=>{t.push(e)}),t)await new Promise(e=>litespeed_load_one(t[d],e));document.dispatchEvent(new Event("DOMContentLiteSpeedLoaded")),window.dispatchEvent(new Event("DOMContentLiteSpeedLoaded"))}function litespeed_load_one(t,e){console.log("[LiteSpeed] Load ",t);var d=document.createElement("script");d.addEventListener("load",e),d.addEventListener("error",e),t.getAttributeNames().forEach(e=>{"type"!=e&&d.setAttribute("data-src"==e?"src":e,t.getAttribute(e))});let a=!(d.type="text/javascript");!d.src&&t.textContent&&(d.src=litespeed_inline2src(t.textContent),a=!0),t.after(d),t.remove(),a&&e()}function litespeed_inline2src(t){try{var d=urlCreator.createObjectURL(new Blob([t.replace(/^(?:<!--)?(.*?)(?:-->)?$/gm,"$1")],{type:"text/javascript"}))}catch(e){d="data:text/javascript;base64,"+btoa(t.replace(/^(?:<!--)?(.*?)(?:-->)?$/gm,"$1"))}return d}</script></body>
				
			

كما ترون، النص أعلاه مكتوب حاليًا مباشرة في الكود. وهذا أقل كفاءة ويجعل من الصعب ترجمة مواقع الويب إلى لغات مختلفة (التدويل).

سنجعل النص أعلاه أكثر مرونة حتى يمكن تكييفه بسهولة مع اللغات المختلفة. يوفر Laravel ميزة مفيدة جدًا لهذا الغرض؛ نظام التوطين. كخطوة أولى، استبدل النص الموجود بالكود التالي.

				
					{{ __('Welcome to Linguise website!') }}
				
			

سيعرض Laravel النص أعلاه افتراضيًا ويبحث عن الترجمة إذا اختار المستخدم لغة أخرى غير الإنجليزية. في هذه الحالة، سيتم استخدام اللغة الإنجليزية كلغة افتراضية للتطبيق.

إعداد اللغات المحلية في شبكة Laravel متعددة اللغات

تعريب Laravel خطوة بخطوة [الدليل]

لكن كيف يحدد Laravel اللغة الحالية أو يعرف اللغات المتوفرة في التطبيق؟ يقوم بالتحقق من الإعدادات المحلية في ملف config/app.php. افتح هذا الملف وابحث عن المفتاحين التاليين.

				
					/*
|--------------------------------------------------------------------------
| Application Locale Configuration
|--------------------------------------------------------------------------
|
| The application locale determines the default locale that will be used
| by the translation service provider. You are free to set this value
| to any of the locales which will be supported by the application.
|
*/

'locale' => 'en',

/*
|--------------------------------------------------------------------------
| Application Fallback Locale
|--------------------------------------------------------------------------
|
| The fallback locale determines the locale to use when the current one
| is not available. You may change the value to correspond to any of
| the language folders that are provided through your application.
|
*/

'fallback_locale' => 'en',

				
			

يجب أن يكون الشرح الموجود فوق المفاتيح واضحًا. باختصار، يحتفظ مفتاح اللغة باللغة الافتراضية لتطبيقك (إذا لم يتم تحديد لغة أخرى في الكود). يتم تنشيط Fallback_locale إذا تم طلب لغة غير موجودة في التطبيق الخاص بك.

الآن، دعونا نضيف مفتاحًا جديدًا لهذا الملف لتوفير قائمة بجميع اللغات المدعومة.

				
					/*
|--------------------------------------------------------------------------
| Available locales
|--------------------------------------------------------------------------
|
| List all locales that your application works with
|
*/

'available_locales' => [
  'English' => 'en',
  'Italian' => 'it',
  'French' => 'fr',
],


				
			

في هذه المرحلة، قمنا بتجربة Laravel web لدعم ثلاث لغات، وهي الإنجليزية والإيطالية والفرنسية.

نظرة عامة على ملفات الترجمة Laravel

تعريب Laravel خطوة بخطوة [الدليل]

في Laravel، كما هو الحال في العديد من الأطر الأخرى، يتم تخزين الترجمات للغات المختلفة في ملفات منفصلة. يتم استخدام طريقتين لتنظيم ملفات الترجمة هذه.

تقوم الطريقة القديمة بتخزين الملفات بالبنية التالية: Resources/lang/{en,fr,it}/{myfile.php}. تستخدم الطريقة الأحدث ملفات JSON، مثل Resources/lang/{fr.json, it.json}. ستركز هذه المقالة على الطريقة الأحدث، على الرغم من أن المبادئ متشابهة مع الطريقة القديمة، بصرف النظر عن الاختلافات في كيفية تسمية مفاتيح الترجمة والوصول إليها.

بالنسبة للغات ذات الاختلافات الإقليمية، يجب عليك تسمية أدلة أو ملفات اللغة وفقًا لمعيار ISO 15897. على سبيل المثال، سيتم تسمية اللغة الإنجليزية البريطانية باسم en_GB بدلاً من en-gb.

معلومات عامة

في Laravel، كما هو الحال مع العديد من أطر العمل، يتم تخزين الترجمات للغات المختلفة في ملفات منفصلة. هناك طريقتان أساسيتان لتنظيم ملفات ترجمة Laravel .

  1. يتضمن الأسلوب القديم تخزين الملفات تحت المسار: Resources/lang/{en,fr,it}/{myfile.php}.
  2. يستخدم الأسلوب الحديث ملفات Resources/lang/{fr.json, it.json}.

ستركز هذه المقالة على الطريقة الثانية، على الرغم من أن المبادئ تنطبق على كليهما (مع اختلافات في كيفية تسمية مفاتيح الترجمة والوصول إليها).

بالنسبة للغات التي تختلف حسب المنطقة، يوصى بتسمية أدلة/ملفات اللغة وفقًا لمعايير ISO 15897. على سبيل المثال، سيتم الإشارة إلى اللغة الإنجليزية البريطانية بالصيغة en_GB بدلاً من en-gb.

إنشاء ملفات الترجمة Laravel

بعد تكوين الإعدادات المحلية لتطبيقنا، يمكننا متابعة ترجمة رسالة الترحيب الافتراضية الخاصة بنا.

لنبدأ بإنشاء ملفات ترجمة جديدة بتنسيق JSON داخل دليل Resources/lang. أولاً، سنقوم بإنشاء ملف Resources/lang/it.json وملؤه بالترجمات المناسبة.

				
					{
  "Welcome to Linguise website!": "Benvenuti nel sito web di Linguise!"
}

				
			

بعد ذلك، أضف ملف Resources/lang/fr.json.

				
					{
 "Welcome to Linguise website!": "Bienvenue sur le site de Linguise"
}

				
			

كما تلاحظ، فإننا نشير باستمرار إلى الرسالة الافتراضية من ملف Welcome.blade.php ({{ __('مرحبًا بك في موقع Linguise !') }}). ليست هناك حاجة لإنشاء ملف en.json، حيث يتعرف Laravel تلقائيًا على أن الرسائل الافتراضية باللغة الإنجليزية.

ضبط محوّل اللغة في تطبيق Laravel متعدد اللغات

تعريب Laravel خطوة بخطوة [الدليل]

علاوة على ذلك، لم يتم إعداد Laravel بعد لتجاوز اللغة المحلية، لذا، في الوقت الحالي، سنتعامل مع الترجمة مباشرة داخل المسار. قم بتعديل مسار الترحيب الافتراضي داخل ملف المسارات/web.php مثل هذا.

				
					Route::get('/{locale?}', function ($locale = null) {
    if (isset($locale) && in_array($locale, config('app.available_locales'))) {
        app()->setLocale($locale);
    }
    
    return view('welcome');
});
				
			

في هذه الحالة، نقوم بالتقاط معلمة GET للغة اختيارية ونقوم بتعيين اللغة الحالية بناءً عليها (إذا كانت اللغة المطلوبة مدعومة).

يمكنك الآن زيارة موقع الويب الخاص بك وتضمين أي من اللغات المدعومة كالجزء الأول في عنوان URL. على سبيل المثال، سيؤدي الانتقال إلى localhost/it أو localhost/fr إلى عرض المحتوى المترجم. إذا لم تحدد لغة أو اخترت لغة غير مدعومة، فسيتم تعيين Laravel افتراضيًا على اللغة الإنجليزية (en).

الوسيطة للتوطين لـ Laravel

قد لا يكون تضمين اللغة في كل عنوان URL أمرًا مثاليًا وقد يؤدي إلى تعطيل المظهر المرئي للموقع. لمعالجة هذه المشكلة، سنقوم بإعداد محوّل لغة واستخدام جلسة المستخدم لعرض المحتوى المترجم. يمكنك إنشاء برامج وسيطة جديدة في ملف app/Http/Middleware/Localization.php، أو إنشائها عن طريق تشغيل الأمر الحرفي make:middleware Localization.

ثم قم بإضافة الكود التالي بداخله.

				
					<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Session;

class Localization
{
    /**
    * Handle an incoming request.
    *
    * @param  \Illuminate\Http\Request  $request
    * @param  \Closure  $next
    * @return mixed
    */
    public function handle(Request $request, Closure $next)
    {
        if (Session::has('locale')) {
            App::setLocale(Session::get('locale'));
        }
        return $next($request);
    }
}


				
			

ستقوم هذه البرمجيات الوسيطة بتوجيه Laravel لاستخدام الموقع الذي حدده المستخدم إذا كان هذا الخيار موجودًا في الجلسة.

نظرًا لأننا نحتاج إلى تنفيذ العملية عند كل طلب، أضفها إلى حزمة البرامج الوسيطة الافتراضية في app/Http/Kernel.php لمجموعة البرامج الوسيطة على الويب.

				
					/**
* The application's route middleware groups.
*
* @var array<string, array<int, class-string|string>>
*/
protected $middlewareGroups = [
  'web' => [
    \App\Http\Middleware\EncryptCookies::class,
    \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
    \Illuminate\Session\Middleware\StartSession::class,
    \Illuminate\View\Middleware\ShareErrorsFromSession::class,
    \App\Http\Middleware\VerifyCsrfToken::class,
    \Illuminate\Routing\Middleware\SubstituteBindings::class,
    \App\Http\Middleware\Localization::class, // <--- add this
],


				
			

تعديل المسارات

بعد ذلك، حدد مسارًا لتغيير الإعدادات المحلية في ملف Routes/web.php. نحن نستخدم مسار إغلاق هنا، ولكن يمكنك وضع نفس الرمز داخل وحدة التحكم إذا كنت تفضل ذلك.

				
					Route::get('language/{locale}', function ($locale) {
   app()->setLocale($locale);
   session()->put('locale', $locale);
   return redirect()->back();
});

				
			

بالإضافة إلى ذلك، قم بإزالة تبديل الإعدادات المحلية الذي تمت إضافته مسبقًا إلى مسار الترحيب الافتراضي. يجب أن يبدو مسار الجذر الخاص بك الآن هكذا.

				
					Route::get('/', function () {
   return view('welcome');
});

				
			

بمجرد الانتهاء من ذلك، يمكن للمستخدم فقط تبديل اللغة النشطة عن طريق زيارة localhost/language/{locale}. سيتم حفظ اللغة المحددة في الجلسة، وسيتم إعادة توجيه المستخدمين مرة أخرى إلى صفحتهم السابقة (كما يتم التعامل معها بواسطة البرنامج الوسيط للتعريب). 

لاختباره، انتقل إلى localhost/language/it (بافتراض أن ملف تعريف ارتباط الجلسة نشط في متصفحك)، ومن المفترض أن تشاهد المحتوى المترجم. يمكنك التنقل في الموقع أو تحديث الصفحة، وستظل اللغة المختارة سارية المفعول.

تنفيذ محول اللغة

الآن، نحن بحاجة إلى تزويد المستخدم بخيار قابل للنقر لتغيير محوّل اللغة Laravel web بدلاً من مطالبته بإدخال رموز الإعدادات المحلية في عنوان URL يدويًا. ولتحقيق ذلك، قم بإنشاء محوّل لغة بسيط. أضف ملفًا جديدًا على Resources/views/partials/language_switcher.blade.php وأدخل الكود التالي.

				
					<div class="flex justify-center pt-8 sm:justify-start sm:pt-0">
    @foreach($available_locales as $locale_name => $available_locale)
        @if($available_locale === $current_locale)
            <span class="ml-2 mr-2 text-gray-700">{{ $locale_name }}</span>
        @else
            <a class="ml-1 underline ml-2 mr-2" href="language/{{ $available_locale }}">
                <span>{{ $locale_name }}</span>
            </a>
        @endif
    @endforeach
</div>


				
			

لتضمين محوّل اللغة الذي تم إنشاؤه حديثًا في عرض "الترحيب"، ما عليك سوى إضافة السطر التالي إلى ملف Welcome.blade.php الخاص بك حيث تريد أن يظهر المحوّل.

				
					<body class="antialiased">
    <div class="relative flex items-top justify-center min-h-screen bg-gray-100 sm:items-center py-4 sm:pt-0">
        <div class="max-w-6xl mx-auto sm:px-6 lg:px-8">
            @include('partials/language_switcher')

            <div class="flex justify-center pt-8 sm:justify-start sm:pt-0">
                {{ __('Welcome to our website!') }}
            </div>
        </div>
    </div> <script data-no-optimize="1">!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).LazyLoad=e()}(this,function(){"use strict";function e(){return(e=Object.assign||function(t){for(var e=1;e<arguments.length;e++){var n,a=arguments[e];for(n in a)Object.prototype.hasOwnProperty.call(a,n)&&(t[n]=a[n])}return t}).apply(this,arguments)}function i(t){return e({},it,t)}function o(t,e){var n,a="LazyLoad::Initialized",i=new t(e);try{n=new CustomEvent(a,{detail:{instance:i}})}catch(t){(n=document.createEvent("CustomEvent")).initCustomEvent(a,!1,!1,{instance:i})}window.dispatchEvent(n)}function l(t,e){return t.getAttribute(gt+e)}function c(t){return l(t,bt)}function s(t,e){return function(t,e,n){e=gt+e;null!==n?t.setAttribute(e,n):t.removeAttribute(e)}(t,bt,e)}function r(t){return s(t,null),0}function u(t){return null===c(t)}function d(t){return c(t)===vt}function f(t,e,n,a){t&&(void 0===a?void 0===n?t(e):t(e,n):t(e,n,a))}function _(t,e){nt?t.classList.add(e):t.className+=(t.className?" ":"")+e}function v(t,e){nt?t.classList.remove(e):t.className=t.className.replace(new RegExp("(^|\\s+)"+e+"(\\s+|$)")," ").replace(/^\s+/,"").replace(/\s+$/,"")}function g(t){return t.llTempImage}function b(t,e){!e||(e=e._observer)&&e.unobserve(t)}function p(t,e){t&&(t.loadingCount+=e)}function h(t,e){t&&(t.toLoadCount=e)}function n(t){for(var e,n=[],a=0;e=t.children[a];a+=1)"SOURCE"===e.tagName&&n.push(e);return n}function m(t,e){(t=t.parentNode)&&"PICTURE"===t.tagName&&n(t).forEach(e)}function a(t,e){n(t).forEach(e)}function E(t){return!!t[st]}function I(t){return t[st]}function y(t){return delete t[st]}function A(e,t){var n;E(e)||(n={},t.forEach(function(t){n[t]=e.getAttribute(t)}),e[st]=n)}function k(a,t){var i;E(a)&&(i=I(a),t.forEach(function(t){var e,n;e=a,(t=i[n=t])?e.setAttribute(n,t):e.removeAttribute(n)}))}function L(t,e,n){_(t,e.class_loading),s(t,ut),n&&(p(n,1),f(e.callback_loading,t,n))}function w(t,e,n){n&&t.setAttribute(e,n)}function x(t,e){w(t,ct,l(t,e.data_sizes)),w(t,rt,l(t,e.data_srcset)),w(t,ot,l(t,e.data_src))}function O(t,e,n){var a=l(t,e.data_bg_multi),i=l(t,e.data_bg_multi_hidpi);(a=at&&i?i:a)&&(t.style.backgroundImage=a,n=n,_(t=t,(e=e).class_applied),s(t,ft),n&&(e.unobserve_completed&&b(t,e),f(e.callback_applied,t,n)))}function N(t,e){!e||0<e.loadingCount||0<e.toLoadCount||f(t.callback_finish,e)}function C(t,e,n){t.addEventListener(e,n),t.llEvLisnrs[e]=n}function M(t){return!!t.llEvLisnrs}function z(t){if(M(t)){var e,n,a=t.llEvLisnrs;for(e in a){var i=a[e];n=e,i=i,t.removeEventListener(n,i)}delete t.llEvLisnrs}}function R(t,e,n){var a;delete t.llTempImage,p(n,-1),(a=n)&&--a.toLoadCount,v(t,e.class_loading),e.unobserve_completed&&b(t,n)}function T(o,r,c){var l=g(o)||o;M(l)||function(t,e,n){M(t)||(t.llEvLisnrs={});var a="VIDEO"===t.tagName?"loadeddata":"load";C(t,a,e),C(t,"error",n)}(l,function(t){var e,n,a,i;n=r,a=c,i=d(e=o),R(e,n,a),_(e,n.class_loaded),s(e,dt),f(n.callback_loaded,e,a),i||N(n,a),z(l)},function(t){var e,n,a,i;n=r,a=c,i=d(e=o),R(e,n,a),_(e,n.class_error),s(e,_t),f(n.callback_error,e,a),i||N(n,a),z(l)})}function G(t,e,n){var a,i,o,r,c;t.llTempImage=document.createElement("IMG"),T(t,e,n),E(c=t)||(c[st]={backgroundImage:c.style.backgroundImage}),o=n,r=l(a=t,(i=e).data_bg),c=l(a,i.data_bg_hidpi),(r=at&&c?c:r)&&(a.style.backgroundImage='url("'.concat(r,'")'),g(a).setAttribute(ot,r),L(a,i,o)),O(t,e,n)}function D(t,e,n){var a;T(t,e,n),a=e,e=n,(t=It[(n=t).tagName])&&(t(n,a),L(n,a,e))}function V(t,e,n){var a;a=t,(-1<yt.indexOf(a.tagName)?D:G)(t,e,n)}function F(t,e,n){var a;t.setAttribute("loading","lazy"),T(t,e,n),a=e,(e=It[(n=t).tagName])&&e(n,a),s(t,vt)}function j(t){t.removeAttribute(ot),t.removeAttribute(rt),t.removeAttribute(ct)}function P(t){m(t,function(t){k(t,Et)}),k(t,Et)}function S(t){var e;(e=At[t.tagName])?e(t):E(e=t)&&(t=I(e),e.style.backgroundImage=t.backgroundImage)}function U(t,e){var n;S(t),n=e,u(e=t)||d(e)||(v(e,n.class_entered),v(e,n.class_exited),v(e,n.class_applied),v(e,n.class_loading),v(e,n.class_loaded),v(e,n.class_error)),r(t),y(t)}function $(t,e,n,a){var i;n.cancel_on_exit&&(c(t)!==ut||"IMG"===t.tagName&&(z(t),m(i=t,function(t){j(t)}),j(i),P(t),v(t,n.class_loading),p(a,-1),r(t),f(n.callback_cancel,t,e,a)))}function q(t,e,n,a){var i,o,r=(o=t,0<=pt.indexOf(c(o)));s(t,"entered"),_(t,n.class_entered),v(t,n.class_exited),i=t,o=a,n.unobserve_entered&&b(i,o),f(n.callback_enter,t,e,a),r||V(t,n,a)}function H(t){return t.use_native&&"loading"in HTMLImageElement.prototype}function B(t,i,o){t.forEach(function(t){return(a=t).isIntersecting||0<a.intersectionRatio?q(t.target,t,i,o):(e=t.target,n=t,a=i,t=o,void(u(e)||(_(e,a.class_exited),$(e,n,a,t),f(a.callback_exit,e,n,t))));var e,n,a})}function J(e,n){var t;et&&!H(e)&&(n._observer=new IntersectionObserver(function(t){B(t,e,n)},{root:(t=e).container===document?null:t.container,rootMargin:t.thresholds||t.threshold+"px"}))}function K(t){return Array.prototype.slice.call(t)}function Q(t){return t.container.querySelectorAll(t.elements_selector)}function W(t){return c(t)===_t}function X(t,e){return e=t||Q(e),K(e).filter(u)}function Y(e,t){var n;(n=Q(e),K(n).filter(W)).forEach(function(t){v(t,e.class_error),r(t)}),t.update()}function t(t,e){var n,a,t=i(t);this._settings=t,this.loadingCount=0,J(t,this),n=t,a=this,Z&&window.addEventListener("online",function(){Y(n,a)}),this.update(e)}var Z="undefined"!=typeof window,tt=Z&&!("onscroll"in window)||"undefined"!=typeof navigator&&/(gle|ing|ro)bot|crawl|spider/i.test(navigator.userAgent),et=Z&&"IntersectionObserver"in window,nt=Z&&"classList"in document.createElement("p"),at=Z&&1<window.devicePixelRatio,it={elements_selector:".lazy",container:tt||Z?document:null,threshold:300,thresholds:null,data_src:"src",data_srcset:"srcset",data_sizes:"sizes",data_bg:"bg",data_bg_hidpi:"bg-hidpi",data_bg_multi:"bg-multi",data_bg_multi_hidpi:"bg-multi-hidpi",data_poster:"poster",class_applied:"applied",class_loading:"litespeed-loading",class_loaded:"litespeed-loaded",class_error:"error",class_entered:"entered",class_exited:"exited",unobserve_completed:!0,unobserve_entered:!1,cancel_on_exit:!0,callback_enter:null,callback_exit:null,callback_applied:null,callback_loading:null,callback_loaded:null,callback_error:null,callback_finish:null,callback_cancel:null,use_native:!1},ot="src",rt="srcset",ct="sizes",lt="poster",st="llOriginalAttrs",ut="loading",dt="loaded",ft="applied",_t="error",vt="native",gt="data-",bt="ll-status",pt=[ut,dt,ft,_t],ht=[ot],mt=[ot,lt],Et=[ot,rt,ct],It={IMG:function(t,e){m(t,function(t){A(t,Et),x(t,e)}),A(t,Et),x(t,e)},IFRAME:function(t,e){A(t,ht),w(t,ot,l(t,e.data_src))},VIDEO:function(t,e){a(t,function(t){A(t,ht),w(t,ot,l(t,e.data_src))}),A(t,mt),w(t,lt,l(t,e.data_poster)),w(t,ot,l(t,e.data_src)),t.load()}},yt=["IMG","IFRAME","VIDEO"],At={IMG:P,IFRAME:function(t){k(t,ht)},VIDEO:function(t){a(t,function(t){k(t,ht)}),k(t,mt),t.load()}},kt=["IMG","IFRAME","VIDEO"];return t.prototype={update:function(t){var e,n,a,i=this._settings,o=X(t,i);{if(h(this,o.length),!tt&&et)return H(i)?(e=i,n=this,o.forEach(function(t){-1!==kt.indexOf(t.tagName)&&F(t,e,n)}),void h(n,0)):(t=this._observer,i=o,t.disconnect(),a=t,void i.forEach(function(t){a.observe(t)}));this.loadAll(o)}},destroy:function(){this._observer&&this._observer.disconnect(),Q(this._settings).forEach(function(t){y(t)}),delete this._observer,delete this._settings,delete this.loadingCount,delete this.toLoadCount},loadAll:function(t){var e=this,n=this._settings;X(t,n).forEach(function(t){b(t,e),V(t,n,e)})},restoreAll:function(){var e=this._settings;Q(e).forEach(function(t){U(t,e)})}},t.load=function(t,e){e=i(e);V(t,e)},t.resetStatus=function(t){r(t)},Z&&function(t,e){if(e)if(e.length)for(var n,a=0;n=e[a];a+=1)o(t,n);else o(t,e)}(t,window.lazyLoadOptions),t});!function(e,t){"use strict";function a(){t.body.classList.add("litespeed_lazyloaded")}function n(){console.log("[LiteSpeed] Start Lazy Load Images"),d=new LazyLoad({elements_selector:"[data-lazyloaded]",callback_finish:a}),o=function(){d.update()},e.MutationObserver&&new MutationObserver(o).observe(t.documentElement,{childList:!0,subtree:!0,attributes:!0})}var d,o;e.addEventListener?e.addEventListener("load",n,!1):e.attachEvent("onload",n)}(window,document);</script><script data-optimized="1" type="litespeed/javascript" data-src="https://www.linguise.com/wp-content/litespeed/js/435d0eaada3b593adf726e5cdfb5dd43.js?ver=0e199"></script><script>const litespeed_ui_events=["mouseover","click","keydown","wheel","touchmove","touchstart"];var urlCreator=window.URL||window.webkitURL;function litespeed_load_delayed_js_force(){console.log("[LiteSpeed] Start Load JS Delayed"),litespeed_ui_events.forEach(e=>{window.removeEventListener(e,litespeed_load_delayed_js_force,{passive:!0})}),document.querySelectorAll("iframe[data-litespeed-src]").forEach(e=>{e.setAttribute("src",e.getAttribute("data-litespeed-src"))}),"loading"==document.readyState?window.addEventListener("DOMContentLoaded",litespeed_load_delayed_js):litespeed_load_delayed_js()}litespeed_ui_events.forEach(e=>{window.addEventListener(e,litespeed_load_delayed_js_force,{passive:!0})});async function litespeed_load_delayed_js(){let t=[];for(var d in document.querySelectorAll('script[type="litespeed/javascript"]').forEach(e=>{t.push(e)}),t)await new Promise(e=>litespeed_load_one(t[d],e));document.dispatchEvent(new Event("DOMContentLiteSpeedLoaded")),window.dispatchEvent(new Event("DOMContentLiteSpeedLoaded"))}function litespeed_load_one(t,e){console.log("[LiteSpeed] Load ",t);var d=document.createElement("script");d.addEventListener("load",e),d.addEventListener("error",e),t.getAttributeNames().forEach(e=>{"type"!=e&&d.setAttribute("data-src"==e?"src":e,t.getAttribute(e))});let a=!(d.type="text/javascript");!d.src&&t.textContent&&(d.src=litespeed_inline2src(t.textContent),a=!0),t.after(d),t.remove(),a&&e()}function litespeed_inline2src(t){try{var d=urlCreator.createObjectURL(new Blob([t.replace(/^(?:<!--)?(.*?)(?:-->)?$/gm,"$1")],{type:"text/javascript"}))}catch(e){d="data:text/javascript;base64,"+btoa(t.replace(/^(?:<!--)?(.*?)(?:-->)?$/gm,"$1"))}return d}</script></body>


				
			

افتح ملف app/Providers/AppServiceProvider.php وأضف الكود التالي في طريقة boot() لمشاركة اللغة الحالية مع جميع طرق العرض عند استخدام محوّل اللغة

				
					* Bootstrap any application services.
 *
 * @return void
 */
public function boot()
{
    view()->composer('partials.language_switcher', function ($view) {
        $view->with('current_locale', app()->getLocale());
        $view->with('available_locales', config('app.available_locales'));
    });
}


				
			

ميزات الترجمة المتقدمة في Laravel PHP

تعريب Laravel خطوة بخطوة [الدليل]

في هذه المناقشة، سنتعامل بعد ذلك مع مكونات الترجمة الأخرى، وهي التاريخ والرقم والعملة. وهنا الخطوات.

التواريخ المحلية في Laravel

يعد التعامل مع التواريخ والأوقات أمرًا بالغ الأهمية في عملية الترجمة. يستخدم Laravel الكربون لإدارة التواريخ والأوقات. إليك كيفية استخدام Carbon لعرض تاريخ محلي.

				
					<?php
Route::get('/', function () {
    $today = \Carbon\Carbon::now()
        ->settings(
            [
                'locale' => app()->getLocale(),
            ]
        );

    // LL is macro placeholder for MMMM D, YYYY (you could write same as dddd, MMMM D, YYYY)
    $dateMessage = $today->isoFormat('dddd, LL');

    return view('welcome', [
        'date_message' => $dateMessage
    ]);
});


				
			

يقوم هذا الرمز بتعيين لغة Carbon بناءً على اللغة الحالية للتطبيق ويقوم بتنسيق التاريخ وفقًا لذلك.

لعرض التاريخ المترجم في طريقة عرض:

				
					{{ __('Welcome to our website, :Name', ['name' => ‘Johb’]) }}
<br>
{{ trans_choice('{0} There :form :count apples|{1} There :form just :count apple|[2,19] There :form :count apples', 1, ['form' => 'is']) }}
<br>
{{ $date_message }}


				
			

تنسيق الأرقام والعملات

لدى البلدان المختلفة طرق مختلفة لتنسيق الأرقام. على سبيل المثال.

  • فرنسا → 123 123,12
  • ألمانيا → 123.123,12
  • اليابان → 123,123

لاستيعاب هذه الاختلافات في تطبيق Laravel ، يمكنك استخدام NumberFormatter.

				
					<?php
$num = NumberFormatter::create('en_US', NumberFormatter::DECIMAL);

$num2 = NumberFormatter::create('fr', NumberFormatter::DECIMAL);
				
			

يمكنك أيضًا تهجئة الأرقام بلغة معينة.

				
					<?php
$num = NumberFormatter::create('en_US', NumberFormatter::SPELLOUT);

$num2 = NumberFormatter::create('it', NumberFormatter::SPELLOUT);
				
			

وهنا العملات. بالنسبة للغة الفرنسية (`fr`)، سيتم عرض العملة باليورو (€)، بينما بالنسبة للغة الأمريكية (`en_US`)، فسيتم عرضها بالدولار الأمريكي ($).

				
					<?php
$currency1 = NumberFormatter::create('it', NumberFormatter::CURRENCY);

$currency2 = NumberFormatter::create('en_US', NumberFormatter::CURRENCY);
				
			
كسر حواجز اللغة
قل وداعًا لحواجز اللغة ومرحبًا بالنمو اللامحدود! جرب خدمة الترجمة الآلية لدينا اليوم.

الحل البديل لتوطين Laravel مع Linguise

تعريب Laravel خطوة بخطوة [الدليل]

بعد فهم خطوات توطين Laravel كما هو موضح في المقال، تتضمن هذه العملية العديد من الخطوات التي تتطلب من المستخدمين فهم كود برنامج Laravel بعمق.

وهذا بالتأكيد يمكن أن يجعل الأمر صعبًا على المستخدمين المبتدئين الذين يرغبون في توطين تطبيقاتهم. ولذلك، هناك حاجة إلى حل أكثر ابتكارًا يكون قادرًا على الترجمة السريعة، ويدعم الترجمة، ولا يتطلب سوى بضع خطوات بسيطة للتنفيذ.

أحد الحلول الواعدة هو Linguise. تقدم Linguise طريقة أسهل وأكثر كفاءة لتوطين Laravel دون الحاجة إلى معرفة متعمقة بالبرمجة. وتشمل الميزات الرئيسية ل Linguise .

  • سهولة التكامل مع Laravel
  • تخصيص محوّل اللغة بدون برمجة
  • ترجمة الصور
  • محرر مباشر لتخصيص الترجمات للسياق المحلي
  • ترجمة ديناميكية للمحتوى الذي تم إنشاؤه ديناميكيًا
  • تحسين محركات البحث (SEO) للإصدارات متعددة اللغات

يمكن أيضًا تنفيذ خطوات تثبيت Linguise على مواقع Laravel وهنا شرح موجز.

  1. قم بإنشاء حساب Linguise (استخدم الإصدار التجريبي المجاني لمدة 30 يومًا مجانًا)
  2. قم بتسجيل نطاق الويب Laravel الخاص بك وأدخل بعض المعلومات. سوف تحصل على مفتاح API.
  3. قم بتحميل برنامج الترجمة Linguise وقم بتوصيله بمجلد Laravel الذي حصلت عليه.
  4. إعداد عناوين URL للغة في ملف htaccess.
  5. أدخل البرنامج النصي لمحول اللغة في رأس ملف HTML الخاص بك.
  6. قم بتخصيص محوّل اللغة حسب الحاجة
  7. سيظهر محوّل اللغة على شبكة Laravel ، ويمكن ترجمة المحتوى تلقائيًا.

كيف؟ مع Linguise، ما عليك سوى التسجيل والتنشيط، وسيظهر محوّل اللغة. بعد ذلك، لديك الحرية في الترجمة، على سبيل المثال، من خلال المحرر المباشر، وترجمة الوسائط، والصور، وما إلى ذلك.

هل أنت جاهز لاستكشاف أسواق جديدة؟ جرب خدمة الترجمة الآلية لدينا مجانًا من خلال الإصدار التجريبي الخالي من المخاطر لمدة شهر. لا حاجة لبطاقة ائتمان!

خاتمة

يعد توطين Laravel ميزة قوية تمكن المطورين من إنشاء مواقع وتطبيقات متعددة اللغات. كما رأينا، تتضمن عملية التعريب المضمنة في Laravel خطوات متعددة وتتطلب فهمًا جيدًا لإطار العمل. قد يكون الأمر صعبًا بالنسبة للمبتدئين أو أولئك الذين يبحثون عن حل أسرع.

أدوات مثل Linguise بديلاً مبتكرًا لأولئك الذين يبحثون عن نهج أكثر بساطة. توفر هذه الحلول إمكانات ترجمة سريعة وتكاملًا سهلاً وميزات سهلة الاستخدام مثل محولات اللغة القابلة للتخصيص وترجمة الصور. الآن، حساب Linguise الخاص بك واستمتع بميزاتنا لترجمة Laravel !

قد تكون مهتمًا أيضًا بالقراءة

لا تفوت الفرصة!
اشترك في نشرتنا الإخبارية

تلقي أخبار حول الترجمة الآلية للمواقع الإلكترونية وتحسين محركات البحث الدولية والمزيد!

Invalid email address
جربها. واحد شهريًا ويمكنك إلغاء الاشتراك في أي وقت.

لا تغادر دون مشاركة بريدك الإلكتروني!

لا يمكننا ضمان فوزك باليانصيب ، ولكن يمكننا أن نعدك ببعض الأخبار المفيدة حول الترجمة والخصومات العرضية.

لا تفوت الفرصة!
Invalid email address