En un tutorial pasado te mostré cómo crear un proyecto multi idioma en Laravel, ahora te enseñaré a crear un proyecto multilenguaje en Laravel usando una base de datos desde cero paso a paso, al final encontrarás el repositorio del tutorial. Sin más, manos a la obra.
Requisitos previos
- Entorno de desarrollo como Xamp o Laragon
- Tener instalado globalmente composer
- Editor de textos como VS Code
1. Crear proyecto Laravel nuevo
Para crear rápidamente un proyecto nuevo de Laravel usa composer abriendo la terminal de comandos y escribe:
composer create-project laravel/laravel multi-idioma-base-datos
Una vez que termine de crearse el proyecto en Laravel desde la terminal de comandos ingresa a la carpeta de nuevo proyecto.
2. Crear base de datos
Para crear una base de datos nueva para tu proyecto ingresa a la consola de mysql escribiendo en la terminal la instrucción:
mysql -u root -p
Accede con tus credenciales:
Escribe:
CREATE DATABASE multi_lenguaje CHARACTER SET utf8 COLLATE utf8_spanish_ci;
Para salir de la consola de mysql escribe ‘exit’ y luego oprime la tecla ‘Enter’.
Desde tu editor de texto ve a tu proyecto y abre el archivo .env y agrega la configuración de la base de datos como el nombre de la base de datos y la contraseña (en caso de tener):
3. Crear modelo, migración y controlador
Para este proyecto estaré usando un modelo llamado Post con su migración y controlador, para crearlos escribe en la terminal el comando:
php artisan make:model Post -mc
4. Editar archivo de migración
Abre el archivo database/migrations/…create_posts_table.php:
Agrega los siguientes campos:
<?php use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; return new class extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('posts', function (Blueprint $table) { $table->id(); $table->string('title_en')->nullable(); $table->text('body_en')->nullable(); $table->string('title_es')->nullable(); $table->text('body_es')->nullable(); $table->timestamps(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::dropIfExists('posts'); } };
La tabla ‘posts’ cuenta con los campos ‘title_es’ y ‘body_es’ en donde se guardará la información en español y ‘title_en’ y ‘body_en’ en donde se guardará las traducciones en inglés.
Ahora corre las migraciones desde la terminal de comandos:
php artisan migrate
5. Crear Middleware SetLocale y configurarlo
Para verificar en que idioma se tiene que traer la información que se encuentra en la base de datos tienes que crear el Middleware SetLocale, para ello en tu terminal de comandos escribe la siguiente instrucción:
php artisan make:middleware SetLocale
Con tu editor de textos abre el archivo App\Http\Middleware\SetLocale y agrega la lógica que necesita para funcionar correctamente:
public function handle(Request $request, Closure $next) { $language = 'en'; // default if (request('language')) { $language = request('language'); session()->put('language', $language); } elseif (session('language')) { $language = session('language'); } app()->setLocale($language); return $next($request); }
Ve al archivo app/Http/Kernel.php y busca el array asociativo $routeMiddleware y agrega la siguiente línea de código:
\App\Http\Middleware\SetLocale::class,
6. Configurar modelo Post
Para habilitar la asignación masiva abre el archivo app/Models/Post.php y agrega la siguiente línea de código dentro de la clase Post:
protected $guarded = ['id'];
7. Crear rutas
En el archivo routes/web.php agrega las siguientes rutas:
Route::get('/', [Controller::class, 'index'])->name('index'); Route::resource('posts', PostController::class);
8. Configurar controlador
Ahora toca configurar los dos controladores que estas utilizando, ve a app/Http/Controllers/PostController.php y en la clase PostController agrega los siguientes métodos:
public function create(){ return view('posts.create'); } public function show(){ return view('posts.show'); } public function store(StorePostRequest $request){ Post::create($request->validated()); return redirect()->route('index'); } public function edit(Post $post){ return view('posts.edit', compact('post')); } public function update(Request $request, Post $post){ $data = $request->validate([ 'title_en' => 'required', 'body_en' => 'required', 'title_es' => 'required', 'body_es' => 'required' ]); $post->title_en = $data['title_en']; $post->body_en = $data['body_en']; $post->title_es = $data['title_es']; $post->body_es = $data['body_es']; $post->save(); return redirect()->route('index'); } public function destroy(Post $post, Request $request){ $post->delete(); return redirect()->route('index'); }
También configura el archivo app/Http/Controllers/Controller.php y agrega el método index:
public function index(){ $locale = app()->getLocale(); $posts = Post::select(['id', 'title_' . $locale, 'body_' . $locale])->latest()->where('title_' . $locale, '!=', '')->take(12)->get(); return view('posts.index', compact('posts')); }
9. Crear form request
Para validar el formulario para crear un nuevo post vas a crear un form request, para ello desde la terminal escribe la instrucción:
php artisan make:request StorePostRequest
Abre el archivo app/Http/Requests/StorePostRequest.php y en el método rules agrega el siguiente código:
public function rules() { $rules = [ 'title_en' => 'required', 'body_en' => 'required' ]; foreach (config('app.available_locales') as $locale){ $rules['title_' . $locale] = 'string'; $rules['body_' . $locale] = 'string'; } return $rules; }
En el método authorize() en el return debe mandar un true, de otra manera va a dar un error de autorización.
10. Agregar idiomas soportados
Para agregar los idiomas que serán soportados por tu aplicación ve al archivo config/app.php y en apartado de idioma debajo de ‘locale’ => ‘en’ agrega la siguiente línea de código:
'available_locales' => ['en', 'es'],
Si quieres agregar más idiomas recuerda agregarlos en este archivo por ejemplo si quieres agregar el idioma Italiano agrega en el array ‘it’.
11. Crear vistas
Crea la carpteta resources/views/posts y dentro de la carpeta posts crea el archivo index.blade.php agrega el siguiente código:
@extends('layouts.app') @section('title', 'Index') @section('content') <div class="col-12"> @foreach ($posts as $post) <div class="card mt-3"> <div class="card-body"> <h5 class="card-title">{{ $post->{'title_'.app()->getLocale()} }}</h5> <p class="card-text">{{ substr($post->{'body_'.app()->getLocale()}, 0, 80) }}</p> <a href="{{ route('posts.edit') }}" class="btn btn-info">Editar</a> <a href="{{ route('posts.destroy') }}" class="btn btn-danger">Borrar</a> </div> </div> @endforeach </div> @endsection
Dentro de la misma carpeta crea el archivo create.blade.php:
@extends('layouts.app') @section('title', 'Create') @section('content') <div class="col-12"> <div class="card mt-5"> <div class="card-body"> <h5 class="card-title">Crear nuevo post</h5> <form method="POST" action="{{ route('posts.store') }}"> @csrf @foreach (config('app.available_locales') as $locale) <div class="form-group"> <label for="title_{{ $locale }}">Titulo ({{ strtoupper($locale) }})</label> <input type="text" class="form-control" name="title_{{ $locale }}" id="title_{{ $locale }}" value="{{ old('title_' . $locale) }}" placeholder="Enter title"> </div> <div class="form-group"> <label for="body_{{ $locale }}">Contenido ({{ strtoupper($locale) }})</label> <textarea class="form-control" name="body_{{ $locale }}" id="body_{{ $locale }}">{{ old('body_' . $locale) }}</textarea> </div> @endforeach <button type="submit" class="btn btn-primary">Guardar</button> </form> </div> </div> </div> @endsection
También el crea el archivo edit.blade.php:
@extends('layouts.app') @section('title', 'Edit') @section('content') <div class="col-12"> <div class="card mt-5"> <div class="card-body"> <h5 class="card-title">Editar post</h5> <form action="{{ route('posts.update', $post->id) }}" method="POST"> @csrf @method('PUT') <div class="form-group"> <label for="title_en">Titulo (EN)</label> <input type="text" class="form-control" name="title_en" id="title_en" value="{{ $post->title_en}}" placeholder="Enter title"> </div> <div class="form-group"> <label for="body_en">Contenido (EN)</label> <textarea class="form-control" name="body_en" id="body_en">{{ $post->body_en}}</textarea> </div> <div class="form-group"> <label for="title_es">Titulo (ES)</label> <input type="text" class="form-control" name="title_es" id="title_es" value="{{ $post->title_es}}" placeholder="Enter title"> </div> <div class="form-group"> <label for="body_es">Contenido (ES)</label> <textarea class="form-control" name="body_es" id="body_es">{{ $post->body_es}}</textarea> </div> <button type="submit" class="btn btn-primary">Guardar</button> </form> </div> </div> </div> @endsection
Sal de la carpeta posts y crea la carpeta resources/views/layouts y dentro de layouts crea el archivo app.blade.php que será la plantilla de las vistas y agrega el siguiente código:
<!doctype html> <html lang="{{ str_replace('_', '-', app()->getLocale()) }}"> <head> <!-- Required meta tags --> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <meta name="csrf-token" content="{{ csrf_token() }}"> <!-- Bootstrap CSS --> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous"> <title>{{ config('app.name') }}</title> </head> <body> <div class="container"> <div class="row"> //contenido @yield('content') </div> </div> <!-- Optional JavaScript --> <!-- jQuery first, then Popper.js, then Bootstrap JS --> <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script> </body> </html>
12. Probar proyecto
Para probar tu proyecto multilenguaje en Laravel desde una base de datos, en tu terminal de comandos escribe la instrucción:
php artisan serve
Abre tu navegador web y ve a la dirección http://127.0.0.1:8000 o localhost:8000 en donde ya puedes crear algunos post de prueba, en mi caso ya hice unas cuantas pruebas y todo funciona correctamente:
Conclusión
En este tutorial aprendiste una de las formas de cómo crear un proyecto multilenguaje en Laravel desde una base de datos, este tipo de traducciones se usa cuando el contenido que se quiere traducir es dinámico, para las traducciones estáticas puedes usar un archivo .json y puedes ver cómo hacerlo aquí. Si este tutorial te sirvió te invito a compartirlo en tus redes sociales para llegar a más personas y si tienes dudas o comentarios déjalos en la caja de comentarios, estaré al pendiente de ellos. Recibe un cordial saludo.
Repositorio del proyecto aquí
Hola! excelente guía, que recomendaciones darias para trabajar con reactjs mediante una api, este tipo de poryectos.
Hola Edderson, gracias por visitar y comentar. Te comparto un tutorial en donde muestro cómo crear un CRUD con Laravel 9 y React, espero te sirva, saludos. https://diarioprogramador.com/crud-con-laravel-9-y-react/
Muchas gracias! Me ha servido mucho tu tutorial, me gusta que es al grano sin rodeos, te agradezco!
Hola Alberto, gracias por visitar, agradezco tus comentarios, saludos.
Este tutorial me ayudo mucho, gracias por compartir.
Hola Saúl, gracias por visitar y comentar, me alegra mucho saber que fue de ayuda este tutorial, saludos!
Este tutorial fue de mucha ayuda, gracias por compartir.
Hola Raúl, gracias por visitar y comentar, saludos!