CodeGym /Cursos /Módulo 5. Spring /Localización de mensajes de error

Localización de mensajes de error

Módulo 5. Spring
Nivel 8 , Lección 8
Disponible

La localización en IT es como un traductor en una conferencia: los usuarios hablan distintos idiomas y el sistema tiene que responderles de forma comprensible. Imagínate que estás desarrollando una aplicación que sale al mercado global. Para usuarios de diferentes países es importante que la interfaz, los errores y las notificaciones estén adaptados a su idioma y a sus particularidades culturales.

¿Qué localizamos?

  1. Mensajes de error: por ejemplo, en vez del seco must not be null, un usuario de Rusia debería ver: El campo no puede estar vacío.
  2. Mensajes de validación: cuando un formulario está mal rellenado, los textos de advertencia también deben estar en el idioma del usuario.
  3. Otras notificaciones: información sobre entradas incorrectas de fechas, números, emails, etc.

¿Cómo funciona la localización en Spring?

Spring proporciona una herramienta potente para la localización — MessageSource. Es el componente que se encarga de trabajar con los textos y soporta múltiples archivos por idioma.

Componentes de localización

  1. Archivos de idioma: son archivos .properties normales con claves y sus valores, por ejemplo:
    • messages_en.properties para inglés.
    • messages_ru.properties para ruso.
  2. MessageSource: Bean que busca el archivo apropiado según la locale actual.
  3. LocaleResolver: determina qué locale está activa para el usuario actual.

Configuración de la localización en una aplicación Spring

1. Añadir dependencias

Para empezar, asegúrate de que tienes las dependencias web y de validación en pom.xml:


<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-validation</artifactId>
</dependency>

2. Añadimos archivos de idioma

Crea en la carpeta src/main/resources los archivos:

  • messages_en.properties:
    
    field.required=Field is required
    field.length=Field must not exceed {0} characters
    
  • messages_ru.properties:
    
    field.required=El campo es obligatorio
    field.length=El campo no debe exceder {0} caracteres
    

Estos archivos contienen claves y traducciones. Las claves son identificadores únicos de los mensajes, y los valores son los textos en el idioma correspondiente.

3. Configuración de MessageSource

En Spring Boot MessageSource se configura mediante un Bean en una clase de configuración. Añadimos el siguiente código:


import org.springframework.context.MessageSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ReloadableResourceBundleMessageSource;

@Configuration
public class LocalizationConfig {

    @Bean
    public MessageSource messageSource() {
        ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
        messageSource.setBasename("classpath:messages");
        messageSource.setDefaultEncoding("UTF-8");
        return messageSource;
    }
}

Esto le indica a Spring que busque archivos messages_*.properties en la carpeta de recursos.

4. Configurar LocaleResolver

Añadimos un LocaleResolver para determinar el idioma del usuario. Por ejemplo, se puede usar una cookie para guardar la selección de idioma:


import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.i18n.CookieLocaleResolver;

import java.util.Locale;

@Configuration
public class LocaleConfig {

    @Bean
    public LocaleResolver localeResolver() {
        CookieLocaleResolver localeResolver = new CookieLocaleResolver();
        localeResolver.setDefaultLocale(Locale.ENGLISH); // Idioma por defecto
        return localeResolver;
    }
}

5. Cambiar la locale desde un controlador

Ahora vamos a crear un controlador para que los usuarios puedan cambiar el idioma. Por ejemplo, mediante el parámetro lang:


import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.LocaleResolver;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Locale;

@RestController
public class LanguageController {

    private final LocaleResolver localeResolver;

    public LanguageController(LocaleResolver localeResolver) {
        this.localeResolver = localeResolver;
    }

    @GetMapping("/change-language")
    public String changeLanguage(@RequestParam String lang, HttpServletRequest request, HttpServletResponse response) {
        Locale locale = new Locale(lang);
        localeResolver.setLocale(request, response, locale);
        return "Language changed to " + lang;
    }
}

Ahora las peticiones como /change-language?lang=ru cambiarán el idioma.


Localización de mensajes de error

Localizamos los mensajes del Bean Validation API.

1. Anotamos los campos del DTO

Nuestro UserDTO podría verse así:


import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;

public class UserDTO {

    @NotNull(message = "{field.required}")
    private String username;

    @Size(max = 20, message = "{field.length}")
    private String password;

    // Getters y setters
}

Las claves de los mensajes de error ({field.required} y {field.length}) se toman de los archivos de idioma.

2. Ejemplo de manejo en el controlador

Creamos un controlador REST que maneje una petición POST para el registro.


import org.springframework.web.bind.annotation.*;
import jakarta.validation.Valid;

@RestController
@RequestMapping("/users")
public class UserController {

    @PostMapping
    public String createUser(@RequestBody @Valid UserDTO userDTO) {
        return "User created: " + userDTO.getUsername();
    }
}

Spring valida las peticiones automáticamente y, en caso de error, lanza la excepción MethodArgumentNotValidException.


Localización de errores mediante GlobalExceptionHandler

Las lecciones anteriores nos enseñaron a usar @ControllerAdvice para el manejo global de errores. Vamos a localizar los errores para los usuarios:


import org.springframework.context.MessageSource;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;

import java.util.HashMap;
import java.util.Locale;
import java.util.Map;

@ControllerAdvice
public class GlobalExceptionHandler {

    private final MessageSource messageSource;

    public GlobalExceptionHandler(MessageSource messageSource) {
        this.messageSource = messageSource;
    }

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseEntity<Map<String, String>> handleValidationExceptions(MethodArgumentNotValidException ex, Locale locale) {
        Map<String, String> errors = new HashMap<>();
        for (FieldError error : ex.getBindingResult().getFieldErrors()) {
            String localizedErrorMessage = messageSource.getMessage(error, locale);
            errors.put(error.getField(), localizedErrorMessage);
        }
        return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(errors);
    }
}

¡Ahora los mensajes de error se devolverán según la locale actual del usuario!


Ejemplo de petición

Cuerpo de la petición


{
  "username": null,
  "password": "password_that_is_too_long_for_the_application_rules"
}

Respuesta con la locale en


{
  "username": "Field is required",
  "password": "Field must not exceed 20 characters"
}

Respuesta con la locale ru


{
  "username": "El campo es obligatorio",
  "password": "El campo no debe exceder 20 caracteres"
}

Ahora tu aplicación Spring entiende varios idiomas. Esto le da un toque profesional y hace el sistema más amigable para el usuario. ¡Has logrado oficialmente la localización!

Comentarios
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION