JavaRush /Blog Java /Random-ES /Implementación de aplicación multilingüe.

Implementación de aplicación multilingüe.

Publicado en el grupo Random-ES
Implementación de aplicación multilingüe - 1

Hoy hablaremos de multilingüismo. ¿Así que qué es lo?

El multilingüismo, es decir, la internacionalización , es parte del desarrollo de una aplicación que se puede adaptar a varios idiomas sin cambiar la lógica del programa. Considere la situación: está creando una aplicación web para una gran empresa comercial para residentes de una gran cantidad de países en los que, por ejemplo, se hablan idiomas como ruso, inglés y español. Debe hacerlo conveniente para todos los usuarios. La idea es la siguiente: un lector de habla rusa debería poder ver sus datos en ruso, un estadounidense se sentirá más cómodo leyendo el material en inglés y un español en español (inesperadamente, ¿verdad?). Consideremos hoy Implementación de aplicación multilingüe - 2varios modelos de internacionalización. , y para uno de ellos (que es el que más me gusta :) Veamos la implementación en Java. Como conejillo de indias, hoy tendremos una placa de datos de película. No nos pervirtamos demasiado, así no tendremos muchos oradores. Por ejemplo, eso está bien. Y traduciremos los nombres de las películas (directores - para los extras): Implementación de aplicación multilingüe - 3

1. Tabla con traducción para cada idioma.

La esencia de este modelo: cada idioma tiene una tabla separada en la base de datos, que contiene todas las celdas que requieren traducción. La desventaja de este método es que cada vez que agregamos un nuevo idioma, necesitamos agregar una nueva tabla. Es decir, imaginemos que a nuestro cliente le está yendo muy bien y está expandiendo su aplicación a muchos países (de hecho, idiomas) del mundo. Esto significa que deberá agregar una tableta por lengua. Como resultado, tendremos una base de datos formada mitad o casi en su totalidad por tablas auxiliares de traducción: Implementación de aplicación multilingüe - 4 Esquema de las propias películas: Implementación de aplicación multilingüe - 5Tablas de traducción:
  • ruso Implementación de aplicación multilingüe - 6
  • Español Implementación de aplicación multilingüe - 7
  • Inglés Implementación de aplicación multilingüe - 8

2. Uno para todos

En cada tabla que pertenece a un modelo concreto se añade un campo con un identificador de la placa de idioma. En consecuencia, la base de datos también contiene esta tabla con traducciones. El problema es que un objeto puede corresponder a varias traducciones (idiomas). Como resultado, habrá duplicación de entidades, y esto confunde y complica mucho la lógica, y esto no es bueno. Nos fijamos en UML: Implementación de aplicación multilingüe - 9 Películas de tabla: Implementación de aplicación multilingüe - 10 Idiomas de tabla: Implementación de aplicación multilingüe - 11

3. Columna por lengua

Se crea una columna de traducción independiente para cada columna de cada idioma de la tabla. La desventaja de este enfoque es que, nuevamente, si se agrega una gran cantidad de idiomas, será necesario cambiar la estructura de la base de datos cada vez, lo que se considera un mal enfoque. Imagínese también cuán inflados estarán los carteles que exigen la internacionalización. Puede valer la pena considerar un modelo en el que la cantidad de idiomas admitidos se conozca de antemano, no haya demasiados y cada modelo debería existir en todas las variaciones de idioma. UML: Implementación de aplicación multilingüe - 12Tabla todo incluido: Implementación de aplicación multilingüe - 13

4. Traducción externa

Esta opción se implementa conectando herramientas externas (Google Translate, Bing Translate, etc.). Se utiliza si necesita proporcionar información a tantos visitantes como sea posible, y hay mucha información. Tantos. En este caso, puede decidir no almacenar información directamente en la base de datos en todos los idiomas, sino traducirla dinámicamente. Pero conviene recordar que la calidad de la traducción automática suele dejar mucho que desear. La opción sólo puede considerarse como muy económica (cuando no hay recursos para traducir cada publicación). Un problema común en términos de traducción correcta es que los traductores que no conocen bien el idioma eligen el significado incorrecto de una palabra y confunden al usuario, obligándolo a descubrir de forma independiente el significado de lo que está escrito en el botón. También es importante no sólo traducir correctamente la frase, sino también llevar su significado a un idioma y nacionalidad específicos. Los desarrolladores tienen muchos problemas con los géneros en algunos idiomas. Tienen que duplicar la frase en el código dependiendo del género del usuario, y también tener en cuenta que no sólo los sustantivos tienen género, sino que también los adjetivos y verbos se declinan de manera diferente. Hay casos en los que, habiendo seleccionado en la aplicación un idioma distinto al inglés, junto con las palabras del idioma seleccionado, aún quedan elementos sin traducir. Es aún peor si se muestran varios idiomas y resulta ser una especie de Babilonia, donde todo se mezcla y el usuario no puede entender la aplicación, por ejemplo: https://cloud.google.com/translate/

5. Archivos de soporte a nivel de aplicación

Se crean archivos separados para almacenar traducciones. Puede ser una lima por lengua o una lima por lengua por tableta (trituración fina). Esta opción se utiliza a menudo debido al hecho de que se pueden almacenar muchos textos en estos archivos, lo que significa que las tablas y la base de datos en sí no se inflarán. La conveniencia también radica en el hecho de que no es necesario acceder a la base de datos para estos campos, y en el código los archivos se pueden reemplazar dinámicamente según el idioma solicitado. Como resultado, el archivo nos sirve como un diccionario, en el que la clave es el idioma y el valor es el texto. Pero no estamos limitados al formato ".properties" que aparece a continuación, y estos formatos de archivo pueden variar ampliamente: JSON, XML, etc. Las desventajas son que en este caso la normalización de la base de datos se reduce considerablemente. Además, la integridad de los datos ya no depende sólo de la base de datos, sino también del mecanismo de serialización. Excelente artículo sobre este tema. Ejemplo de archivos de diccionario con traducciones: Implementación de aplicación multilingüe - 14
  • Inglés Implementación de aplicación multilingüe - 15
  • ruso Implementación de aplicación multilingüe - 16
  • Español Implementación de aplicación multilingüe - 17

6. Tabla de traducción auxiliar para cada tabla.

En mi opinión, la solución más flexible. La esencia de este enfoque es crear una tabla separada para idiomas. Cuando es necesario implementar la posibilidad de traducciones para la tabla en cuestión, se crea un enlace con la tabla de idiomas, y la tabla de enlaces contiene el id del idioma, el id del elemento y las columnas con las traducciones. No da tanto miedo como parece. Este enfoque permite una extensibilidad bastante flexible de los lenguajes admitidos. Miremos más de cerca. UML: Implementación de aplicación multilingüe - 18Tabla con películas: Implementación de aplicación multilingüe - 19Tabla de idiomas: Implementación de aplicación multilingüe - 20Tabla de traducciones: Implementación de aplicación multilingüe - 21 Y, como dije anteriormente, veamos la implementación de una de las opciones en código Java (como comprenderá, esta será la última opción). No hay nada de eso en la aplicación en sí: pasaremos de los controladores a las capas dao. Veremos el método de creación; por ejemplo, esto será suficiente. Así que vamos)) Nuestra esencia es una película:
@Builder
@Getter
public class Movie {

   private Long id;

   private String producer;
}
Nada interesante, solo implementar el modelo de la primera tabla. Controlador con convertidores dto (Objeto de transferencia de datos):
@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();
   }
}
En DTO pasamos las traducciones como mapas, la clave es la abreviatura del idioma, el valor es el valor de la traducción (nombre de la película). 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' : 'Матрица'}"
}
Aquí vemos la clase dto en sí, como se escribió anteriormente, mapa para traducciones, los campos restantes son una visualización del modelo Película. Pasemos al servicio de películas:
public interface MovieService {

   Movie create(Movie movie, Map nameList);
}
Su implementación:
@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;
   }
}
Aquí vemos el uso de un servicio LanguageService relativamente de terceros para recuperar la identificación del idioma por su abreviatura. Y con este identificador guardamos nuestras traducciones (también en forma de mapa) en la tabla de conexiones. Veamos el DAO:
public interface MovieDAO {

   void create(Movie movie);

   void createTranslator(Long movieId, Map<Long,String> nameTranslations);
}
Implementación:
@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));
   }
}
Aquí vemos la preservación de la esencia y los lenguajes correspondientes (diccionario). Y sí, aquí se utiliza Spring JDBC: lo considero preferible para principiantes, ya que es más transparente. Pasemos a un servicio de "terceros". Servicio de idiomas:
public interface LanguageService {

   Long getIdByLangCode(String lang);
}
Implementación:
@Service
@RequiredArgsConstructor
public class LanguageServiceImpl implements LanguageService {
   private final LanguageDAO languageDAO;

   @Override
   public Long getIdByLangCode(String lang) {
       return languageDAO.getIdByLangCode(lang);
   }
}
Nada especial, busca por nombre abreviado. DAO:
public interface LanguageDAO {

   Long getIdByLangCode(String lang);
}
Implementación:
@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);
   }
}
Estructura: Implementación de aplicación multilingüe - 23 Todos los modelos descritos anteriormente tienen derecho a la vida. Debes decidir cuál usar según la situación. Por supuesto, eso no es todo: hay muchos más enfoques diferentes, incluido el uso de diferentes bases de datos para diferentes idiomas, el uso de cachés, diferentes marcos, etc. Eso es todo para mí hoy y... Implementación de aplicación multilingüe - 24
Comentarios
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION