Instrukcja: lokalizacja Laravel krok po kroku [Przewodnik]

Przenieś swój biznes na wyższy poziom dzięki globalnej ekspansji. Rozwój i wzrost biznesu.
Spis Treści

Laravel lokalizację internetową w projektach Laravel, możesz zapewnić spersonalizowane doświadczenie użytkownikom z różnych środowisk językowych, ostatecznie rozszerzając swój zasięg i poprawiając zaangażowanie użytkowników.

Prowadzimy Cię przez proces wdrażania lokalizacji w aplikacji Laravel i przedstawiamy narzędzie, które może uprościć i usprawnić Twoje wysiłki lokalizacyjne!

Dlaczego warto lokalizować stronę internetową Laravel ?

Mężczyzna w pomarańczowej kamizelce trzymający tablet z mapą świata. Widoczne są różne flagi państw.

Oto kilka ważnych powodów, dla których warto zlokalizować witrynę Laravel .

  • Dotrzyj do globalnej publiczności: Zlokalizuj swoją witrynę Laravel
  • Poprawia doświadczenie użytkownika: Lokalizacja umożliwia użytkownikom interakcję z aplikacją w ich ojczystym języku, co znacznie poprawia doświadczenie użytkownika. Może to zwiększyć wskaźniki zaangażowania, zmniejszyć współczynniki odrzuceń i zwiększyć konwersje.
  • Przewaga konkurencyjna: Na konkurencyjnym rynku globalnym, oferowanie aplikacji w wielu językach może zapewnić znaczną przewagę nad konkurentami. To pokazuje twoje zaangażowanie na rynkach międzynarodowych i może pomóc ci wejść na nowe rynki bardziej efektywnie.
  • Poprawia SEO: Dobrze zlokalizowane strony internetowe mają tendencję do lepszego pozycjonowania w wyszukiwarkach dla zapytań w danym języku. To może zwiększyć ruch na twoim blogu i widoczność online na różnych rynkach z tłumaczeniem wielojęzycznym.

Wymagania dla wielojęzycznej lokalizacji Laravel

Dwie osoby współpracujące przy dużym ekranie komputera z różnymi aplikacjami. Wydają się pracować razem.

Istnieje kilka wymagań i kroków do rozważenia przy implementacji wielojęzycznej lokalizacji w Laravel.

  • Aby uzyskać najnowsze funkcje lokalizacji, upewnij się, że używasz najnowszej wersji Laravel (np. wersja 10.x).
  • Podstawowa znajomość PHP i frameworka Laravel będzie pomocna w procesie implementacji.
  • Ustaw lokalne środowisko programistyczne lub serwer, który obsługuje Laravel, w tym serwer WWW i bazę danych.
  • Określ języki, które Twoja aplikacja będzie obsługiwać od samego początku.

Proste tłumaczenia Laravel

Mężczyzna pracujący na laptopie. Przeglądanie stron internetowych na ekranie.

Po zrozumieniu wymagań, które muszą być spełnione przed przetłumaczeniem aplikacji Laravel lub sieci, przedstawimy kilka kroków do prostego tłumaczenia Laravel .

Aby to zrobić, otwórz plik widoku, który chcesz zlokalizować, na przykład resources/views/welcome.blade.php. Następnie zastąp tag body poniższym kodem.

				
					<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/5cde28a74717112195c10502c32f111f.js?ver=2483c"></script></body>
				
			

Jak widać, powyższy tekst jest obecnie zapisany bezpośrednio w kodzie. Jest to mniej efektywne i utrudnia tłumaczenie stron internetowych na różne języki (internacjonalizacja).

Zamierzamy uczynić powyższy tekst bardziej elastycznym, aby można go było łatwo dostosować do różnych języków. Laravel zapewnia bardzo przydatną funkcję; system lokalizacji. Jako pierwszy krok zastąp istniejący tekst poniższym kodem.

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

Laravel wyświetli powyższy tekst domyślnie i wyszuka tłumaczenie, jeśli użytkownik wybierze język inny niż angielski. W tym przypadku angielski będzie używany jako domyślny język aplikacji.

Konfigurowanie ustawień regionalnych w Laravel wielojęzycznej sieci

Dwie osoby pracujące przy ekranach komputerów. Interagują z dużymi wyświetlaczami.

Ale jak Laravel określa bieżący język lub wie, które języki są dostępne w aplikacji? Sprawdza ustawienia lokalizacji w pliku config/app.php. Otwórz ten plik i poszukaj następujących dwóch kluczy.

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

				
			

