JavaRush /وبلاگ جاوا /Random-FA /اجرای برنامه چند زبانه

اجرای برنامه چند زبانه

در گروه منتشر شد
اجرای برنامه چند زبانه - 1

امروز در مورد چندزبانگی صحبت خواهیم کرد. پس چیست؟

چندزبانگی، به عبارت دیگر، بین المللی سازی ، بخشی از توسعه برنامه ای است که می تواند برای چندین زبان بدون تغییر منطق برنامه سازگار شود. وضعیت را در نظر بگیرید: شما در حال ایجاد یک برنامه وب برای یک شرکت تجاری بزرگ برای ساکنان تعداد زیادی از کشورها هستید که به عنوان مثال در آنها به زبان هایی مانند روسی، انگلیسی و اسپانیایی صحبت می شود. شما باید آن را برای همه کاربران راحت کنید. ایده این است: یک خواننده روسی زبان باید این فرصت را داشته باشد که داده های شما را به زبان روسی ببیند، برای یک آمریکایی راحت تر است که مطالب را به زبان انگلیسی بخواند و برای یک اسپانیایی - به زبان اسپانیایی (به طور غیرمنتظره، درست است؟) بگذارید اجرای برنامه چند زبانه - 2امروز چندین مدل بین‌المللی‌سازی را در نظر می‌گیریم ، و برای یکی از آنها (که بیشتر آن را دوست دارم :) اجازه دهید به پیاده‌سازی در جاوا نگاه کنیم. به عنوان یک خوکچه هندی امروز یک تابلوی اطلاعات فیلم خواهیم داشت. بیایید زیاد منحرف نشویم، بنابراین سخنرانان زیادی نخواهیم داشت. مثلاً اشکالی ندارد. و ما نام فیلم ها (کارگردان - برای موارد اضافی) را ترجمه خواهیم کرد: اجرای برنامه چند زبانه - 3

1. جدول با ترجمه برای هر زبان

ماهیت این مدل: هر زبان یک جدول جداگانه در پایگاه داده دارد که شامل تمام سلول هایی است که نیاز به ترجمه دارند. عیب این روش این است که هر بار که یک زبان جدید اضافه می کنیم، باید یک جدول جدید اضافه کنیم. یعنی بیایید تصور کنیم که مشتری ما خیلی خوب کار می کند و برنامه خود را به بسیاری از کشورهای جهان (در واقع زبان ها) گسترش می دهد. این بدان معناست که شما باید به ازای هر زبان یک قرص اضافه کنید. در نتیجه، ما یک پایگاه داده نصف یا تقریباً به طور کامل از جداول ترجمه کمکی خواهیم داشت: اجرای برنامه چند زبانه - 4 شماتیک خود فیلم ها: اجرای برنامه چند زبانه - 5جداول ترجمه:
  • روسی اجرای برنامه چند زبانه - 6
  • اسپانیایی اجرای برنامه چند زبانه - 7
  • انگلیسی اجرای برنامه چند زبانه - 8

2. یکی برای همه

در هر جدولی که متعلق به یک مدل خاص است، یک فیلد با یک شناسه برای صفحه زبان اضافه می شود. بر این اساس پایگاه داده حاوی این جدول با ترجمه نیز می باشد. مشکل این است که یک شی می تواند با چندین ترجمه (زبان) مطابقت داشته باشد. در نتیجه کپی شدن موجودیت ها وجود خواهد داشت و این به شدت منطق را گیج و پیچیده می کند و این خوب نیست. ما به UML نگاه می کنیم: اجرای برنامه چند زبانه - 9 فیلم های جدول: اجرای برنامه چند زبانه - 10 زبان های جدول: اجرای برنامه چند زبانه - 11

3. ستون در هر زبان

یک ستون ترجمه جداگانه برای هر ستون برای هر زبان در جدول ایجاد می شود. عیب این روش این است که مجدداً اگر تعداد زیادی زبان اضافه شود، ساختار پایگاه داده هر بار نیاز به تغییر دارد و این رویکرد بدی تلقی می شود. همچنین تصور کنید که نشانه های بین المللی شدن چقدر متورم خواهند شد. شاید ارزش در نظر گرفتن مدلی را داشته باشد که در آن تعداد زبان های پشتیبانی شده از قبل مشخص باشد، تعداد زیادی از آنها وجود نداشته باشد و هر مدل باید در همه انواع زبان وجود داشته باشد. UML: اجرای برنامه چند زبانه - 12جدول همه شامل: اجرای برنامه چند زبانه - 13

4. ترجمه خارجی

این گزینه با اتصال ابزارهای خارجی (گوگل ترنسلیت، ترنسل بینگ و ...) پیاده سازی می شود. در صورت نیاز به ارائه اطلاعات به بیشترین تعداد بازدید کننده استفاده می شود و از این اطلاعات بسیار زیاد است. خیلی زیاد. در این صورت، می توانید تصمیم بگیرید که اطلاعات را مستقیماً در همه زبان ها در پایگاه داده ذخیره نکنید، بلکه آن را به صورت پویا ترجمه کنید. اما شایان ذکر است که کیفیت ترجمه ماشینی اغلب چیزهای زیادی را برای دلخواه باقی می گذارد. این گزینه را فقط می توان بسیار مقرون به صرفه در نظر گرفت (زمانی که منابعی برای ترجمه هر نشریه وجود نداشته باشد). یک مشکل رایج از نظر ترجمه صحیح این است که مترجمانی که زبان را به خوبی نمی دانند، معنای اشتباه یک کلمه را انتخاب می کنند و کاربر را گیج می کنند و او را مجبور می کنند که به طور مستقل معنای آنچه روی دکمه نوشته شده است را دریابد. همچنین نه تنها ترجمه صحیح جمله، بلکه رساندن معنای آن به یک زبان و ملیت خاص نیز مهم است. توسعه دهندگان در برخی از زبان ها با جنسیت مشکلات زیادی دارند. آنها باید بسته به جنسیت کاربر عبارت را در کد تکرار کنند و همچنین در نظر بگیرند که نه تنها اسم ها دارای جنسیت هستند، بلکه صفت ها و افعال نیز به طور متفاوتی عطف می شوند. مواردی وجود دارد که با انتخاب زبانی غیر از انگلیسی در برنامه، به همراه کلمات زبان انتخاب شده، هنوز عناصر ترجمه نشده وجود دارد. حتی بدتر از آن است که چندین زبان نمایش داده شود و معلوم شود که نوعی بابیلون است، جایی که همه چیز قاطی شده است و کاربر نمی تواند برنامه را درک کند. به عنوان مثال: https://cloud.google.com/translate/

5. فایل های پشتیبانی سطح برنامه

فایل های جداگانه ای برای ذخیره ترجمه ها ایجاد می شود. این می تواند یک فایل در هر زبان یا یک فایل در هر زبان در هر قرص (خرد کردن خوب) باشد. این گزینه اغلب به دلیل اینکه متون زیادی را می توان در این فایل ها ذخیره کرد استفاده می شود که به این معنی است که جداول و خود پایگاه داده متورم نمی شوند. راحتی دیگر این است که برای این فیلدها نیازی به ضربه زدن به پایگاه داده ندارید و بسته به زبان درخواستی می توان فایل های موجود در کد را به صورت پویا جایگزین کرد. در نتیجه، فایل به عنوان یک فرهنگ لغت برای ما عمل می کند که در آن کلید زبان است، مقدار آن متن است. اما ما محدود به قالب ".properties" در زیر نیستیم، و این فرمت‌های فایل می‌توانند بسیار متفاوت باشند - JSON، XML، و غیره. معایب آن این است که در این حالت عادی سازی پایگاه داده تا حد زیادی کاهش می یابد. همچنین، یکپارچگی داده ها دیگر تنها به پایگاه داده بستگی ندارد، بلکه به مکانیسم سریال سازی نیز بستگی دارد. مقاله عالی در مورد این موضوع نمونه ای از فایل های فرهنگ لغت با ترجمه: اجرای برنامه چند زبانه - 14
  • انگلیسی اجرای برنامه چند زبانه - 15
  • روسی اجرای برنامه چند زبانه - 16
  • اسپانیایی اجرای برنامه چند زبانه - 17

6. جدول ترجمه کمکی برای هر جدول

به نظر من، منعطف ترین راه حل. ماهیت این رویکرد ایجاد یک جدول جداگانه برای زبان ها است. در مواقعی که نیاز به پیاده سازی امکان ترجمه برای جدول مورد نظر باشد، پیوندی با جدول زبان ایجاد می شود و جدول پیوند حاوی شناسه زبان، شناسه عنصر و ستون هایی با ترجمه است. آنقدرها هم که به نظر می رسد ترسناک نیست. این رویکرد امکان گسترش نسبتاً انعطاف پذیر زبان های پشتیبانی شده را فراهم می کند. بیایید نگاه دقیق تری بیندازیم. UML: اجرای برنامه چند زبانه - 18جدول با فیلم‌ها: اجرای برنامه چند زبانه - 19جدول زبان‌ها: اجرای برنامه چند زبانه - 20جدول ترجمه‌ها: اجرای برنامه چند زبانه - 21 و همانطور که در بالا گفتم، اجازه دهید اجرای یکی از گزینه‌ها در کد جاوا را بررسی کنیم (همانطور که متوجه شدید، این آخرین گزینه خواهد بود). در خود برنامه چیزی شبیه به آن وجود ندارد: ما از کنترلرها به لایه های دائو خواهیم رفت. ما به روش ایجاد نگاه خواهیم کرد - برای مثال این کافی است. پس بریم)) ذات ما یک فیلم است:
@Builder
@Getter
public class Movie {

   private Long id;

   private String producer;
}
چیز جالبی نیست، فقط پیاده سازی مدل جدول اول است. کنترل کننده با مبدل های 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();
   }
}
در DTO ترجمه ها را به عنوان نقشه ارسال می کنیم، کلید مخفف زبان است، مقدار ارزش ترجمه (نام فیلم) است. 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' : 'Матрица'}"
}
در اینجا ما خود کلاس dto را می بینیم، همانطور که در بالا نوشته شده است، نقشه برای ترجمه ها، فیلدهای باقی مانده نمایشی از مدل Movie هستند. بیایید به سرویس فیلم برویم:
public interface MovieService {

   Movie create(Movie movie, Map nameList);
}
اجرای آن:
@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;
   }
}
در اینجا ما شاهد استفاده از یک سرویس LanguageService نسبتا شخص ثالث برای بازیابی شناسه زبان با مخفف آن هستیم. و با این شناسه ترجمه های خود را (همچنین به صورت نقشه) در جدول اتصال ذخیره می کنیم. بیایید به DAO نگاه کنیم:
public interface MovieDAO {

   void create(Movie movie);

   void createTranslator(Long movieId, Map<Long,String> nameTranslations);
}
پیاده سازی:
@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));
   }
}
در اینجا ما شاهد حفظ ذات و زبان ها برای آن هستیم (فرهنگ لغت). و بله، Spring JDBC در اینجا استفاده می شود: من آن را برای مبتدیان ترجیح می دهم، زیرا شفاف تر است. بیایید به یک سرویس "شخص ثالث" برویم. خدمات زبان:
public interface LanguageService {

   Long getIdByLangCode(String lang);
}
پیاده سازی:
@Service
@RequiredArgsConstructor
public class LanguageServiceImpl implements LanguageService {
   private final LanguageDAO languageDAO;

   @Override
   public Long getIdByLangCode(String lang) {
       return languageDAO.getIdByLangCode(lang);
   }
}
چیز خاصی نیست، با نام کوتاه شده جستجو کنید. DAO:
public interface LanguageDAO {

   Long getIdByLangCode(String lang);
}
پیاده سازی:
@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);
   }
}
ساختار: اجرای برنامه چند زبانه - 23 تمام مدل هایی که در بالا توضیح داده شد حق حیات دارند. شما باید بر اساس شرایط تصمیم بگیرید که از کدام یک استفاده کنید. البته، این همه ماجرا نیست: رویکردهای متفاوت تری وجود دارد، از جمله استفاده از پایگاه داده های مختلف برای زبان های مختلف، استفاده از حافظه پنهان، چارچوب های مختلف و غیره. امروز برای من همین است و... اجرای برنامه چند زبانه - 24
نظرات
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION