Поетапна локалізація Laravel [Посібник]

Виведи свій бізнес на новий рівень за допомогою глобального розширення. Бізнес-розвиток та зростання.
Зміст

Laravel локалізація - це потужний інструмент, який дозволяє розробникам створювати мультимовні веб-сайти. Впроваджуючи веб локалізацію у ваші Laravel проекти, ви можете забезпечити персоналізований користувацький досвід для відвідувачів з різних мовних середовищ, що в кінцевому підсумку розширить ваш вплив і покращить взаємодію з користувачами.

Ми проведемо вас через процес впровадження локалізації у вашому додатку Laravel і познайомимо вас із інструментом, який може спростити та покращити ваші зусилля з локалізації!

Чому ви повинні локалізувати свій веб-сайт Laravel ?

Чоловік у помаранчевому жилете, який тримає планшет із картою світу. Відображені різні прапори країн.

Ось декілька важливих причин, чому ви повинні локалізувати свій веб-сайт Laravel .

  • Охопіть глобальну аудиторію: Локалізуючи свій Laravel веб-сайт, ви можете розширити охоплення вашого застосунку на міжнародну аудиторію. Це дозволяє користувачам з різних країн та мовних середовищ розуміти та взаємодіяти з вашим вмістом.
  • Покращує користувацький досвід: Локалізація дозволяє користувачам взаємодіяти із застосунком їхньою рідною мовою, що суттєво покращує користувацький досвід. Це може збільшити показники залучення, зменшити показники відмов і збільшити конверсії.
  • Конкурентна перевага: На конкурентному світовому ринку надання додатків кількома мовами може забезпечити значну перевагу над конкурентами. Це свідчить про вашу прихильність до міжнародних ринків і може допомогти вам вийти на нові ринки ефективніше.
  • Покращує SEO: Добре локалізовані веб-сайти мають тенденцію краще ранжуватися у пошукових системах для пошукових запитів певною мовою. Це може збільшити трафік вашого блогу та онлайн-відимість на різних ринках з мультимовним перекладом.

Вимоги до багатомовної локалізації Laravel

Дві людини співпрацюють на великому екрані комп'ютера з різними додатками. Вони працюють разом.

Існує кілька вимог та кроків, які слід враховувати при впровадженні багатомовної локалізації у Laravel.

  • Щоб отримати останні функції локалізації, переконайтеся, що ви використовуєте останню версію Laravel (наприклад, версію 10.x).
  • Базове розуміння PHP і фреймворку Laravel буде корисним у процесі реалізації.
  • Налаштуйте локальне середовище розробки або сервер, який підтримує Laravel, включаючи веб-сервер та базу даних.
  • Визначте мови, які буде підтримувати ваша програма з самого початку.

Прості переклади Laravel

Людина працює на ноутбуці. Веб-серфінг на екрані.

Після розуміння вимог, яким необхідно відповідати перед перекладом застосунку або веб-сторінки Laravel , ми надамо кілька кроків для простого перекладу Laravel .

Щоб зробити це, відкрийте файл перегляду, який ви хочете локалізувати, наприклад, resources/views/welcome.blade.php. Потім замініть тег body наступним кодом.

				
					<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">window.lazyLoadOptions=Object.assign({},{threshold:300},window.lazyLoadOptions||{});!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 o(t){return e({},at,t)}function l(t,e){return t.getAttribute(gt+e)}function c(t){return l(t,vt)}function s(t,e){return function(t,e,n){e=gt+e;null!==n?t.setAttribute(e,n):t.removeAttribute(e)}(t,vt,e)}function i(t){return s(t,null),0}function r(t){return null===c(t)}function u(t){return c(t)===_t}function d(t,e,n,a){t&&(void 0===a?void 0===n?t(e):t(e,n):t(e,n,a))}function f(t,e){et?t.classList.add(e):t.className+=(t.className?" ":"")+e}function _(t,e){et?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 v(t,e){!e||(e=e._observer)&&e.unobserve(t)}function b(t,e){t&&(t.loadingCount+=e)}function p(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 h(t,e){(t=t.parentNode)&&"PICTURE"===t.tagName&&n(t).forEach(e)}function a(t,e){n(t).forEach(e)}function m(t){return!!t[lt]}function E(t){return t[lt]}function I(t){return delete t[lt]}function y(e,t){var n;m(e)||(n={},t.forEach(function(t){n[t]=e.getAttribute(t)}),e[lt]=n)}function L(a,t){var o;m(a)&&(o=E(a),t.forEach(function(t){var e,n;e=a,(t=o[n=t])?e.setAttribute(n,t):e.removeAttribute(n)}))}function k(t,e,n){f(t,e.class_loading),s(t,st),n&&(b(n,1),d(e.callback_loading,t,n))}function A(t,e,n){n&&t.setAttribute(e,n)}function O(t,e){A(t,rt,l(t,e.data_sizes)),A(t,it,l(t,e.data_srcset)),A(t,ot,l(t,e.data_src))}function w(t,e,n){var a=l(t,e.data_bg_multi),o=l(t,e.data_bg_multi_hidpi);(a=nt&&o?o:a)&&(t.style.backgroundImage=a,n=n,f(t=t,(e=e).class_applied),s(t,dt),n&&(e.unobserve_completed&&v(t,e),d(e.callback_applied,t,n)))}function x(t,e){!e||0<e.loadingCount||0<e.toLoadCount||d(t.callback_finish,e)}function M(t,e,n){t.addEventListener(e,n),t.llEvLisnrs[e]=n}function N(t){return!!t.llEvLisnrs}function z(t){if(N(t)){var e,n,a=t.llEvLisnrs;for(e in a){var o=a[e];n=e,o=o,t.removeEventListener(n,o)}delete t.llEvLisnrs}}function C(t,e,n){var a;delete t.llTempImage,b(n,-1),(a=n)&&--a.toLoadCount,_(t,e.class_loading),e.unobserve_completed&&v(t,n)}function R(i,r,c){var l=g(i)||i;N(l)||function(t,e,n){N(t)||(t.llEvLisnrs={});var a="VIDEO"===t.tagName?"loadeddata":"load";M(t,a,e),M(t,"error",n)}(l,function(t){var e,n,a,o;n=r,a=c,o=u(e=i),C(e,n,a),f(e,n.class_loaded),s(e,ut),d(n.callback_loaded,e,a),o||x(n,a),z(l)},function(t){var e,n,a,o;n=r,a=c,o=u(e=i),C(e,n,a),f(e,n.class_error),s(e,ft),d(n.callback_error,e,a),o||x(n,a),z(l)})}function T(t,e,n){var a,o,i,r,c;t.llTempImage=document.createElement("IMG"),R(t,e,n),m(c=t)||(c[lt]={backgroundImage:c.style.backgroundImage}),i=n,r=l(a=t,(o=e).data_bg),c=l(a,o.data_bg_hidpi),(r=nt&&c?c:r)&&(a.style.backgroundImage='url("'.concat(r,'")'),g(a).setAttribute(ot,r),k(a,o,i)),w(t,e,n)}function G(t,e,n){var a;R(t,e,n),a=e,e=n,(t=Et[(n=t).tagName])&&(t(n,a),k(n,a,e))}function D(t,e,n){var a;a=t,(-1<It.indexOf(a.tagName)?G:T)(t,e,n)}function S(t,e,n){var a;t.setAttribute("loading","lazy"),R(t,e,n),a=e,(e=Et[(n=t).tagName])&&e(n,a),s(t,_t)}function V(t){t.removeAttribute(ot),t.removeAttribute(it),t.removeAttribute(rt)}function j(t){h(t,function(t){L(t,mt)}),L(t,mt)}function F(t){var e;(e=yt[t.tagName])?e(t):m(e=t)&&(t=E(e),e.style.backgroundImage=t.backgroundImage)}function P(t,e){var n;F(t),n=e,r(e=t)||u(e)||(_(e,n.class_entered),_(e,n.class_exited),_(e,n.class_applied),_(e,n.class_loading),_(e,n.class_loaded),_(e,n.class_error)),i(t),I(t)}function U(t,e,n,a){var o;n.cancel_on_exit&&(c(t)!==st||"IMG"===t.tagName&&(z(t),h(o=t,function(t){V(t)}),V(o),j(t),_(t,n.class_loading),b(a,-1),i(t),d(n.callback_cancel,t,e,a)))}function $(t,e,n,a){var o,i,r=(i=t,0<=bt.indexOf(c(i)));s(t,"entered"),f(t,n.class_entered),_(t,n.class_exited),o=t,i=a,n.unobserve_entered&&v(o,i),d(n.callback_enter,t,e,a),r||D(t,n,a)}function q(t){return t.use_native&&"loading"in HTMLImageElement.prototype}function H(t,o,i){t.forEach(function(t){return(a=t).isIntersecting||0<a.intersectionRatio?$(t.target,t,o,i):(e=t.target,n=t,a=o,t=i,void(r(e)||(f(e,a.class_exited),U(e,n,a,t),d(a.callback_exit,e,n,t))));var e,n,a})}function B(e,n){var t;tt&&!q(e)&&(n._observer=new IntersectionObserver(function(t){H(t,e,n)},{root:(t=e).container===document?null:t.container,rootMargin:t.thresholds||t.threshold+"px"}))}function J(t){return Array.prototype.slice.call(t)}function K(t){return t.container.querySelectorAll(t.elements_selector)}function Q(t){return c(t)===ft}function W(t,e){return e=t||K(e),J(e).filter(r)}function X(e,t){var n;(n=K(e),J(n).filter(Q)).forEach(function(t){_(t,e.class_error),i(t)}),t.update()}function t(t,e){var n,a,t=o(t);this._settings=t,this.loadingCount=0,B(t,this),n=t,a=this,Y&&window.addEventListener("online",function(){X(n,a)}),this.update(e)}var Y="undefined"!=typeof window,Z=Y&&!("onscroll"in window)||"undefined"!=typeof navigator&&/(gle|ing|ro)bot|crawl|spider/i.test(navigator.userAgent),tt=Y&&"IntersectionObserver"in window,et=Y&&"classList"in document.createElement("p"),nt=Y&&1<window.devicePixelRatio,at={elements_selector:".lazy",container:Z||Y?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",it="srcset",rt="sizes",ct="poster",lt="llOriginalAttrs",st="loading",ut="loaded",dt="applied",ft="error",_t="native",gt="data-",vt="ll-status",bt=[st,ut,dt,ft],pt=[ot],ht=[ot,ct],mt=[ot,it,rt],Et={IMG:function(t,e){h(t,function(t){y(t,mt),O(t,e)}),y(t,mt),O(t,e)},IFRAME:function(t,e){y(t,pt),A(t,ot,l(t,e.data_src))},VIDEO:function(t,e){a(t,function(t){y(t,pt),A(t,ot,l(t,e.data_src))}),y(t,ht),A(t,ct,l(t,e.data_poster)),A(t,ot,l(t,e.data_src)),t.load()}},It=["IMG","IFRAME","VIDEO"],yt={IMG:j,IFRAME:function(t){L(t,pt)},VIDEO:function(t){a(t,function(t){L(t,pt)}),L(t,ht),t.load()}},Lt=["IMG","IFRAME","VIDEO"];return t.prototype={update:function(t){var e,n,a,o=this._settings,i=W(t,o);{if(p(this,i.length),!Z&&tt)return q(o)?(e=o,n=this,i.forEach(function(t){-1!==Lt.indexOf(t.tagName)&&S(t,e,n)}),void p(n,0)):(t=this._observer,o=i,t.disconnect(),a=t,void o.forEach(function(t){a.observe(t)}));this.loadAll(i)}},destroy:function(){this._observer&&this._observer.disconnect(),K(this._settings).forEach(function(t){I(t)}),delete this._observer,delete this._settings,delete this.loadingCount,delete this.toLoadCount},loadAll:function(t){var e=this,n=this._settings;W(t,n).forEach(function(t){v(t,e),D(t,n,e)})},restoreAll:function(){var e=this._settings;K(e).forEach(function(t){P(t,e)})}},t.load=function(t,e){e=o(e);D(t,e)},t.resetStatus=function(t){i(t)},t}),function(t,e){"use strict";function n(){e.body.classList.add("litespeed_lazyloaded")}function a(){console.log("[LiteSpeed] Start Lazy Load"),o=new LazyLoad(Object.assign({},t.lazyLoadOptions||{},{elements_selector:"[data-lazyloaded]",callback_finish:n})),i=function(){o.update()},t.MutationObserver&&new MutationObserver(i).observe(e.documentElement,{childList:!0,subtree:!0,attributes:!0})}var o,i;t.addEventListener?t.addEventListener("load",a,!1):t.attachEvent("onload",a)}(window,document);</script><script data-no-optimize="1">window.litespeed_ui_events=window.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><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/91733db3849bd555826dc24780e4dad1.js?ver=0275f"></script></body>
				
			

Як ви бачите, зазначений вище текст наразі написано безпосередньо у коді. Це менш ефективно і ускладнює переклад веб-сайтів різними мовами (інтернаціоналізація).

Ми збираємося зробити наведений вище текст більш гнучким, щоб його можна було легко адаптувати до різних мов. Laravel надає дуже корисну функцію для цього; систему локалізації. Як перший крок замініть існуючий текст наступним кодом.

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

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',

				
			

Пояснення вище ключів має бути зрозумілим. У підсумку, ключ мови зберігає мову за замовчуванням для вашого застосунку (якщо інша мова не вказана в коді). Резервна мова активується, якщо у вашому застосунку запитується неіснуюча мова.

Тепер давайте додамо новий ключ до цього файлу, щоб надати список усіх підтримуваних локалізацій.

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

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


				
			

На цей момент ми спробували підтримати на веб-сайті 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 ще не налаштовано для зміни локальної мови, тому зараз ми будемо обробляти переклад безпосередньо в маршруті. Змініть маршрут вітання за замовчуванням всередині файлу routes/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 або створити його, виконавши команду artisan 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}. Вибрана локаль буде збережена у сесії, і користувачі будуть перенаправлені назад на попередню сторінку (як обробляється проміжним програмним забезпеченням Localization). 

