JavaRush /Java-Blog /Random-DE /Implementierung einer mehrsprachigen Anwendung

Implementierung einer mehrsprachigen Anwendung

Veröffentlicht in der Gruppe Random-DE
Implementierung einer mehrsprachigen Anwendung – 1

Heute sprechen wir über Mehrsprachigkeit. Also, was ist es?

Mehrsprachigkeit, also Internationalisierung , ist Teil der Entwicklung einer Anwendung, die für mehrere Sprachen angepasst werden kann, ohne die Programmlogik zu ändern. Stellen Sie sich die Situation vor: Sie erstellen eine Webanwendung für ein großes Handelsunternehmen für Einwohner einer Vielzahl von Ländern, in denen beispielsweise Sprachen wie Russisch, Englisch und Spanisch gesprochen werden. Sie müssen es für alle Benutzer bequem machen. Die Idee ist folgende: Ein russischsprachiger Leser sollte Ihre Daten auf Russisch sehen können, ein Amerikaner wird sich wohler fühlen, das Material auf Englisch zu lesen, und ein Spanier - auf Spanisch (unerwartet, oder?) Betrachten wir Implementierung einer mehrsprachigen Anwendung – 2heute mehrere Internationalisierungsmodelle , und für eine davon (die mir am besten gefällt :) Schauen wir uns die Implementierung in Java an. Als Versuchskaninchen werden wir heute ein Filmdatenschild haben. Lassen Sie uns nicht zu pervers werden, also werden wir nicht viele Redner haben. Das ist zum Beispiel in Ordnung. Und wir übersetzen die Namen der Filme (Regisseure - für die Statisten): Implementierung einer mehrsprachigen Anwendung – 3

1. Tabelle mit Übersetzung für jede Sprache

Die Essenz dieses Modells: Jede Sprache verfügt über eine separate Tabelle in der Datenbank, die alle Zellen enthält, die übersetzt werden müssen. Der Nachteil dieser Methode besteht darin, dass wir jedes Mal, wenn wir eine neue Sprache hinzufügen, eine neue Tabelle hinzufügen müssen. Stellen wir uns also vor, dass es unserem Kunden sehr gut geht und er seine Anwendung auf viele Länder (eigentlich Sprachen) der Welt ausweitet. Das bedeutet, dass Sie eine Tablette pro Zunge hinzufügen müssen. Als Ergebnis verfügen wir über eine Datenbank, die zur Hälfte oder fast vollständig aus Hilfsübersetzungstabellen besteht: Implementierung einer mehrsprachigen Anwendung – 4 Schematische Darstellung der Filme selbst: Implementierung einer mehrsprachigen Anwendung – 5Übersetzungstabellen:
  • Russisch Implementierung einer mehrsprachigen Anwendung – 6
  • Spanisch Implementierung einer mehrsprachigen Anwendung – 7
  • Englisch Implementierung einer mehrsprachigen Anwendung – 8

2. Einer für alle

In jeder Tabelle, die zu einem bestimmten Modell gehört, wird ein Feld mit einer Kennung für das Sprachschild hinzugefügt. Dementsprechend enthält die Datenbank auch diese Tabelle mit Übersetzungen. Das Problem besteht darin, dass ein Objekt mehreren Übersetzungen (Sprachen) entsprechen kann. Infolgedessen kommt es zu Duplikaten von Entitäten, was die Logik stark verwirrt und verkompliziert, und das ist nicht gut. Wir schauen uns UML an: Implementierung einer mehrsprachigen Anwendung – 9 Tabellenfilme: Implementierung einer mehrsprachigen Anwendung – 10 Tabellensprachen: Implementierung einer mehrsprachigen Anwendung – 11

3. Spalte pro Zunge

Für jede Spalte und jede Sprache in der Tabelle wird eine eigene Übersetzungsspalte erstellt. Der Nachteil dieses Ansatzes besteht wiederum darin, dass beim Hinzufügen einer großen Anzahl von Sprachen die Datenbankstruktur jedes Mal geändert werden muss, was als schlechter Ansatz angesehen wird. Stellen Sie sich auch vor, wie übertrieben die Schilder sein werden, die eine Internationalisierung fordern. Es könnte sich lohnen, ein Modell in Betracht zu ziehen, bei dem die Anzahl der unterstützten Sprachen im Voraus bekannt ist, es nicht zu viele davon gibt und jedes Modell in allen Sprachvarianten existieren sollte. UML: Implementierung einer mehrsprachigen Anwendung – 12All-Inclusive-Tabelle: Implementierung einer mehrsprachigen Anwendung – 13

4. Externe Übersetzung

Diese Option wird durch die Anbindung externer Tools (Google Translate, Bing Translate usw.) realisiert. Es wird verwendet, wenn Sie möglichst vielen Besuchern Informationen zur Verfügung stellen müssen, und es gibt viele dieser Informationen. Sehr viel. In diesem Fall können Sie sich dafür entscheiden, Informationen nicht direkt in allen Sprachen in der Datenbank zu speichern, sondern sie dynamisch zu übersetzen. Es sei jedoch daran erinnert, dass die Qualität der maschinellen Übersetzung oft zu wünschen übrig lässt. Die Option kann nur als sehr wirtschaftlich angesehen werden (wenn keine Ressourcen für die Übersetzung jeder Veröffentlichung vorhanden sind). Ein häufiges Problem bei der korrekten Übersetzung besteht darin, dass Übersetzer, die die Sprache nicht gut beherrschen, die falsche Bedeutung eines Wortes wählen und den Benutzer verwirren, wodurch er gezwungen wird, die Bedeutung dessen, was auf der Schaltfläche steht, selbstständig herauszufinden. Es ist auch wichtig, den Satz nicht nur richtig zu übersetzen, sondern auch seine Bedeutung auf eine bestimmte Sprache und Nationalität zu übertragen. Entwickler haben in einigen Sprachen große Probleme mit den Geschlechtern. Sie müssen die Phrase im Code abhängig vom Geschlecht des Benutzers duplizieren und außerdem berücksichtigen, dass nicht nur Substantive ein Geschlecht haben, sondern auch Adjektive und Verben unterschiedlich flektiert werden. Es gibt Fälle, in denen nach Auswahl einer anderen Sprache als Englisch in der Anwendung neben den Wörtern der ausgewählten Sprache noch nicht übersetzte Elemente vorhanden sind. Noch schlimmer wird es, wenn mehrere Sprachen angezeigt werden und es sich um eine Art Babylon handelt, bei dem alles durcheinander gerät und der Nutzer die Anwendung nicht verstehen kann. Beispiel: https://cloud.google.com/translate/

5. Supportdateien auf Anwendungsebene

Zum Speichern von Übersetzungen werden separate Dateien erstellt. Es kann eine Feile pro Zunge oder eine Feile pro Zunge und Tablette (feine Zerkleinerung) sein. Diese Option wird häufig genutzt, da in diesen Dateien viele Texte gespeichert werden können und dadurch die Tabellen und die Datenbank selbst nicht aufgebläht werden. Ein weiterer Vorteil besteht darin, dass Sie für diese Felder nicht auf die Datenbank zugreifen müssen und die Dateien im Code je nach angeforderter Sprache dynamisch ersetzt werden können. Dadurch dient die Datei für uns als Wörterbuch, bei dem der Schlüssel die Sprache und der Wert der Text ist. Aber wir sind nicht auf das untenstehende „.properties“-Format beschränkt, und diese Dateiformate können stark variieren – JSON, XML usw. Die Nachteile bestehen darin, dass in diesem Fall die Normalisierung der Datenbank stark eingeschränkt wird. Außerdem hängt die Datenintegrität nicht mehr nur von der Datenbank, sondern auch vom Serialisierungsmechanismus ab. Ausgezeichneter Artikel zu diesem Thema. Beispiel für Wörterbuchdateien mit Übersetzungen: Implementierung einer mehrsprachigen Anwendung – 14
  • Englisch Implementierung einer mehrsprachigen Anwendung – 15
  • Russisch Implementierung einer mehrsprachigen Anwendung – 16
  • Spanisch Implementierung einer mehrsprachigen Anwendung – 17

6. Hilfsübersetzungstabelle für jede Tabelle

Meiner Meinung nach die flexibelste Lösung. Der Kern dieses Ansatzes besteht darin, eine separate Tabelle für Sprachen zu erstellen. Wenn es notwendig ist, die Möglichkeit von Übersetzungen für die betreffende Tabelle zu implementieren, wird eine Verknüpfung mit der Sprachtabelle erstellt, und die Verknüpfungstabelle enthält die Sprach-ID, die Element-ID und Spalten mit Übersetzungen. Es ist nicht so beängstigend, wie es klingt. Dieser Ansatz ermöglicht eine relativ flexible Erweiterbarkeit der unterstützten Sprachen. Lass uns genauer hinschauen. UML: Implementierung einer mehrsprachigen Anwendung – 18Tabelle mit Filmen: Implementierung einer mehrsprachigen Anwendung – 19Tabelle der Sprachen: Implementierung einer mehrsprachigen Anwendung – 20Tabelle der Übersetzungen: Implementierung einer mehrsprachigen Anwendung – 21 Und wie ich oben sagte, schauen wir uns die Implementierung einer der Optionen im Java-Code an (wie Sie verstehen, wird dies die letzte Option sein). In der Anwendung selbst gibt es nichts Vergleichbares: Wir wechseln von Controllern zu Dao-Ebenen. Wir werden uns die Methode create ansehen – als Beispiel reicht dies aus. Also lass uns gehen)) Unsere Essenz ist ein Film:
@Builder
@Getter
public class Movie {

   private Long id;

   private String producer;
}
Nichts Interessantes, nur die Umsetzung des Modells der ersten Tabelle. Controller mit DTO-Konvertern (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();
   }
}
In DTO übergeben wir Übersetzungen als Karten, Schlüssel ist die Sprachabkürzung, Wert ist der Übersetzungswert (Filmname). 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' : 'Матрица'}"
}
Hier sehen wir die dto-Klasse selbst, wie oben beschrieben, Karte für Übersetzungen, die restlichen Felder sind eine Anzeige des Movie-Modells. Fahren wir mit dem Movie-Dienst fort:
public interface MovieService {

   Movie create(Movie movie, Map nameList);
}
Seine Umsetzung:
@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;
   }
}
Hier sehen wir die Verwendung eines LanguageService-Dienstes relativ eines Drittanbieters, um die Sprach-ID anhand ihrer Abkürzung abzurufen. Und mit dieser Kennung speichern wir unsere Übersetzungen (auch in Form einer Karte) in der Verbindungstabelle. Schauen wir uns das DAO an:
public interface MovieDAO {

   void create(Movie movie);

   void createTranslator(Long movieId, Map<Long,String> nameTranslations);
}
Implementierung:
@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));
   }
}
Hier sehen wir die Bewahrung des Wesens und der Sprachen dafür (Wörterbuch). Und ja, hier wird Spring JDBC verwendet: Ich halte es für Anfänger für vorzuziehen, da es transparenter ist. Kommen wir nun zu einem „Drittanbieter“-Dienst. Sprachdienst:
public interface LanguageService {

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

   @Override
   public Long getIdByLangCode(String lang) {
       return languageDAO.getIdByLangCode(lang);
   }
}
Nichts Besonderes, Suche nach verkürztem Namen. DAO:
public interface LanguageDAO {

   Long getIdByLangCode(String lang);
}
Implementierung:
@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);
   }
}
Struktur: Implementierung einer mehrsprachigen Anwendung – 23 Alle oben beschriebenen Modelle haben das Recht auf Leben. Sie müssen je nach Situation entscheiden, welches Sie verwenden möchten. Das ist natürlich noch nicht alles: Es gibt noch viele weitere unterschiedliche Ansätze, darunter die Verwendung unterschiedlicher Datenbanken für unterschiedliche Sprachen, die Verwendung von Caches, unterschiedlichen Frameworks und so weiter. Das ist alles für mich heute und... Implementierung einer mehrsprachigen Anwendung – 24
Kommentare
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION