JavaRush /Blog Java /Random-VI /Triển khai ứng dụng đa ngôn ngữ

Triển khai ứng dụng đa ngôn ngữ

Xuất bản trong nhóm
Triển khai ứng dụng đa ngôn ngữ - 1

Hôm nay chúng ta sẽ nói về đa ngôn ngữ. Vậy đo la cai gi?

Nói cách khác, đa ngôn ngữ là quốc tế hóa , là một phần của việc phát triển một ứng dụng có thể điều chỉnh cho phù hợp với nhiều ngôn ngữ mà không làm thay đổi logic chương trình. Hãy xem xét tình huống: bạn đang tạo một ứng dụng web cho một công ty thương mại lớn dành cho cư dân của nhiều quốc gia, chẳng hạn như các ngôn ngữ như tiếng Nga, tiếng Anh và tiếng Tây Ban Nha được sử dụng. Bạn cần làm cho nó thuận tiện cho tất cả người dùng. Ý tưởng là thế này: một độc giả nói tiếng Nga sẽ có thể xem dữ liệu của bạn bằng tiếng Nga, một người Mỹ sẽ thoải mái hơn khi đọc tài liệu bằng tiếng Anh và một người Tây Ban Nha - bằng tiếng Tây Ban Nha (thật bất ngờ, phải không?) Hãy xem xét một số mô hình quốc tế hóaTriển khai ứng dụng đa ngôn ngữ - 2 ngay hôm nay và đối với một trong số chúng (cái mà tôi thích nhất :) Hãy xem cách triển khai trong Java. Như một con chuột lang, hôm nay chúng ta sẽ có một bảng dữ liệu phim. Chúng ta đừng quá biến thái sẽ không có nhiều người nói. Ví dụ, điều đó ổn thôi. Và chúng tôi sẽ dịch tên các bộ phim (đạo diễn - cho phần ngoại truyện): Triển khai ứng dụng đa ngôn ngữ - 3

1. Bảng dịch cho từng ngôn ngữ

Bản chất của mô hình này: mỗi ngôn ngữ có một bảng riêng trong cơ sở dữ liệu, chứa tất cả các ô cần dịch. Nhược điểm của phương pháp này là mỗi khi thêm ngôn ngữ mới, chúng ta cần thêm bảng mới. Nghĩa là, hãy tưởng tượng rằng khách hàng của chúng ta đang làm việc rất tốt và anh ta đang mở rộng ứng dụng của mình sang nhiều quốc gia (thực tế là các ngôn ngữ) trên thế giới. Điều này có nghĩa là bạn sẽ cần thêm một viên cho mỗi lưỡi. Kết quả là chúng ta sẽ có một cơ sở dữ liệu một nửa hoặc gần như hoàn toàn bao gồm các bảng dịch phụ trợ: Triển khai ứng dụng đa ngôn ngữ - 4 Sơ đồ của các bộ phim: Triển khai ứng dụng đa ngôn ngữ - 5Bảng dịch:
  • tiếng Nga Triển khai ứng dụng đa ngôn ngữ - 6
  • người Tây Ban Nha Triển khai ứng dụng đa ngôn ngữ - 7
  • Tiếng Anh Triển khai ứng dụng đa ngôn ngữ - 8

2. Một cho tất cả

Trong mỗi bảng thuộc về một kiểu máy cụ thể, một trường có mã định danh cho bảng ngôn ngữ sẽ được thêm vào. Theo đó, cơ sở dữ liệu cũng chứa bảng này với các bản dịch. Vấn đề là một đối tượng có thể tương ứng với một số bản dịch (ngôn ngữ). Kết quả là sẽ có sự trùng lặp của các thực thể, điều này rất gây nhầm lẫn và phức tạp về mặt logic, và điều này là không tốt. Chúng tôi xem xét UML: Triển khai ứng dụng đa ngôn ngữ - 9 Phim bảng: Triển khai ứng dụng đa ngôn ngữ - 10 Ngôn ngữ bảng: Triển khai ứng dụng đa ngôn ngữ - 11

3. Cột mỗi lưỡi