Щоб перевірити це, перейдіть до localhost/language/it (за умови, що cookie сесії активний у вашому браузері), і ви побачите перекладений контент. Ви можете переміщатися сайтом або оновити сторінку, і вибрана мова залишиться в силі.

Реалізація перемикача мов

Тепер нам потрібно надати користувачеві можливість кліком змінити перемикач мови Laravel веб, а не вимагати від них введення кодів локалі в 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», просто додайте наступний рядок до вашого файлу 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">window.lazyLoadOptions=Object.assign({},{threshold:300},window.lazyLoadOptions||{});!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 o(t){return e({},at,t)}function l(t,e){return t.getAttribute(gt+e)}function c(t){return l(t,vt)}function s(t,e){return function(t,e,n){e=gt+e;null!==n?t.setAttribute(e,n):t.removeAttribute(e)}(t,vt,e)}function i(t){return s(t,null),0}function r(t){return null===c(t)}function u(t){return c(t)===_t}function d(t,e,n,a){t&&(void 0===a?void 0===n?t(e):t(e,n):t(e,n,a))}function f(t,e){et?t.classList.add(e):t.className+=(t.className?" ":"")+e}function _(t,e){et?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 v(t,e){!e||(e=e._observer)&&e.unobserve(t)}function b(t,e){t&&(t.loadingCount+=e)}function p(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 h(t,e){(t=t.parentNode)&&"PICTURE"===t.tagName&&n(t).forEach(e)}function a(t,e){n(t).forEach(e)}function m(t){return!!t[lt]}function E(t){return t[lt]}function I(t){return delete t[lt]}function y(e,t){var n;m(e)||(n={},t.forEach(function(t){n[t]=e.getAttribute(t)}),e[lt]=n)}function L(a,t){var o;m(a)&&(o=E(a),t.forEach(function(t){var e,n;e=a,(t=o[n=t])?e.setAttribute(n,t):e.removeAttribute(n)}))}function k(t,e,n){f(t,e.class_loading),s(t,st),n&&(b(n,1),d(e.callback_loading,t,n))}function A(t,e,n){n&&t.setAttribute(e,n)}function O(t,e){A(t,rt,l(t,e.data_sizes)),A(t,it,l(t,e.data_srcset)),A(t,ot,l(t,e.data_src))}function w(t,e,n){var a=l(t,e.data_bg_multi),o=l(t,e.data_bg_multi_hidpi);(a=nt&&o?o:a)&&(t.style.backgroundImage=a,n=n,f(t=t,(e=e).class_applied),s(t,dt),n&&(e.unobserve_completed&&v(t,e),d(e.callback_applied,t,n)))}function x(t,e){!e||0<e.loadingCount||0<e.toLoadCount||d(t.callback_finish,e)}function M(t,e,n){t.addEventListener(e,n),t.llEvLisnrs[e]=n}function N(t){return!!t.llEvLisnrs}function z(t){if(N(t)){var e,n,a=t.llEvLisnrs;for(e in a){var o=a[e];n=e,o=o,t.removeEventListener(n,o)}delete t.llEvLisnrs}}function C(t,e,n){var a;delete t.llTempImage,b(n,-1),(a=n)&&--a.toLoadCount,_(t,e.class_loading),e.unobserve_completed&&v(t,n)}function R(i,r,c){var l=g(i)||i;N(l)||function(t,e,n){N(t)||(t.llEvLisnrs={});var a="VIDEO"===t.tagName?"loadeddata":"load";M(t,a,e),M(t,"error",n)}(l,function(t){var e,n,a,o;n=r,a=c,o=u(e=i),C(e,n,a),f(e,n.class_loaded),s(e,ut),d(n.callback_loaded,e,a),o||x(n,a),z(l)},function(t){var e,n,a,o;n=r,a=c,o=u(e=i),C(e,n,a),f(e,n.class_error),s(e,ft),d(n.callback_error,e,a),o||x(n,a),z(l)})}function T(t,e,n){var a,o,i,r,c;t.llTempImage=document.createElement("IMG"),R(t,e,n),m(c=t)||(c[lt]={backgroundImage:c.style.backgroundImage}),i=n,r=l(a=t,(o=e).data_bg),c=l(a,o.data_bg_hidpi),(r=nt&&c?c:r)&&(a.style.backgroundImage='url("'.concat(r,'")'),g(a).setAttribute(ot,r),k(a,o,i)),w(t,e,n)}function G(t,e,n){var a;R(t,e,n),a=e,e=n,(t=Et[(n=t).tagName])&&(t(n,a),k(n,a,e))}function D(t,e,n){var a;a=t,(-1<It.indexOf(a.tagName)?G:T)(t,e,n)}function S(t,e,n){var a;t.setAttribute("loading","lazy"),R(t,e,n),a=e,(e=Et[(n=t).tagName])&&e(n,a),s(t,_t)}function V(t){t.removeAttribute(ot),t.removeAttribute(it),t.removeAttribute(rt)}function j(t){h(t,function(t){L(t,mt)}),L(t,mt)}function F(t){var e;(e=yt[t.tagName])?e(t):m(e=t)&&(t=E(e),e.style.backgroundImage=t.backgroundImage)}function P(t,e){var n;F(t),n=e,r(e=t)||u(e)||(_(e,n.class_entered),_(e,n.class_exited),_(e,n.class_applied),_(e,n.class_loading),_(e,n.class_loaded),_(e,n.class_error)),i(t),I(t)}function U(t,e,n,a){var o;n.cancel_on_exit&&(c(t)!==st||"IMG"===t.tagName&&(z(t),h(o=t,function(t){V(t)}),V(o),j(t),_(t,n.class_loading),b(a,-1),i(t),d(n.callback_cancel,t,e,a)))}function $(t,e,n,a){var o,i,r=(i=t,0<=bt.indexOf(c(i)));s(t,"entered"),f(t,n.class_entered),_(t,n.class_exited),o=t,i=a,n.unobserve_entered&&v(o,i),d(n.callback_enter,t,e,a),r||D(t,n,a)}function q(t){return t.use_native&&"loading"in HTMLImageElement.prototype}function H(t,o,i){t.forEach(function(t){return(a=t).isIntersecting||0<a.intersectionRatio?$(t.target,t,o,i):(e=t.target,n=t,a=o,t=i,void(r(e)||(f(e,a.class_exited),U(e,n,a,t),d(a.callback_exit,e,n,t))));var e,n,a})}function B(e,n){var t;tt&&!q(e)&&(n._observer=new IntersectionObserver(function(t){H(t,e,n)},{root:(t=e).container===document?null:t.container,rootMargin:t.thresholds||t.threshold+"px"}))}function J(t){return Array.prototype.slice.call(t)}function K(t){return t.container.querySelectorAll(t.elements_selector)}function Q(t){return c(t)===ft}function W(t,e){return e=t||K(e),J(e).filter(r)}function X(e,t){var n;(n=K(e),J(n).filter(Q)).forEach(function(t){_(t,e.class_error),i(t)}),t.update()}function t(t,e){var n,a,t=o(t);this._settings=t,this.loadingCount=0,B(t,this),n=t,a=this,Y&&window.addEventListener("online",function(){X(n,a)}),this.update(e)}var Y="undefined"!=typeof window,Z=Y&&!("onscroll"in window)||"undefined"!=typeof navigator&&/(gle|ing|ro)bot|crawl|spider/i.test(navigator.userAgent),tt=Y&&"IntersectionObserver"in window,et=Y&&"classList"in document.createElement("p"),nt=Y&&1<window.devicePixelRatio,at={elements_selector:".lazy",container:Z||Y?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",it="srcset",rt="sizes",ct="poster",lt="llOriginalAttrs",st="loading",ut="loaded",dt="applied",ft="error",_t="native",gt="data-",vt="ll-status",bt=[st,ut,dt,ft],pt=[ot],ht=[ot,ct],mt=[ot,it,rt],Et={IMG:function(t,e){h(t,function(t){y(t,mt),O(t,e)}),y(t,mt),O(t,e)},IFRAME:function(t,e){y(t,pt),A(t,ot,l(t,e.data_src))},VIDEO:function(t,e){a(t,function(t){y(t,pt),A(t,ot,l(t,e.data_src))}),y(t,ht),A(t,ct,l(t,e.data_poster)),A(t,ot,l(t,e.data_src)),t.load()}},It=["IMG","IFRAME","VIDEO"],yt={IMG:j,IFRAME:function(t){L(t,pt)},VIDEO:function(t){a(t,function(t){L(t,pt)}),L(t,ht),t.load()}},Lt=["IMG","IFRAME","VIDEO"];return t.prototype={update:function(t){var e,n,a,o=this._settings,i=W(t,o);{if(p(this,i.length),!Z&&tt)return q(o)?(e=o,n=this,i.forEach(function(t){-1!==Lt.indexOf(t.tagName)&&S(t,e,n)}),void p(n,0)):(t=this._observer,o=i,t.disconnect(),a=t,void o.forEach(function(t){a.observe(t)}));this.loadAll(i)}},destroy:function(){this._observer&&this._observer.disconnect(),K(this._settings).forEach(function(t){I(t)}),delete this._observer,delete this._settings,delete this.loadingCount,delete this.toLoadCount},loadAll:function(t){var e=this,n=this._settings;W(t,n).forEach(function(t){v(t,e),D(t,n,e)})},restoreAll:function(){var e=this._settings;K(e).forEach(function(t){P(t,e)})}},t.load=function(t,e){e=o(e);D(t,e)},t.resetStatus=function(t){i(t)},t}),function(t,e){"use strict";function n(){e.body.classList.add("litespeed_lazyloaded")}function a(){console.log("[LiteSpeed] Start Lazy Load"),o=new LazyLoad(Object.assign({},t.lazyLoadOptions||{},{elements_selector:"[data-lazyloaded]",callback_finish:n})),i=function(){o.update()},t.MutationObserver&&new MutationObserver(i).observe(e.documentElement,{childList:!0,subtree:!0,attributes:!0})}var o,i;t.addEventListener?t.addEventListener("load",a,!1):t.attachEvent("onload",a)}(window,document);</script><script data-no-optimize="1">window.litespeed_ui_events=window.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><script data-optimized="1" type="litespeed/javascript" data-src="https://www.linguise.com/wp-content/litespeed/js/91733db3849bd555826dc24780e4dad1.js?ver=0275f"></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 використовує Carbon для управління датами і часом. Ось як ви можете використовувати 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 .

Це, безумовно, може ускладнити життя початківцям, які хочуть локалізувати свої застосунки. Тому потрібне більш інноваційне рішення, здатне швидко перекладати, підтримувати локалізацію і вимагати лише кількох простих кроків для реалізації.

Одним із перспективних рішень є 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вам потрібно лише зареєструватися та активувати, і перемикач мови з'явиться. Після цього ви можете вільно локалізувати, наприклад, через живий редактор, перекладати медіа, зображення тощо.

Готові досліджувати нові ринки? Спробуйте наш автоматичний сервіс перекладу безкоштовно з нашим 1-місячним безризиковим пробним періодом. Номер кредитної картки не потрібен!

Висновок

Локалізація Laravel - це потужна функція, яка дозволяє розробникам створювати багатомовні веб-сайти та додатки. Як ми бачили, вбудований процес локалізації Laravel включає кілька етапів і вимагає хорошого розуміння фреймворку. Це може бути складно для початківців або тих, хто шукає швидше рішення.

Інструменти на кшталт Linguise пропонують інноваційну альтернативу для тих, хто шукає більш спрощений підхід. Ці рішення пропонують можливості швидкого перекладу, легку інтеграцію та зручні функції, такі як настроювані перемикачі мови та переклад зображень. Тепер, створіть свій Linguise обліковий запис та скористайтеся нашою функцією для локалізації вашого Laravel

Вас також може зацікавити читання

Не пропустіть!
Підпишіться на нашу розсилку

Отримуйте новини про автоматичний переклад веб-сайтів, міжнародне SEO та багато іншого!

Invalid email address
Спробуйте. Один раз на місяць, і ви можете відмовитися від підписки в будь-який момент.

Не йдіть без поділу своєю електронною поштою!

Ми не можемо гарантувати, що ви виграєте в лотерею, але ми можемо пообіцяти цікаві інформаційні новини щодо перекладу та періодичні знижки.

Не пропустіть!
Invalid email address