JavaRush /Blogue Java /Random-PT /Implementação de aplicação multilíngue

Implementação de aplicação multilíngue

Publicado no grupo Random-PT
Implementação de aplicação multilíngue - 1

Hoje falaremos sobre multilinguismo. Então o que é?

O multilinguismo, ou seja, a internacionalização , faz parte do desenvolvimento de uma aplicação que pode ser adaptada para vários idiomas sem alterar a lógica do programa. Considere a situação: você está criando um aplicativo da web para uma grande empresa comercial para residentes de um grande número de países onde, por exemplo, são falados idiomas como russo, inglês e espanhol. Você precisa torná-lo conveniente para todos os usuários. A ideia é esta: um leitor que fala russo deve ter a oportunidade de ver seus dados em russo, será mais conveniente para um americano ler o material em inglês, e para um espanhol - em espanhol (inesperadamente, certo?) Vamos Vamos considerar vários modelos de internacionalizaçãoImplementação de aplicação multilingue - 2 hoje , e para um deles (que é o que mais gosto :) vamos dar uma olhada na implementação em Java. Como cobaia hoje teremos um quadro de dados de filmes. Não sejamos muito pervertidos, pois não teremos muitos palestrantes. Por exemplo, tudo bem. E vamos traduzir os nomes dos filmes (diretores - para os figurantes): Implementação de aplicação multilíngue - 3

1. Tabela com tradução para cada idioma

A essência deste modelo: cada idioma possui uma tabela separada no banco de dados, que contém todas as células que requerem tradução. A desvantagem deste método é que cada vez que adicionamos uma nova linguagem, precisamos adicionar uma nova tabela. Ou seja, vamos imaginar que nosso cliente está indo muito bem e está expandindo sua aplicação para vários países (na verdade, idiomas) do mundo. Isso significa que você precisará adicionar um comprimido por língua. Como resultado, teremos uma base de dados composta metade ou quase inteiramente por tabelas auxiliares de tradução: Implementação de aplicação multilíngue - 4 Esquema dos próprios filmes: Implementação de aplicação multilíngue - 5Tabelas de tradução:
  • russo Implementação de aplicação multilíngue - 6
  • Espanhol Implementação de aplicação multilíngue - 7
  • Inglês Implementação de aplicação multilíngue - 8

2. Um por todos

Em cada tabela pertencente a um modelo específico, é adicionado um campo com um identificador para a placa de idioma. Assim, o banco de dados também contém esta tabela com traduções. O problema é que um objeto pode corresponder a várias traduções (idiomas). Como resultado, haverá duplicação de entidades, e isso confunde e complica muito a lógica, e isso não é bom. Vemos UML: Implementação de aplicação multilíngue - 9 Filmes de tabela: Implementação de aplicação multilíngue – 10 Linguagens de tabela: Implementação de aplicação multilíngue - 11

3. Coluna por língua

Uma coluna de tradução separada é criada para cada coluna de cada idioma da tabela. A desvantagem dessa abordagem é que, novamente, se um grande número de idiomas for adicionado, a estrutura do banco de dados precisará ser alterada a cada vez, e isso é considerado uma abordagem ruim. Imagine também o quão inflados serão os sinais de internacionalização. Pode valer a pena considerar um modelo em que o número de idiomas suportados seja conhecido antecipadamente, não haja muitos deles e cada modelo deva existir em todas as variações de idioma. UML: Implementação de aplicação multilíngue - 12tabela com tudo incluído: Implementação de aplicação multilíngue - 13

4. Tradução externa

Esta opção é implementada conectando ferramentas externas (Google Translate, Bing Translate, etc.). É usado se você precisar fornecer informações ao maior número possível de visitantes, e há muitas dessas informações. Muitos. Nesse caso, você pode decidir não armazenar informações diretamente no banco de dados em todos os idiomas, mas sim traduzi-las dinamicamente. Mas vale lembrar que a qualidade da tradução automática muitas vezes deixa muito a desejar. A opção só pode ser considerada muito econômica (quando não há recursos para traduzir cada publicação). Um problema frequente do ponto de vista da tradução correta é que tradutores que não conhecem bem o idioma escolhem o significado errado de uma palavra e confundem o usuário, obrigando-o a descobrir de forma independente o significado do que está escrito no botão. Também é importante não apenas traduzir corretamente a frase, mas também trazer o seu significado para um idioma e nacionalidade específicos. Os desenvolvedores têm muitos problemas com gêneros em alguns idiomas. Eles têm que duplicar a frase no código dependendo do gênero do usuário, e também levar em consideração que não apenas os substantivos têm gênero, mas também os adjetivos e verbos são flexionados de forma diferente. Há casos em que, tendo selecionado um idioma diferente do inglês na aplicação, juntamente com as palavras do idioma selecionado, ainda existem elementos não traduzidos. Pior ainda se forem exibidos vários idiomas e acabar sendo uma espécie de Babilônia, onde tudo se confunde e o usuário não consegue entender a aplicação. Por exemplo: https://cloud.google.com/translate/

5. Arquivos de suporte em nível de aplicativo

Arquivos separados são criados para armazenar traduções. Pode ser uma lima por língua ou uma lima por língua por comprimido (trituração fina). Esta opção é frequentemente utilizada devido ao fato de que muitos textos podem ser armazenados nesses arquivos, o que significa que as tabelas e o próprio banco de dados não ficarão inchados. Outra comodidade é que você não precisa bater no banco de dados para obter esses campos, e os arquivos do código podem ser substituídos dinamicamente dependendo do idioma solicitado. Com isso, o arquivo serve para nós como um dicionário, em que a chave é o idioma, o valor é o texto. Mas não estamos limitados ao formato “.properties” abaixo, e esses formatos de arquivo podem variar bastante – JSON, XML, etc. As desvantagens são que neste caso a normalização do banco de dados é bastante reduzida. Além disso, a integridade dos dados não depende mais apenas do banco de dados, mas também do mecanismo de serialização. Excelente artigo sobre este tópico. Exemplo de arquivos de dicionário com traduções: Implementação de aplicação multilíngue - 14
  • Inglês Implementação de aplicação multilíngue – 15
  • russo Implementação de aplicação multilíngue - 16
  • Espanhol Implementação de aplicação multilíngue - 17

6. Tabela auxiliar de tradução para cada tabela

Na minha opinião, a solução mais flexível. A essência desta abordagem é criar uma tabela separada para idiomas. Quando for necessário implementar a possibilidade de traduções para a tabela em questão, é criado um link com a tabela de idiomas, e a tabela de links contém o id do idioma, id do elemento e colunas com traduções. Não é tão assustador quanto parece. Esta abordagem permite uma extensibilidade bastante flexível dos idiomas suportados. Vamos olhar mais de perto. UML: Implementação de aplicação multilíngue - 18Tabela com filmes: Implementação de aplicação multilíngue - 19Tabela de linguagens: Implementação de aplicação multilíngue – 20Tabela de traduções: Implementação de aplicação multilíngue - 21 E, como falei acima, vamos dar uma olhada na implementação de uma das opções no código Java (como você entende, esta será a última opção). Não há nada disso no aplicativo em si: passaremos dos controladores às camadas dao. Veremos o método create - por exemplo, isso será suficiente. Então vamos lá)) Nossa essência é um filme:
@Builder
@Getter
public class Movie {

   private Long id;

   private String producer;
}
Nada de interessante, apenas implementando o modelo da primeira tabela. Controlador com conversores dto (Data Transfer Object):
@RestController
@RequiredArgsConstructor
@RequestMapping(path = "/cities")
public class MovieController {

   private final MovieService movieService;

   @PostMapping
   public ResponseEntity<moviedto> create(MovieDTO movieDTO) {
       return new ResponseEntity<>(toDTO(movieService.create(fromDTO(movieDTO), movieDTO.getNameTranslations()), movieDTO.getNameTranslations()), HttpStatus.CREATED);
   }

   private Movie fromDTO(MovieDTO dto) {
       return Movie.builder()
               .id(dto.getId())
               .producer(dto.getProducer())
               .build();
   }

