Suporte Multilíngue
Para integrar suporte multilíngue em uma aplicação Spring Boot, configure um bean de resolução de localização. Defina o idioma padrão e o local dos arquivos de propriedades de internacionalização (i18n) usando uma classe de configuração.
package org.example.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.LocaleContextResolver;
import org.springframework.web.servlet.i18n.CookieLocaleResolver;
import java.util.Locale;
@Configuration
public class ConfiguracaoIdioma {
private final String idiomaPadrao = "pt-BR"; // Idioma padrão definido como português brasileiro
@Bean
public LocaleContextResolver resolvedorLocal() {
CookieLocaleResolver resolvedor = new CookieLocaleResolver();
resolvedor.setDefaultLocale(Locale.forLanguageTag(idiomaPadrao));
resolvedor.setCookieName("APP_IDIOMA");
resolvedor.setCookieMaxAge(Integer.MAX_VALUE);
return resolvedor;
}
}
Em ambientes de microsserviços, sessões podem não ser adequadas, então cookies são usados para armazenar a localização. A chave padrão do cookie é configurada na classe.
Troca de Linguagem
Adicione um endpoint em um controlador para permitir a troca de idioma via API. Isso permite que o cliente altere o idioma dinamicamente.
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.LocaleContextResolver;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@RestController
public class ControladorIdioma {
private final LocaleContextResolver resolvedorLocal;
public ControladorIdioma(LocaleContextResolver resolvedorLocal) {
this.resolvedorLocal = resolvedorLocal;
}
@GetMapping("/mudar-idioma")
public ResponseEntity<void> alterarIdioma(@RequestParam String codigoIdioma, HttpServletRequest requisicao, HttpServletResponse resposta) {
resolvedorLocal.resolveLocaleContext(requisicao);
resolvedorLocal.setLocale(requisicao, resposta, Locale.forLanguageTag(codigoIdioma));
return ResponseEntity.ok().build();
}
}</void>
Exceções Multilíngues
No tratamento de exceções, diferencie entre exceções de negócio e exceções do sistema, especialmente ao integrar com Dubbo, onde exceções podem ser encapsuladas.
Exceções de Negócio
Defina uma exceção de negócio que carrega uma chave de mensagem e argumentos para internacionalização.
package org.example.excecao;
public class ExcecaoNegocio extends RuntimeException {
private final String chaveMsg;
private final Object[] argumentos;
public ExcecaoNegocio(String chaveMsg, Object... argumentos) {
super(chaveMsg);
this.chaveMsg = chaveMsg;
this.argumentos = argumentos;
}
public String getChaveMsg() {
return chaveMsg;
}
public Object[] getArgumentos() {
return argumentos;
}
}
Use uma chave especial para mensagens diretas, como definido no arquivo de propriedades: mensagem.direta={0}.
Exceções do Sistema
Quando Dubbo ou Lombok encapsulam exceções em RuntimeException, a classe original pode não ser acessível diretamente. Porém, a mensagem da exceção muitas vezes contém o nome da classe original. Extraia esse nome usando uma expressão regular para buscar recursos de internacionalização.
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class ExtratorExcecao {
private static final Pattern PADRAO_CLASSE = Pattern.compile("^([a-z]+(\\.[a-z_][a-z0-9_]*)*\\.[A-Za-z0-9_]*Exception): ");
public static String extrairChaveExcecao(String mensagem) {
Matcher correspondencia = PADRAO_CLASSE.matcher(mensagem);
if (correspondencia.find()) {
return correspondencia.group(1);
}
return null;
}
}
Implementação Global de Tratamento de Exceções
Use uma classe de aconselhamento controlador para capturar exceções e retornar respostas padronizadas com mensagens internacionalizadas.
package org.example.mvc;
import org.example.excecao.ExcecaoNegocio;
import org.springframework.context.MessageSource;
import org.springframework.context.NoSuchMessageException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.LocaleResolver;
import javax.servlet.http.HttpServletRequest;
import java.util.Locale;
@RestControllerAdvice
public class AconselhadorExcecoes {
private final MessageSource fonteMensagem;
private final LocaleResolver resolvedorLocal;
public AconselhadorExcecoes(MessageSource fonteMensagem, LocaleResolver resolvedorLocal) {
this.fonteMensagem = fonteMensagem;
this.resolvedorLocal = resolvedorLocal;
}
@ExceptionHandler(ExcecaoNegocio.class)
public ResponseEntity<string> tratarExcecaoNegocio(HttpServletRequest requisicao, ExcecaoNegocio excecao) {
Locale localAtual = resolvedorLocal.resolveLocale(requisicao);
String mensagem;
try {
mensagem = fonteMensagem.getMessage(excecao.getChaveMsg(), excecao.getArgumentos(), localAtual);
} catch (NoSuchMessageException e) {
mensagem = excecao.getMessage();
}
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(mensagem);
}
@ExceptionHandler(Throwable.class)
public ResponseEntity<string> tratarExcecaoSistema(HttpServletRequest requisicao, Throwable excecao) {
Locale localAtual = resolvedorLocal.resolveLocale(requisicao);
String chave = ExtratorExcecao.extrairChaveExcecao(excecao.getMessage());
String mensagem;
if (chave != null) {
try {
mensagem = fonteMensagem.getMessage(chave, new Object[]{}, localAtual);
} catch (NoSuchMessageException e) {
mensagem = excecao.getMessage();
}
} else {
mensagem = excecao.getMessage();
}
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(mensagem);
}
}</string></string>
Esta abordagem permite que o frontend trate diferentes tipos de exceções com base nas mnesagens retornadas, suportando múltiplos idiomas de forma integrada.