JavaRush /בלוג Java /Random-HE /יישום יישום רב לשוני

יישום יישום רב לשוני

פורסם בקבוצה
יישום יישום רב לשוני - 1

היום נדבר על רב לשוניות. אז מה זה?

רב לשוניות, במילים אחרות, בינלאומיות , היא חלק מפיתוח אפליקציה שניתן להתאים למספר שפות מבלי לשנות את היגיון התוכנית. שקול את המצב: אתה יוצר יישום אינטרנט עבור חברת סחר גדולה עבור תושבי מספר רב של מדינות שבהן, למשל, מדובר בשפות כמו רוסית, אנגלית וספרדית. אתה צריך לעשות את זה נוח עבור כל המשתמשים. הרעיון הוא כזה: קורא דובר רוסית אמור להיות מסוגל לראות את הנתונים שלך ברוסית, אמריקאי יהיה נוח יותר לקרוא את החומר באנגלית, ולספרדי - בספרדית (באופן בלתי צפוי, נכון?) בואו נשקול כמה מודלים של בינאוםיישום יישום רב לשוני - 2 היום , ולאחד מהם (שזה הכי אני אוהב את זה :) בואו נסתכל על היישום בג'אווה. בתור שפן ניסיונות, היום תהיה לנו לוחית נתונים של סרט. בואו לא נהיה סוטים מדי, אז לא יהיו לנו הרבה דוברים. למשל, זה בסדר. ונתרגם את שמות הסרטים (במאים - לתוספות): יישום יישום רב לשוני - 3

1. טבלה עם תרגום לכל שפה

מהות המודל הזה: לכל שפה יש טבלה נפרדת במסד הנתונים, המכילה את כל התאים שדורשים תרגום. החיסרון בשיטה זו הוא שבכל פעם שאנו מוסיפים שפה חדשה, עלינו להוסיף טבלה חדשה. כלומר, בואו נדמיין שהלקוח שלנו מצליח מאוד, והוא מרחיב את היישום שלו למדינות רבות (למעשה, שפות) בעולם. זה אומר שתצטרך להוסיף טבליה אחת לכל לשון. כתוצאה מכך, יהיה לנו מסד נתונים המורכב חצי או כמעט כולו מטבלאות תרגום עזר: יישום יישום רב לשוני - 4 סכימה של הסרטים עצמם: יישום יישום רב לשוני - 5טבלאות תרגום:
  • רוּסִי יישום יישום רב לשוני - 6
  • ספרדית יישום יישום רב לשוני - 7
  • אנגלית יישום יישום רב לשוני - 8

2. אחד לכולם

בכל טבלה ששייכת לדגם ספציפי מתווסף שדה עם מזהה ללוחית השפה. בהתאם לכך, המאגר מכיל גם טבלה זו עם תרגומים. הבעיה היא שאובייקט אחד יכול להתאים למספר תרגומים (שפות). כתוצאה מכך תהיה כפילות של ישויות, וזה מאוד מבלבל ומסבך את ההיגיון, וזה לא טוב. אנו מסתכלים על UML: יישום יישום רב לשוני - 9 סרטי שולחן: יישום יישום רב לשוני - 10 שפות טבלה: יישום יישום רב לשוני - 11

3. טור לכל לשון

עמודת תרגום נפרדת נוצרת עבור כל עמודה עבור כל שפה בטבלה. החיסרון של גישה זו הוא ששוב, אם יתווספו מספר רב של שפות, יהיה צורך לשנות את מבנה מסד הנתונים בכל פעם, וזו נחשבת לגישה גרועה. תארו לעצמכם גם כמה מנופחים יהיו השלטים הדורשים בינאום. אולי כדאי לשקול מודל שבו מספר השפות הנתמכות ידוע מראש, אין יותר מדי מהן, וכל דגם צריך להתקיים בכל וריאציות השפה. UML: יישום יישום רב לשוני - 12טבלה הכל כלול: יישום יישום רב לשוני - 13

4. תרגום חיצוני

אפשרות זו מיושמת על ידי חיבור כלים חיצוניים (Google translate, Bing translate וכו'). הוא משמש אם אתה צריך לספק מידע לכמה שיותר מבקרים, ויש הרבה מהמידע הזה. כל כך הרבה. במקרה זה, אתה יכול להחליט לא לאחסן מידע ישירות במסד הנתונים בכל השפות, אלא לתרגם אותו באופן דינמי. אבל כדאי לזכור שאיכות התרגום המכונה לעתים קרובות משאירה הרבה מה לרצוי. האפשרות יכולה להיחשב כחסכונית מאוד (כאשר אין משאבים לתרגום כל פרסום). בעיה נפוצה מבחינת תרגום נכון היא שמתרגמים שאינם יודעים היטב את השפה בוחרים במשמעות השגויה של מילה ומבלבלים את המשתמש, ומאלצים אותו להבין באופן עצמאי את המשמעות של מה שכתוב על הכפתור. חשוב גם לא רק לתרגם נכון את המשפט, אלא גם להביא את המשמעות שלו לשפה ולאום ספציפיים. למפתחים יש הרבה בעיות עם מגדרים בשפות מסוימות. הם צריכים לשכפל את הביטוי בקוד בהתאם למין המשתמש, וגם לקחת בחשבון שלא רק לשמות עצם יש מגדר, אלא גם שמות תואר ופעלים מוטים אחרת. ישנם מקרים שבהם, לאחר בחירת שפה שאינה אנגלית באפליקציה, יחד עם המילים של השפה הנבחרת, עדיין ישנם אלמנטים לא מתורגמים. זה אפילו יותר גרוע אם מוצגות מספר שפות ומתברר שזה סוג של בבילון, שבה הכל מתערבב והמשתמש לא יכול להבין את האפליקציה. לדוגמה: https://cloud.google.com/translate/

5. קבצי תמיכה ברמת האפליקציה

נוצרים קבצים נפרדים לאחסון תרגומים. זה יכול להיות קובץ אחד לכל לשון או קובץ אחד לכל לשון לטאבלט (ריסוק עדין). אפשרות זו משמשת לעתים קרובות בשל העובדה שניתן לאחסן טקסטים רבים בקבצים אלו, מה שאומר שהטבלאות ומסד הנתונים עצמו לא יהפכו למנופחים. נוחות נוספת היא שאינך צריך לדפוק במסד הנתונים עבור שדות אלו, וניתן להחליף את הקבצים בקוד באופן דינמי בהתאם לשפה המבוקשת. כתוצאה מכך, הקובץ משמש עבורנו מילון, שבו המפתח הוא השפה, הערך הוא הטקסט. אבל אנחנו לא מוגבלים לפורמט ".properties" להלן, ופורמטים של קבצים אלה יכולים להשתנות מאוד - JSON, XML וכו'. החסרונות הם שבמקרה זה הנורמליזציה של בסיס הנתונים מצטמצמת מאוד. כמו כן, שלמות הנתונים כבר אינה תלויה רק ​​במסד הנתונים, אלא גם במנגנון ההסדרה. מאמר מצוין בנושא זה דוגמה לקבצי מילון עם תרגומים: יישום יישום רב לשוני - 14
  • אנגלית יישום יישום רב לשוני - 15
  • רוּסִי יישום יישום רב לשוני - 16
  • ספרדית יישום יישום רב לשוני - 17

6. טבלת תרגום עזר לכל טבלה

לדעתי הפתרון הכי גמיש. המהות של גישה זו היא ליצור טבלה נפרדת לשפות. כאשר יש צורך ביישום אפשרות של תרגומים לטבלה המדוברת נוצר קישור עם טבלת השפה, וטבלת הקישורים מכילה את מזהה השפה, מזהה האלמנט ועמודות עם תרגומים. זה לא מפחיד כמו שזה נשמע. גישה זו מאפשרת הרחבה גמישה למדי של שפות נתמכות. בואו נסתכל מקרוב. UML: יישום יישום רב לשוני - 18טבלה עם סרטים: יישום יישום רב לשוני - 19טבלת שפות: טבלת יישום יישום רב לשוני - 20תרגומים: יישום יישום רב לשוני - 21 וכמו שאמרתי למעלה, בואו נסתכל על היישום של אחת האפשרויות בקוד Java (כפי שהבנתם, זו תהיה האפשרות האחרונה). אין דבר כזה באפליקציה עצמה: נעבור מבקרים לשכבות דאו. נסתכל על שיטת היצירה - לדוגמא זה יספיק. אז בואו נלך)) המהות שלנו היא סרט:
@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 עצמה, כפי שנכתב לעיל, מפה לתרגומים, השדות הנותרים הם תצוגה של מודל הסרט. בואו נעבור לשירות הסרטים:
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