   private MovieDTO toDTO(Movie movie, Map<string, string=""> nameTranslation) {
       return MovieDTO.builder()
               .id(movie.getId())
               .producer(movie.getProducer())
               .nameTranslations(nameTranslation)
               .build();
   }
}
No DTO passamos as traduções como mapas, key é a abreviatura do idioma, value é o valor da tradução (nome do filme). DTO:
@Builder
@Getter
@NoArgsConstructor
@AllArgsConstructor
public class MovieDTO {

   @JsonProperty("id")
   private Long id;

   @JsonProperty("name")
   private String producer;

   @JsonProperty("nameTranslations")
   private Map<String, String> nameTranslations;//example = "{'en': 'The Matrix', 'ru' : 'Матрица'}"
}
Aqui vemos a própria classe dto, como escrito acima, mapa para traduções, os campos restantes são uma exibição do modelo Movie. Vamos passar para o serviço movie:
public interface MovieService {

   Movie create(Movie movie, Map nameList);
}
Sua implementação:
@Service
@RequiredArgsConstructor
public class MovieServiceImpl implements MovieService {

   private final MovieDAO movieDAO;
   private LanguageService languageService;

   @Override
   public Movie create(Movie movie, Map<string, string=""> nameList) {
       movieDAO.create(movie);
       Map<Long, String> map = new HashMap<>();
       nameList.forEach((x, y) -> map.put(languageService.getIdByLangCode(x), y));
       movieDAO.createTranslator(movie.getId(), map);
       return movie;
   }
}
Aqui vemos o uso de um serviço LanguageService relativamente de terceiros para recuperar o ID do idioma por sua abreviatura. E com esse identificador salvamos nossas traduções (também na forma de mapa) na tabela de conexões. Vejamos o DAO:
public interface MovieDAO {

   void create(Movie movie);

   void createTranslator(Long movieId, Map<Long,String> nameTranslations);
}
Implementação:
@RequiredArgsConstructor
@Repository
public class MovieDAOImpl implements MovieDAO {
   private final JdbcTemplate jdbcTemplate;

   private static final String CREATE_MOVIE = "INSERT INTO movies(id, producer) VALUES(?, ?)";

   private static final String CREATE_TRANSLATOR = "INSERT INTO movies_translator(movies_id, language_id, name) VALUES(?, ?, ?)";

   @Override
   public void create(Movie movie) {
       jdbcTemplate.update(CREATE_MOVIE, movie.getId(), movie.getProducer());
   }

   @Override
   public void createTranslator(Long movieId, Map<Long, String> nameTranslations) {
       nameTranslations.forEach((x, y) -> jdbcTemplate.update(CREATE_TRANSLATOR, movieId, x, y));
   }
}
Aqui vemos a preservação da essência e das linguagens para ela (dicionário). E sim, Spring JDBC é usado aqui: considero-o preferível para iniciantes, pois é mais transparente. Vamos passar para um serviço de “terceiros”. Serviço de idiomas:
public interface LanguageService {

   Long getIdByLangCode(String lang);
}
Implementação:
@Service
@RequiredArgsConstructor
public class LanguageServiceImpl implements LanguageService {
   private final LanguageDAO languageDAO;

   @Override
   public Long getIdByLangCode(String lang) {
       return languageDAO.getIdByLangCode(lang);
   }
}
Nada de especial, pesquise pelo nome abreviado. DAO:
public interface LanguageDAO {

   Long getIdByLangCode(String lang);
}
Implementação:
@RequiredArgsConstructor
@Repository
public class LanguageDAOImpl implements LanguageDAO {
   private final JdbcTemplate jdbcTemplate;

   private static final String FIND_ID_BY_LANG_CODE = "SELECT id FROM languages WHERE lang_code = ?";

   @Override
   public Long getIdByLangCode(String lang) {
       return jdbcTemplate.queryForObject(FIND_ID_BY_LANG_CODE, Long.class, lang);
   }
}
Estrutura: Implementação de aplicação multilíngue - 23 Todos os modelos descritos acima têm direito à vida. Você precisa decidir qual usar com base na situação. Claro, isso não é tudo: existem muitas outras abordagens diferentes, incluindo o uso de diferentes bancos de dados para diferentes linguagens, o uso de caches, diferentes estruturas e assim por diante. Isso é tudo para mim hoje e... Implementação de aplicação multilíngue - 24
Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION