JavaRush /Blog Java /Random-FR /Mise en place d'une application multilingue

Mise en place d'une application multilingue

Publié dans le groupe Random-FR
Implémentation d'application multilingue - 1

Aujourd'hui, nous parlerons de multilinguisme. Alors c'est quoi?

Le multilinguisme, autrement dit l'internationalisation , fait partie du développement d'une application adaptable à plusieurs langues sans changer la logique du programme. Considérez la situation : vous créez une application Web pour une grande société commerciale destinée aux résidents d'un grand nombre de pays dans lesquels, par exemple, des langues telles que le russe, l'anglais et l'espagnol sont parlées. Vous devez le rendre pratique pour tous les utilisateurs. L'idée est la suivante : un lecteur russophone devrait pouvoir voir vos données en russe, un Américain sera plus à l'aise pour lire le matériel en anglais et un Espagnol - en espagnol (de façon inattendue, n'est-ce pas ?). Considérons Implémentation d'application multilingue - 2aujourd'hui plusieurs modèles d'internationalisation . , et pour l'un d'eux (qui est celui que j'aime le plus :) Regardons l'implémentation en Java. En tant que cobaye, nous aurons aujourd'hui une plaque signalétique de film. Ne soyons pas trop pervers, nous n'aurons donc pas beaucoup d'intervenants. Par exemple, ça va. Et nous traduirons les noms des films (réalisateurs - pour les figurants) : Implémentation d'application multilingue - 3

1. Tableau avec traduction pour chaque langue

L'essence de ce modèle : chaque langue possède une table distincte dans la base de données, qui contient toutes les cellules à traduire. L’inconvénient de cette méthode est que chaque fois que nous ajoutons une nouvelle langue, nous devons ajouter une nouvelle table. Autrement dit, imaginons que notre client se porte très bien et qu'il étend son application à de nombreux pays (en fait, langues) du monde. Cela signifie que vous devrez ajouter un comprimé par langue. De ce fait, nous aurons une base de données constituée à moitié ou presque entièrement de tables de traduction auxiliaires : Implémentation d'application multilingue - 4 Schéma des films eux-mêmes : Implémentation d'application multilingue - 5Tables de traduction :
  • russe Implémentation d'application multilingue - 6
  • Espagnol Implémentation d'application multilingue - 7
  • Anglais Implémentation d'application multilingue - 8

2. Un pour tous

Dans chaque table appartenant à un modèle spécifique, un champ avec un identifiant pour la plaque de langue est ajouté. En conséquence, la base de données contient également ce tableau avec des traductions. Le problème est qu'un objet peut correspondre à plusieurs traductions (langues). En conséquence, il y aura une duplication des entités, ce qui confondra et compliquera grandement la logique, et ce n'est pas bon. Nous regardons UML : Implémentation d'application multilingue - 9 Films de table : Implémentation d'application multilingue - 10 Langages de table : Implémentation d'application multilingue - 11

3. Colonne par langue

Une colonne de traduction distincte est créée pour chaque colonne pour chaque langue du tableau. L'inconvénient de cette approche est que, encore une fois, si un grand nombre de langues sont ajoutées, la structure de la base de données devra être modifiée à chaque fois, ce qui est considéré comme une mauvaise approche. Imaginez aussi à quel point les panneaux réclamant l’internationalisation seront exagérés. Il peut être intéressant d'envisager un modèle dans lequel le nombre de langues prises en charge est connu à l'avance, il n'y en a pas beaucoup et chaque modèle doit exister dans toutes les variantes linguistiques. UML : Implémentation d'application multilingue - 12 Tableau tout compris : Implémentation d'application multilingue - 13

4. Traduction externe

Cette option est implémentée en connectant des outils externes (Google Translate, Bing Translate, etc.). Il est utilisé si vous avez besoin de fournir des informations au plus grand nombre de visiteurs possible, et ces informations sont nombreuses. Tant. Dans ce cas, vous pouvez décider de ne pas stocker directement les informations dans la base de données dans toutes les langues, mais de les traduire dynamiquement. Mais il ne faut pas oublier que la qualité de la traduction automatique laisse souvent à désirer. L'option ne peut être considérée que comme très économique (lorsqu'il n'y a pas de ressources pour traduire chaque publication). Un problème courant en termes de traduction correcte est que les traducteurs qui ne connaissent pas bien la langue choisissent le mauvais sens d'un mot et confondent l'utilisateur, l'obligeant à comprendre de manière indépendante le sens de ce qui est écrit sur le bouton. Il est également important non seulement de traduire correctement la phrase, mais également de lui donner un sens dans une langue et une nationalité spécifiques. Les développeurs ont beaucoup de problèmes avec les genres dans certaines langues. Ils doivent dupliquer la phrase dans le code en fonction du sexe de l'utilisateur et tenir également compte du fait que non seulement les noms ont un genre, mais que les adjectifs et les verbes sont également fléchis différemment. Il existe des cas où, après avoir sélectionné une langue autre que l'anglais dans l'application, avec les mots de la langue sélectionnée, il reste encore des éléments non traduits. C'est encore pire si plusieurs langues sont affichées et cela s'avère être une sorte de Babylone, où tout est mélangé et où l'utilisateur ne comprend pas l'application. Par exemple : https://cloud.google.com/translate/

