Покрокова локалізація 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/e21c417ddc5d9e2a026725d14a9fa8f0.js?ver=fd4ac"></script></body>
				
			

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

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

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

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

Налаштування локалізацій у багатомовному веб-середовищі Laravel

Двоє людей працюють за екранами комп&#39;ютерів. Вони взаємодіють з великими дисплеями.

Але як 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',

				
			

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

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

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

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


				
			

На цьому етапі ми спробували Laravel web для підтримки трьох мов, а саме англійської, італійської та французької.

Огляд файлів перекладу Laravel

Жінка вказує на великий екран комп&#39;ютера, на якому відображаються різні барвисті значки. Екран має білий фон із синіми та фіолетовими значками.

У 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}. Вибрана локалізація буде збережена в сеансі, а користувачі будуть перенаправлені назад на попередню сторінку (як це обробляє проміжне програмне забезпечення локалізації). 

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

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

Тепер нам потрібно надати користувачеві опцію зміни мови в перемикачі 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">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/e21c417ddc5d9e2a026725d14a9fa8f0.js?ver=fd4ac"></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