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?
- 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. - Mensajes de validación: cuando un formulario está mal rellenado, los textos de advertencia también deben estar en el idioma del usuario.
- 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
- Archivos de idioma: son archivos
.propertiesnormales con claves y sus valores, por ejemplo:messages_en.propertiespara inglés.messages_ru.propertiespara ruso.
- MessageSource: Bean que busca el archivo apropiado según la locale actual.
- 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} charactersmessages_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!
GO TO FULL VERSION