5. Fichiers de support au niveau de l'application

Des fichiers séparés sont créés pour stocker les traductions. Il peut s'agir d'une lime par langue ou d'une lime par langue et par comprimé (concassage fin). Cette option est souvent utilisée car de nombreux textes peuvent être stockés dans ces fichiers, ce qui signifie que les tables et la base de données elle-même ne seront pas surchargées. Un autre avantage est que vous n'avez pas besoin de cliquer sur la base de données pour ces champs, et les fichiers du code peuvent être remplacés dynamiquement en fonction de la langue demandée. De ce fait, le fichier nous sert de dictionnaire, dans lequel la clé est la langue, la valeur est le texte. Mais nous ne nous limitons pas au format « .properties » ci-dessous, et ces formats de fichiers peuvent varier considérablement : JSON, XML, etc. Les inconvénients sont que dans ce cas, la normalisation de la base de données est considérablement réduite. De plus, l’intégrité des données ne dépend plus uniquement de la base de données, mais également du mécanisme de sérialisation. Excellent article sur ce sujet Exemple de fichiers de dictionnaire avec traductions : Implémentation d'application multilingue - 14
  • Anglais Implémentation d'application multilingue - 15
  • russe Implémentation d'application multilingue - 16
  • Espagnol Implémentation d'application multilingue - 17

6. Table de traduction auxiliaire pour chaque table

À mon avis, la solution la plus flexible. L'essence de cette approche est de créer un tableau séparé pour les langues. Lorsqu'il est nécessaire d'implémenter la possibilité de traductions pour la table en question, un lien est créé avec la table des langues, et la table des liens contient l'identifiant de la langue, l'identifiant de l'élément et les colonnes avec les traductions. Ce n'est pas aussi effrayant que ça en a l'air. Cette approche permet une extensibilité assez flexible des langages pris en charge. Regardons de plus près. UML : Implémentation d'application multilingue - 18Table avec films : Implémentation d'application multilingue - 19Table des langues : Implémentation d'application multilingue - 20Table des traductions : Implémentation d'application multilingue - 21 Et, comme je l'ai dit plus haut, regardons l'implémentation d'une des options dans le code Java (comme vous l'avez compris, ce sera la dernière option). Il n’y a rien de tel dans l’application elle-même : on va passer des contrôleurs aux couches dao. Nous examinerons la méthode create - pour un exemple, cela suffira. Alors c'est parti)) Notre essence est un film :
@Builder
@Getter
public class Movie {

   private Long id;

   private String producer;
}
Rien d'intéressant, juste implémenter le modèle du premier tableau. Contrôleur avec convertisseurs 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();
   }
}
Dans DTO, nous transmettons les traductions sous forme de cartes, la clé est l'abréviation de la langue, la valeur est la valeur de la traduction (nom du film). 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' : 'Матрица'}"
}
Ici, nous voyons la classe dto elle-même, comme écrit ci-dessus, une carte pour les traductions, les champs restants sont un affichage du modèle Movie. Passons au service movie :
public interface MovieService {

   Movie create(Movie movie, Map nameList);
}
Sa mise en œuvre :
@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;
   }
}
Nous voyons ici l'utilisation d'un service LanguageService relativement tiers pour récupérer l'identifiant de langue par son abréviation. Et avec cet identifiant, nous sauvegardons nos traductions (également sous forme de carte) dans la table de connexion. Regardons le DAO :
public interface MovieDAO {

   void create(Movie movie);

   void createTranslator(Long movieId, Map<Long,String> nameTranslations);
}
Mise en œuvre:
@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));
   }
}
Ici, nous voyons la préservation de l'essence et des langues (dictionnaire). Et oui, Spring JDBC est utilisé ici : je le considère préférable pour les débutants, car il est plus transparent. Passons à un service « tiers ». Service linguistique :
public interface LanguageService {

   Long getIdByLangCode(String lang);
}
Mise en œuvre:
@Service
@RequiredArgsConstructor
public class LanguageServiceImpl implements LanguageService {
   private final LanguageDAO languageDAO;

   @Override
   public Long getIdByLangCode(String lang) {
       return languageDAO.getIdByLangCode(lang);
   }
}
Rien de spécial, recherchez par nom abrégé. DAO :
public interface LanguageDAO {

   Long getIdByLangCode(String lang);
}
Mise en œuvre:
@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);
   }
}
Structure : Implémentation d'application multilingue - 23 Tous les modèles décrits ci-dessus ont droit à la vie. Vous devez décider lequel utiliser en fonction de la situation. Bien sûr, ce n’est pas tout : il existe de nombreuses autres approches différentes, notamment l’utilisation de différentes bases de données pour différents langages, l’utilisation de caches, différents frameworks, etc. C'est tout pour moi aujourd'hui et... Implémentation d'application multilingue - 24
Commentaires
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION