Bu gün çoxdillilik haqqında danışacağıq. Bəs bu nədir?
Çoxdillilik, başqa sözlə,
beynəlmiləlləşmə , proqram məntiqini dəyişdirmədən bir neçə dil üçün uyğunlaşdırıla bilən bir tətbiqin inkişafının bir hissəsidir. Vəziyyəti nəzərdən keçirin: siz, məsələn, rus, ingilis və ispan dillərində danışılan çoxlu sayda ölkələrin sakinləri üçün böyük bir ticarət şirkəti üçün veb tətbiqi yaradırsınız. Bunu bütün istifadəçilər üçün rahat etmək lazımdır. İdeya belədir: rusdilli oxucunun məlumatlarınızı rus dilində görmək imkanı olmalıdır, amerikalı üçün materialı ingilis dilində, ispan üçün isə ispan dilində oxumaq daha rahat olacaq (gözlənilmədən, elə deyilmi?)
Bu gün
bir neçə beynəlmiləlləşdirmə modelini nəzərdən keçirək və onlardan biri üçün (ən çox bəyəndiyim budur :) Gəlin Java-da tətbiqinə baxaq. Bir qvineya donuzu olaraq bu gün bir film məlumat lövhəsinə sahib olacağıq. Çox azğın olmayaq, ona görə də çox danışanlarımız olmayacaq. Məsələn, bu yaxşıdır. Və filmlərin adlarını tərcümə edəcəyik (rejissorlar - əlavələr üçün):
1. Hər dil üçün tərcüməsi olan cədvəl
Bu modelin mahiyyəti: hər bir dil üçün verilənlər bazasında tərcümə tələb edən bütün xanaları ehtiva edən ayrıca cədvəl var. Bu metodun dezavantajı ondan ibarətdir ki, biz hər dəfə yeni dil əlavə etdikdə yeni cədvəl əlavə etməliyik. Yəni, təsəvvür edək ki, müştərimiz çox yaxşı işləyir və o, tətbiqini dünyanın bir çox ölkələrində (əslində, dillərdə) genişləndirir. Bu o deməkdir ki, hər dilə bir tablet əlavə etməlisiniz. Nəticədə, yarım və ya demək olar ki, tamamilə köməkçi tərcümə cədvəllərindən ibarət verilənlər bazasına sahib olacağıq:
Filmlərin özlərinin sxemi: Tərcümə cədvəlləri:
- rus
- ispan dili
- İngilis dili
2. Hamı üçün bir
Müəyyən bir modelə aid olan hər bir cədvəldə dil lövhəsi üçün identifikatoru olan bir sahə əlavə olunur. Müvafiq olaraq, verilənlər bazası bu cədvəli tərcümələrlə də ehtiva edir. Problem ondadır ki, bir obyekt bir neçə tərcüməyə (dilə) uyğun gələ bilər. Nəticədə, subyektlərin təkrarlanması baş verəcək və bu, məntiqi çox çaşdırır və çətinləşdirir və bu yaxşı deyil.
Biz UML-ə baxırıq: Cədvəl filmləri: Cədvəl dilləri:
3. Dil başına sütun
Cədvəldəki hər dil üçün hər sütun üçün ayrıca tərcümə sütunu yaradılır. Bu yanaşmanın dezavantajı ondan ibarətdir ki, yenə də çoxlu sayda dil əlavə edilərsə, verilənlər bazası strukturu hər dəfə dəyişdirilməlidir və bu, pis yanaşma hesab olunur. Təsəvvür edin ki, beynəlmiləlləşmə tələb edən əlamətlər nə qədər şişirdiləcək. Dəstəklənən dillərin sayının əvvəlcədən məlum olduğu, onların çox olmadığı və hər bir modelin bütün dil varyasyonlarında mövcud olduğu bir modeli nəzərdən keçirməyə dəyər ola bilər.
UML: Hər şey daxil cədvəl:
4. Xarici tərcümə
Bu seçim xarici alətləri (Google translate, Bing translate və s.) birləşdirməklə həyata keçirilir. Mümkün qədər çox ziyarətçiyə məlumat vermək lazım olduqda istifadə olunur və bu məlumatların çoxu var. Bu qədər çox. Bu halda, məlumat bazasında məlumatı bütün dillərdə bilavasitə saxlamaq deyil, dinamik şəkildə tərcümə etmək qərarına gələ bilərsiniz. Ancaq yadda saxlamaq lazımdır ki, maşın tərcüməsinin keyfiyyəti çox vaxt arzuolunanları tərk edir. Seçim yalnız çox qənaətcil hesab edilə bilər (hər bir nəşri tərcümə etmək üçün heç bir resurs olmadıqda). Düzgün tərcümə baxımından ümumi problem dili yaxşı bilməyən tərcüməçilərin sözün yanlış mənasını seçməsi və istifadəçini çaşdırması, onu düymədə yazılanların mənasını müstəqil anlamağa məcbur etməsidir. Cümləni təkcə düzgün tərcümə etmək deyil, həm də onun mənasını konkret bir dilə və milliyyətə çatdırmaq da vacibdir. Tərtibatçıların bəzi dillərdə cinslərlə bağlı çoxlu problemləri var. Onlar koddakı ifadəni istifadəçinin cinsindən asılı olaraq təkrarlamalı, həm də nəzərə almalıdırlar ki, təkcə isimlər cinsiyyətə malik deyil, həm də sifət və fellərin fərqli şəkildə fleksiyası olur. Tətbiqdə ingilis dilindən başqa bir dil seçərək, seçilmiş dilin sözləri ilə yanaşı hələ də tərcümə olunmamış elementlərin qaldığı hallar var. Bir neçə dil göstərilsə və hər şeyin qarışdığı və istifadəçinin tətbiqi başa düşə bilmədiyi bir növ Babylon olduğu ortaya çıxsa, daha da pisdir. Məsələn:
https://cloud.google.com/translate/
5. Tətbiq səviyyəsində dəstək faylları
Tərcümələri saxlamaq üçün ayrıca fayllar yaradılır. Bu, hər dil üçün bir fayl və ya tablet üçün hər dil üçün bir fayl ola bilər (incə sarsıdıcı). Bu seçim tez-tez bu fayllarda bir çox mətnin saxlanıla bilməsi səbəbindən istifadə olunur, yəni cədvəllər və verilənlər bazası özü şişməyəcəkdir. Başqa bir rahatlıq ondan ibarətdir ki, bu sahələr üçün verilənlər bazasını döymək lazım deyil və koddakı fayllar tələb olunan dildən asılı olaraq dinamik şəkildə dəyişdirilə bilər. Nəticədə, fayl bizim üçün lüğət rolunu oynayır, burada açar dil, dəyər mətndir. Lakin biz aşağıdakı ".properties" formatı ilə məhdudlaşmırıq və bu fayl formatları geniş şəkildə dəyişə bilər - JSON, XML və s. Dezavantajlar odur ki, bu halda verilənlər bazasının normallaşması çox azalır. Həmçinin, məlumatların bütövlüyü artıq yalnız verilənlər bazasından deyil, həm də seriallaşdırma mexanizmindən asılıdır.
Bu mövzuda əla məqalə Tərcümələri olan lüğət fayllarının nümunəsi:
- İngilis dili
- rus
- ispan dili
6. Hər bir cədvəl üçün köməkçi tərcümə cədvəli
Məncə, ən çevik həll. Bu yanaşmanın mahiyyəti dillər üçün ayrıca cədvəl yaratmaqdır. Sözügedən cədvəl üçün tərcümələrin mümkünlüyünü həyata keçirmək lazım olduqda, dil cədvəli ilə bir keçid yaradılır və keçid cədvəlində dil id, element id və tərcümələri olan sütunlar var. Bu səsləndiyi qədər qorxulu deyil. Bu yanaşma dəstəklənən dillərin kifayət qədər çevik genişlənməsinə imkan verir. Gəlin daha yaxından nəzər salaq.
UML: Filmlərlə cədvəl: Dillər cədvəli: Tərcümələr cədvəli: Və yuxarıda dediyim kimi, Java kodunda variantlardan birinin həyata keçirilməsinə baxaq (başa düşdüyünüz kimi, bu, sonuncu variant olacaq). Tətbiqin özündə belə bir şey yoxdur: biz nəzarətçilərdən tao təbəqələrinə keçəcəyik. Yaratma metoduna baxacağıq - misal üçün bu kifayət edəcək. Elə isə gedək)) Bizim mahiyyətimiz filmdir:
@Builder
@Getter
public class Movie {
private Long id;
private String producer;
}
Maraqlı bir şey yoxdur, sadəcə birinci cədvəlin modelini həyata keçirmək.
dto (Data Transfer Object) çeviriciləri olan nəzarətçi:
@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();
}
}
DTO-da biz tərcümələri xəritə kimi keçirik, açar dil abbreviaturasıdır, dəyər tərcümə dəyəridir (film adı).
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;
}
Burada yuxarıda yazıldığı kimi dto sinifinin özünü görürük, tərcümələr üçün xəritə, qalan sahələr Film modelinin ekranıdır.Gəlin
film xidmətinə keçək:
public interface MovieService {
Movie create(Movie movie, Map nameList);
}
Onun həyata keçirilməsi:
@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;
}
}
Burada dil identifikatorunu abbreviatura ilə əldə etmək üçün nisbətən üçüncü tərəfin LanguageService xidmətinin istifadəsini görürük. Və bu identifikatorla tərcümələrimizi (həmçinin xəritə şəklində) əlaqə cədvəlində saxlayırıq.
Gəlin DAO-ya baxaq:
public interface MovieDAO {
void create(Movie movie);
void createTranslator(Long movieId, Map<Long,String> nameTranslations);
}
İcra:
@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));
}
}
Burada mahiyyətin və onun üçün dillərin qorunub saxlanmasını görürük (lüğət). Bəli, burada Spring JDBC istifadə olunur: daha şəffaf olduğu üçün onu yeni başlayanlar üçün üstünlük hesab edirəm. Gəlin “üçüncü tərəf” xidmətinə keçək.
Dil xidməti:
public interface LanguageService {
Long getIdByLangCode(String lang);
}
İcra:
@Service
@RequiredArgsConstructor
public class LanguageServiceImpl implements LanguageService {
private final LanguageDAO languageDAO;
@Override
public Long getIdByLangCode(String lang) {
return languageDAO.getIdByLangCode(lang);
}
}
Xüsusi bir şey yoxdur, qısaldılmış adla axtarın.
DAO:
public interface LanguageDAO {
Long getIdByLangCode(String lang);
}
İcra:
@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: Yuxarıda təsvir edilən bütün modellərin yaşamaq hüququ var. Vəziyyətdən asılı olaraq hansını istifadə edəcəyinizə qərar verməlisiniz. Əlbəttə ki, bu, hamısı deyil: daha çox fərqli yanaşmalar var, o cümlədən müxtəlif dillər üçün müxtəlif verilənlər bazalarından istifadə, keşlərdən, fərqli çərçivələrdən istifadə etmək və s. Bu gün mənim üçün hamısı budur və...
GO TO FULL VERSION