Wyjaśnienie powyżej kluczy powinno być jasne. W skrócie, klucz lokalizacji zawiera domyślną lokalizację dla Twojej aplikacji (jeśli nie określono innej lokalizacji w kodzie). fallback_locale jest aktywowany, jeśli w Twojej aplikacji zażądano nieistniejącej lokalizacji.

Teraz dodajmy nowy klucz do tego pliku, aby zapewnić listę wszystkich obsługiwanych lokalizacji.

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

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


				
			

W tym momencie próbowaliśmy Laravel web, aby wesprzeć trzy języki, a mianowicie angielski, włoski i francuski.

Przegląd plików tłumaczeń Laravel

Kobieta wskazująca na duży ekran komputera wyświetlający różne kolorowe ikony. Ekran ma białe tło z niebieskimi i fioletowymi ikonami.

W Laravel, jak i w wielu innych frameworkach, tłumaczenia na różne języki są przechowywane w oddzielnych plikach. Do organizowania tych plików tłumaczeń używa się dwóch metod.

Starsza metoda przechowuje pliki w następującej strukturze: zasoby/lang/{en,fr,it}/{myfile.php}. Nowsza metoda używa plików JSON, takich jak zasoby/lang/{fr.json, it.json}. Ten artykuł skupi się na nowszej metodzie, choć zasady są podobne dla starszej metody, poza różnicami w nazewnictwie i dostępie do kluczy tłumaczeniowych.

Dla języków z różnicami regionalnymi, należy nazwać katalogi lub pliki językowe zgodnie ze standardem ISO 15897. Na przykład, brytyjski angielski będzie nazwany en_GB zamiast en-gb.

Informacje ogólne

W Laravel, jak w wielu frameworkach, tłumaczenia na różne języki są przechowywane w oddzielnych plikach. Istnieją dwie podstawowe metody organizowania plików tłumaczeń Laravel .

  1. Starsze podejście polega na przechowywaniu plików w ścieżce: resources/lang/{en,fr,it}/{myfile.php}.
  2. Nowoczesne podejście wykorzystuje pliki resources/lang/{fr.json, it.json}.

Ten artykuł skupi się na drugiej metodzie, choć zasady mają zastosowanie do obu (z różnicami w nazewnictwie i dostępie do kluczy tłumaczeń).

Dla języków, które różnią się w zależności od regionu, zaleca się nazywanie katalogów/plików językowych zgodnie ze standardami ISO 15897. Na przykład, brytyjski angielski będzie oznaczony jako en_GB, a nie en-gb.

Tworzenie plików tłumaczeń Laravel

Po skonfigurowaniu ustawień regionalnych dla naszej aplikacji możemy przystąpić do tłumaczenia naszego domyślnego komunikatu powitalnego.

Zacznijmy od utworzenia nowych plików lokalizacyjnych w formacie JSON w katalogu resources/lang. Najpierw utworzymy plik resources/lang/it.json i wypełnimy go odpowiednimi tłumaczeniami.

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

				
			

Następnie dodaj plik resources/lang/fr.json.

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

				
			

Jak można zaobserwować, konsekwentnie odwołujemy się do domyślnej wiadomości z pliku welcome.blade.php ({{ __(‘Witamy na stronie Linguise !’). }}). Nie ma potrzeby tworzenia pliku en.json, ponieważ Laravel automatycznie rozpoznaje, że domyślne wiadomości są w języku angielskim.

Ustawianie przełącznika języka w wielojęzycznej aplikacji Laravel

Ludzie wchodzący w interakcję z dużym interfejsem poczty elektronicznej.

Ponadto Laravel nie jest jeszcze skonfigurowany do nadpisywania lokalnego języka, więc na razie będziemy obsługiwać tłumaczenie bezpośrednio w ramach trasy. Zmodyfikuj domyślną trasę powitalną wewnątrz pliku routes/web.php w ten sposób.

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

W tym przypadku przechwytujemy opcjonalny parametr GET locale i ustawiamy bieżącą lokalizację na podstawie niego (jeśli żądana lokalizacja jest obsługiwana).

Teraz możesz odwiedzić swoją stronę internetową i dołączyć dowolny z obsługiwanych języków jako pierwszy segment w adresie URL. Na przykład przejście do localhost/it lub localhost/fr wyświetli zlokalizowaną treść. Jeśli nie określisz lokalizacji lub wybierzesz taką, która nie jest obsługiwana, Laravel domyślnie ustawi język angielski (en).

Oprogramowanie pośredniczące lokalizacji dla Laravel

Włączanie lokalizacji do każdego adresu URL może nie być idealne i może zaburzyć atrakcyjność wizualną witryny. Aby rozwiązać ten problem, utworzymy przełącznik języka i wykorzystamy sesję użytkownika do wyświetlania przetłumaczonej zawartości. Możesz utworzyć nowe oprogramowanie pośredniczące w pliku app/Http/Middleware/Localization.php lub wygenerować je, uruchamiając polecenie artisan make:middleware Localization.

Następnie dodaj poniższy kod wewnątrz.

				
					<?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);
    }
}


				
			

To oprogramowanie pośredniczące skieruje Laravel do korzystania z lokalizacji wybranej przez użytkownika, jeśli ta opcja jest dostępna w sesji.

Ponieważ potrzebujemy, aby operacja była wykonywana przy każdym żądaniu, dodaj ją do domyślnego stosu oprogramowania pośredniczącego w app/Http/Kernel.php dla grupy oprogramowania pośredniczącego sieci.

				
					/**
* 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
],


				
			

Modyfikowanie tras

Następnie zdefiniuj trasę, aby zmienić ustawienia regionalne w pliku routes/web.php. Używamy tutaj trasy zamknięcia, ale możesz umieścić ten sam kod wewnątrz kontrolera, jeśli wolisz.

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

				
			

Dodatkowo usuń przełączanie ustawień regionalnych, które zostało wcześniej dodane do domyślnej trasy powitalnej. Twoja główna trasa powinna teraz wyglądać tak.

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

				
			

Po wykonaniu tej czynności użytkownik może przełączyć aktywny język tylko odwiedzając localhost/language/{locale}. Wybrane ustawienia regionalne zostaną zapisane w sesji, a użytkownicy zostaną przekierowani z powrotem na poprzednią stronę (zgodnie z obsługą oprogramowania pośredniczącego lokalizacji). 

Aby to przetestować, przejdź do localhost/language/it (zakładając, że ciasteczko sesji jest aktywne w Twojej przeglądarce), a powinieneś zobaczyć przetłumaczoną treść. Możesz nawigować po stronie lub odświeżyć stronę, a wybrany język pozostanie w mocy.

Implementacja przełącznika języka

Teraz musimy zapewnić użytkownikowi klikalny przycisk do zmiany przełącznika języka Laravel sieci, zamiast wymagać od nich ręcznego wprowadzania kodów lokalizacji w adresie URL. Aby to osiągnąć, utwórz prosty przełącznik języka. Dodaj nowy plik w resources/views/partials/language_switcher.blade.php i wstaw poniższy kod.

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


				
			

Aby dołączyć nowo utworzony przełącznik języka do widoku „welcome”, po prostu dodaj poniższą linię do Twojego pliku welcome.blade.php, gdzie chcesz, aby przełącznik się pojawił.

				
					<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/5cde28a74717112195c10502c32f111f.js?ver=2483c"></script></body>


				
			

Otwórz plik app/Providers/AppServiceProvider.php i dodaj poniższy kod w metodzie boot(), aby udostępnić bieżące ustawienia regionalne we wszystkich widokach podczas korzystania z przełącznika języka

				
					* 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'));
    });
}


				
			

Zaawansowane funkcje tłumaczenia w Laravel PHP

Ilustracja osób pracujących nad projektem. Zespół współpracujący.

W tej dyskusji będziemy następnie zajmować się innymi komponentami lokalizacji, a mianowicie datą, liczbą i walutą. Oto kroki.

Zlokalizowane daty w Laravel

Obsługa dat i godzin jest kluczowa w procesie lokalizacji. Laravel używa Carbon do zarządzania datami i godzinami. Oto jak możesz użyć Carbon do wyświetlenia zlokalizowanej daty.

				
					<?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
    ]);
});


				
			

Ten kod ustawia locale Carbon na podstawie bieżącego locale aplikacji i formatuje datę odpowiednio.

Aby wyświetlić zlokalizowaną datę w widoku:

				
					{{ __('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 }}


				
			

Formatowanie liczb i walut

Różne kraje mają różne sposoby formatowania liczb. Na przykład.

  • Francja → 123 123,12
  • Niemcy → 123.123,12
  • Japonia → 123,123

Aby dostosować się do tych różnic w aplikacji Laravel , możesz użyć NumberFormatter.

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

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

Możesz również przeliterować liczby w określonym języku.

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

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

Oto waluty. Dla lokalizacji francuskiej (`fr`), waluta będzie wyświetlana w euro (€), natomiast dla lokalizacji amerykańskiej (`en_US`), będzie wyświetlana w dolarach amerykańskich ($).

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

$currency2 = NumberFormatter::create('en_US', NumberFormatter::CURRENCY);
				
			
Przełam bariery językowe
Żegnaj z barierami językowymi i witaj nieograniczony wzrost! Wypróbuj nasz automatyczny serwis tłumaczeń już dziś.

Alternatywne rozwiązanie lokalizacji Laravel z Linguise

Zespół pracujący razem nad projektem cyfrowym. Są otoczeni różnymi narzędziami cyfrowymi i symbolami.

Po zrozumieniu kroków lokalizacji Laravel opisanych w artykule, proces ten obejmuje wiele kroków, które wymagają od użytkowników dogłębnego zrozumienia kodu programu Laravel .

To może zdecydowanie utrudnić życie początkującym użytkownikom, którzy chcą zlokalizować swoje aplikacje. Dlatego potrzebne jest bardziej innowacyjne rozwiązanie, które umożliwia szybkie tłumaczenie, obsługuje lokalizację i wymaga tylko kilku prostych kroków do wdrożenia.

Jednym z obiecujących rozwiązań jest Linguise. Linguise oferuje łatwiejsze i bardziej efektywne podejście do lokalizacji Laravel bez potrzeby dogłębnej wiedzy o kodowaniu. Kluczowe funkcje Linguise obejmują.

  • Łatwa integracja z Laravel
  • Dostosuj przełącznik języka bez kodowania
  • Tłumaczenie obrazów
  • Edytor na żywo do dostosowywania tłumaczeń do lokalnego kontekstu
  • Dynamiczne tłumaczenie dla dynamicznie generowanych treści
  • Optymalizacja SEO dla wersji wielojęzycznych

Kroki do instalacji Linguise na Laravel stronach internetowych można również wykonać łatwo. Oto krótkie wyjaśnienie.

  1. Utwórz konto Linguise (użyj 30-dniowego bezpłatnego okresu próbnego)
  2. Zarejestruj swoją domenę internetową Laravel i wprowadź pewne informacje. Otrzymasz klucz API.
  3. Prześlij i podłącz skrypt tłumaczenia Linguise do folderu Laravel , który otrzymałeś.
  4. Ustaw adresy URL języka w pliku htaccess.
  5. Wstaw skrypt przełącznika języka w nagłówku HTML.
  6. Dostosuj przełącznik języka według potrzeb
  7. Przełącznik języka pojawi się na stronie Laravel , a treść może być tłumaczona automatycznie.

Jak? Dzięki Linguisewystarczy się zarejestrować i aktywować, a przełącznik języka się pojawi. Następnie możesz lokalizować, na przykład za pomocą edytora na żywo, tłumaczyć media, obrazy itp.

Gotowi na podbój nowych rynków? Wypróbuj nasze automatyczne usługi tłumaczeniowe za darmo z naszą bezpłatną próbą 1-miesięczną. Nie wymagamy podania numeru karty kredytowej!

Wnioski

Lokalizacja Laravel to potężna funkcja, która umożliwia programistom tworzenie wielojęzycznych stron internetowych i aplikacji. Jak widzieliśmy, wbudowany proces lokalizacji Laravel obejmuje wiele kroków i wymaga dobrej znajomości frameworka. Może to być wyzwaniem dla początkujących lub osób szukających szybszego rozwiązania.

Narzędzia takie jak Linguise oferują innowacyjną alternatywę dla osób szukających bardziej usprawnionego podejścia. Rozwiązania te zapewniają szybkie możliwości tłumaczenia, łatwą integrację i przyjazne dla użytkownika funkcje, takie jak konfigurowalne przełączniki języka i tłumaczenie obrazów. Teraz utwórz swoje Linguise konto i ciesz się naszą funkcją lokalizowania Twojego Laravel

Możesz być również zainteresowany przeczytaniem

Nie przegap okazji!
Zapisz się do naszego newslettera

Otrzymuj wiadomości o automatycznym tłumaczeniu witryny, międzynarodowym SEO i nie tylko!

Invalid email address
Wypróbuj. Raz na miesiąc, a możesz zrezygnować w dowolnym momencie.

Nie odchodź bez podania swojego adresu e-mail!

Nie możemy zagwarantować, że wygrasz w loterii, ale możemy obiecać kilka interesujących wiadomości informacyjnych dotyczących tłumaczenia i okazjonalnych zniżek.

Nie przegap okazji!
Invalid email address