Một cột dịch riêng được tạo cho mỗi cột cho từng ngôn ngữ trong bảng. Nhược điểm của phương pháp này là, một lần nữa, nếu một số lượng lớn ngôn ngữ được thêm vào, cấu trúc cơ sở dữ liệu sẽ cần phải thay đổi mỗi lần và đây được coi là một cách tiếp cận tồi. Cũng hãy tưởng tượng các dấu hiệu đòi quốc tế hóa sẽ bị thổi phồng như thế nào. Có thể đáng để xem xét một mô hình trong đó số lượng ngôn ngữ được hỗ trợ đã được biết trước, không có quá nhiều ngôn ngữ và mỗi mô hình phải tồn tại ở tất cả các biến thể ngôn ngữ. UML: Triển khai ứng dụng đa ngôn ngữ - 12Bảng bao gồm tất cả: Triển khai ứng dụng đa ngôn ngữ - 13

4. Dịch thuật bên ngoài

Tùy chọn này được thực hiện bằng cách kết nối các công cụ bên ngoài (Google dịch, Bing dịch, v.v.). Nó được sử dụng nếu bạn cần cung cấp thông tin cho càng nhiều khách truy cập càng tốt và có rất nhiều thông tin này. Rất nhiều. Trong trường hợp này, bạn có thể quyết định không lưu trữ trực tiếp thông tin trong cơ sở dữ liệu bằng tất cả các ngôn ngữ mà dịch động nó. Nhưng điều đáng ghi nhớ là chất lượng của bản dịch máy thường không được như mong muốn. Tùy chọn này chỉ có thể được coi là rất tiết kiệm (khi không có nguồn lực để dịch từng ấn phẩm). Một vấn đề thường gặp theo quan điểm của bản dịch chính xác là những người dịch không biết rõ về ngôn ngữ sẽ chọn sai nghĩa của từ và khiến người dùng nhầm lẫn, buộc họ phải độc lập tìm ra ý nghĩa của những gì được viết trên nút. Điều quan trọng không chỉ là dịch chính xác câu mà còn phải đưa ý nghĩa của nó sang một ngôn ngữ và quốc tịch cụ thể. Các nhà phát triển gặp rất nhiều vấn đề về giới tính ở một số ngôn ngữ. Họ phải sao chép cụm từ trong mã tùy thuộc vào giới tính của người dùng, đồng thời tính đến việc không chỉ danh từ có giới tính mà cả tính từ và động từ cũng được biến cách khác nhau. Có những trường hợp, khi đã chọn một ngôn ngữ không phải tiếng Anh trong ứng dụng, cùng với các từ của ngôn ngữ đã chọn, vẫn có những phần tử chưa được dịch. Thậm chí còn tệ hơn nếu một số ngôn ngữ được hiển thị và nó trở thành một loại Babylon, nơi mọi thứ bị xáo trộn và người dùng không thể hiểu được ứng dụng. Ví dụ: https://cloud.google.com/translate/

5. Tệp hỗ trợ cấp ứng dụng

Các tập tin riêng biệt được tạo ra để lưu trữ bản dịch. Nó có thể là một tệp trên mỗi lưỡi hoặc một tệp trên mỗi lưỡi trên mỗi viên (nghiền mịn). Tùy chọn này thường được sử dụng do thực tế là nhiều văn bản có thể được lưu trữ trong các tệp này, điều đó có nghĩa là các bảng và cơ sở dữ liệu sẽ không bị cồng kềnh. Một tiện ích khác là bạn không cần phải gõ vào cơ sở dữ liệu cho các trường này và các tệp trong mã có thể được thay thế động tùy thuộc vào ngôn ngữ được yêu cầu. Kết quả là, tệp đóng vai trò như một từ điển cho chúng ta, trong đó khóa là ngôn ngữ, giá trị là văn bản. Nhưng chúng tôi không giới hạn ở định dạng ".properties" bên dưới và các định dạng tệp này có thể rất khác nhau - JSON, XML, v.v. Nhược điểm là trong trường hợp này việc chuẩn hóa cơ sở dữ liệu bị giảm đi rất nhiều. Ngoài ra, tính toàn vẹn dữ liệu không còn chỉ phụ thuộc vào cơ sở dữ liệu mà còn phụ thuộc vào cơ chế tuần tự hóa. Bài viết xuất sắc về chủ đề này Ví dụ về tệp từ điển có bản dịch: Triển khai ứng dụng đa ngôn ngữ - 14
  • Tiếng Anh Triển khai ứng dụng đa ngôn ngữ - 15
  • tiếng Nga Triển khai ứng dụng đa ngôn ngữ - 16
  • người Tây Ban Nha Triển khai ứng dụng đa ngôn ngữ - 17

6. Bảng dịch phụ trợ cho từng bảng

Theo tôi, giải pháp linh hoạt nhất. Bản chất của phương pháp này là tạo một bảng riêng cho các ngôn ngữ. Khi cần triển khai khả năng dịch cho bảng được đề cập, một liên kết sẽ được tạo với bảng ngôn ngữ và bảng liên kết chứa id ngôn ngữ, id thành phần và các cột có bản dịch. Nó không đáng sợ như người ta tưởng. Cách tiếp cận này cho phép mở rộng khá linh hoạt các ngôn ngữ được hỗ trợ. Chúng ta hãy xem xét kỹ hơn. UML: Triển khai ứng dụng đa ngôn ngữ - 18Bảng có phim: Triển khai ứng dụng đa ngôn ngữ - 19Bảng ngôn ngữ: Triển khai ứng dụng đa ngôn ngữ - 20Bảng dịch: Triển khai ứng dụng đa ngôn ngữ - 21 Và, như tôi đã nói ở trên, hãy xem việc triển khai một trong các tùy chọn trong mã Java (như bạn hiểu, đây sẽ là tùy chọn cuối cùng). Không có gì giống như vậy trong chính ứng dụng: chúng ta sẽ chuyển từ bộ điều khiển sang lớp tao. Chúng ta sẽ xem xét phương thức tạo - để lấy ví dụ, điều này là đủ. Vậy đi thôi)) Bản chất của chúng tôi là một bộ phim:
@Builder
@Getter
public class Movie {

   private Long id;

   private String producer;
}
Không có gì thú vị, chỉ thực hiện mô hình của bảng đầu tiên. Bộ điều khiển với bộ chuyển đổi dto (Đối tượng truyền dữ liệu):
@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();
   }
}
Trong DTO, chúng tôi chuyển các bản dịch dưới dạng bản đồ, khóa là tên viết tắt của ngôn ngữ, giá trị là giá trị dịch (tên phim). 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' : 'Матрица'}"
}
Ở đây chúng ta thấy chính lớp dto, như đã viết ở trên, bản đồ cho các bản dịch, các trường còn lại là hiển thị của mô hình Phim. Hãy chuyển sang dịch vụ phim:
public interface MovieService {

   Movie create(Movie movie, Map nameList);
}
Việc thực hiện 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;
   }
}
Ở đây chúng ta thấy việc sử dụng dịch vụ LanguageService tương đối của bên thứ ba để truy xuất id ngôn ngữ bằng chữ viết tắt của nó. Và với mã định danh này, chúng tôi lưu bản dịch của mình (cũng ở dạng bản đồ) vào bảng kết nối. Hãy nhìn vào DAO:
public interface MovieDAO {

   void create(Movie movie);

   void createTranslator(Long movieId, Map<Long,String> nameTranslations);
}
Thực hiệ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));
   }
}
Ở đây chúng ta thấy sự bảo tồn bản chất và ngôn ngữ cho nó (từ điển). Và vâng, Spring JDBC được sử dụng ở đây: Tôi cho rằng nó thích hợp hơn cho người mới bắt đầu vì nó minh bạch hơn. Hãy chuyển sang dịch vụ “bên thứ ba”. Dịch vụ ngôn ngữ:
public interface LanguageService {

   Long getIdByLangCode(String lang);
}
Thực hiện:
@Service
@RequiredArgsConstructor
public class LanguageServiceImpl implements LanguageService {
   private final LanguageDAO languageDAO;

   @Override
   public Long getIdByLangCode(String lang) {
       return languageDAO.getIdByLangCode(lang);
   }
}
Không có gì đặc biệt, tìm kiếm theo tên rút gọn. ĐÀO:
public interface LanguageDAO {

   Long getIdByLangCode(String lang);
}
Thực hiệ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);
   }
}
Cấu trúc: Triển khai ứng dụng đa ngôn ngữ - 23 Tất cả các mô hình được mô tả ở trên đều có quyền sống. Bạn cần phải quyết định sử dụng cái nào dựa trên tình huống. Tất nhiên, đó không phải là tất cả: còn có nhiều cách tiếp cận khác nhau, bao gồm sử dụng các cơ sở dữ liệu khác nhau cho các ngôn ngữ khác nhau, sử dụng bộ nhớ đệm, các khung công tác khác nhau, v.v. Đó là tất cả đối với tôi ngày hôm nay và... Triển khai ứng dụng đa ngôn ngữ - 24
Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION