JavaRush /จาวาบล็อก /Random-TH /การดำเนินการแอปพลิเคชันหลายภาษา
Константин
ระดับ

การดำเนินการแอปพลิเคชันหลายภาษา

เผยแพร่ในกลุ่ม
การใช้งานแอปพลิเคชันหลายภาษา - 1

วันนี้เราจะพูดถึงพหุภาษา แล้วมันคืออะไร?

พูดได้หลายภาษาหรืออีกนัยหนึ่งความเป็นสากลเป็นส่วนหนึ่งของการพัฒนาแอปพลิเคชันที่สามารถปรับใช้ได้กับหลายภาษาโดยไม่ต้องเปลี่ยนลอจิกของโปรแกรม พิจารณาสถานการณ์: คุณกำลังสร้างเว็บแอปพลิเคชันสำหรับบริษัทการค้าขนาดใหญ่สำหรับผู้อยู่อาศัยในหลายประเทศซึ่งมีการพูดภาษาต่างๆ เช่น รัสเซีย อังกฤษ และสเปน คุณต้องทำให้สะดวกสำหรับผู้ใช้ทุกคน แนวคิดก็คือ: ผู้อ่านที่พูดภาษารัสเซียควรมีโอกาสดูข้อมูลของคุณเป็นภาษารัสเซียจะสะดวกกว่าสำหรับชาวอเมริกันที่จะอ่านเนื้อหาเป็นภาษาอังกฤษและสำหรับชาวสเปน - เป็นภาษาสเปน (โดยไม่คาดคิดใช่ไหม?) ให้ การใช้งานแอปพลิเคชันหลายภาษา - 2วันนี้ เราจะพิจารณา โมเดลการทำให้เป็นสากลหลายแบบและสำหรับหนึ่งในนั้น (ซึ่งฉันชอบมากที่สุด :) มาดูการใช้งานใน Java กันดีกว่า สำหรับหนูตะเภาวันนี้เราจะมีบอร์ดข้อมูลหนัง อย่าไปวิปริตเกินไป เราจะไม่มีวิทยากรมากนัก ตัวอย่างเช่น ไม่เป็นไร และเราจะแปลชื่อภาพยนตร์ (ผู้กำกับ - เพื่อความพิเศษ): การใช้งานแอปพลิเคชันหลายภาษา - 3

1. ตารางพร้อมคำแปลของแต่ละภาษา

สาระสำคัญของแบบจำลองนี้: แต่ละภาษามีตารางแยกกันในฐานข้อมูลซึ่งมีเซลล์ทั้งหมดที่ต้องแปล ข้อเสียของวิธีนี้คือทุกครั้งที่เราเพิ่มภาษาใหม่ เราจะต้องเพิ่มตารางใหม่ นั่นคือ ลองจินตนาการว่าลูกค้าของเรากำลังทำได้ดีมากและเขากำลังขยายการใช้งานไปยังหลายประเทศ (อันที่จริงคือภาษา) ของโลก ซึ่งหมายความว่าคุณจะต้องเพิ่มหนึ่งเม็ดต่อลิ้น เป็นผลให้เราจะมีฐานข้อมูลครึ่งหนึ่งหรือเกือบทั้งหมดประกอบด้วยตารางการแปลเสริม: การใช้งานแอปพลิเคชันหลายภาษา - 4 แผนผังของภาพยนตร์: การใช้งานแอปพลิเคชันหลายภาษา - 5ตารางการแปล:
  • ภาษารัสเซีย การใช้งานแอปพลิเคชันหลายภาษา - 6
  • สเปน การใช้งานแอปพลิเคชันหลายภาษา - 7
  • ภาษาอังกฤษ การใช้งานแอปพลิเคชันหลายภาษา - 8

2. หนึ่งเดียวสำหรับทุกคน

ในแต่ละตารางที่เป็นของโมเดลเฉพาะ จะมีการเพิ่มฟิลด์ที่มีตัวระบุสำหรับแผ่นภาษา ดังนั้นฐานข้อมูลจึงมีตารางนี้พร้อมคำแปลด้วย ปัญหาคือวัตถุหนึ่งสามารถสอดคล้องกับการแปลได้หลายภาษา (ภาษา) เป็นผลให้เกิดความซ้ำซ้อนของเอนทิตี และทำให้ตรรกะสับสนและซับซ้อนอย่างมาก และสิ่งนี้ไม่ดี เราดูที่ UML: การใช้งานแอปพลิเคชันหลายภาษา - 9 ภาพยนตร์ตาราง: การใช้งานแอปพลิเคชันหลายภาษา - 10 ภาษาตาราง: การใช้งานแอปพลิเคชันหลายภาษา - 11

3. คอลัมน์ต่อลิ้น

มีการสร้างคอลัมน์การแปลแยกกันสำหรับแต่ละคอลัมน์สำหรับแต่ละภาษาในตาราง ข้อเสียของแนวทางนี้คือ ขอย้ำอีกครั้งว่าหากมีการเพิ่มภาษาจำนวนมาก โครงสร้างฐานข้อมูลจะต้องมีการเปลี่ยนแปลงในแต่ละครั้ง ซึ่งถือเป็นแนวทางที่ไม่ดี ลองจินตนาการดูว่าสัญญาณที่เรียกร้องความเป็นสากลจะสูงเกินจริงเพียงใด การพิจารณาแบบจำลองที่ทราบจำนวนภาษาที่รองรับล่วงหน้าอาจคุ้มค่า มีไม่มากเกินไป และแต่ละรุ่นควรมีอยู่ในรูปแบบภาษาทั้งหมด UML: การใช้งานแอปพลิเคชันหลายภาษา - 12ตารางรวมทุกอย่าง: การใช้งานแอปพลิเคชันหลายภาษา - 13

4. การแปลภายนอก

ตัวเลือกนี้ใช้งานได้โดยการเชื่อมต่อเครื่องมือภายนอก (Google แปล, Bing แปล ฯลฯ ) มันถูกใช้หากคุณต้องการให้ข้อมูลแก่ผู้เยี่ยมชมให้ได้มากที่สุดและมีข้อมูลนี้จำนวนมาก มากมาย. ในกรณีนี้ คุณสามารถตัดสินใจว่าจะไม่จัดเก็บข้อมูลโดยตรงในฐานข้อมูลในทุกภาษา แต่เลือกที่จะแปลข้อมูลแบบไดนามิก แต่ควรจำไว้ว่าคุณภาพของการแปลด้วยเครื่องมักจะไม่เป็นที่ต้องการมากนัก ตัวเลือกนี้ถือว่าประหยัดมากเท่านั้น (เมื่อไม่มีทรัพยากรในการแปลสิ่งพิมพ์แต่ละฉบับ) ปัญหาที่พบบ่อยจากมุมมองของการแปลที่ถูกต้องคือนักแปลที่ไม่รู้ภาษาดีเลือกความหมายที่ผิดของคำและทำให้ผู้ใช้สับสนทำให้เขาต้องเข้าใจความหมายของสิ่งที่เขียนบนปุ่มอย่างอิสระ สิ่งสำคัญไม่เพียงแต่จะต้องแปลประโยคให้ถูกต้องเท่านั้น แต่ยังต้องนำความหมายของประโยคมาเป็นภาษาและสัญชาติที่เฉพาะเจาะจงด้วย นักพัฒนาซอฟต์แวร์มีปัญหามากมายเกี่ยวกับเพศในบางภาษา พวกเขาต้องทำซ้ำวลีในโค้ดโดยขึ้นอยู่กับเพศของผู้ใช้ และยังคำนึงด้วยว่าไม่เพียงแต่คำนามที่มีเพศเท่านั้น แต่ยังมีคำคุณศัพท์และคำกริยาที่ผันต่างกันออกไปด้วย มีหลายกรณีที่เมื่อเลือกภาษาอื่นที่ไม่ใช่ภาษาอังกฤษในแอปพลิเคชันพร้อมกับคำของภาษาที่เลือกแล้ว ยังมีองค์ประกอบที่ยังไม่ได้แปล จะแย่ไปกว่านั้นหากมีการแสดงหลายภาษาและกลายเป็นบาบิโลนที่ทุกอย่างปะปนกันและผู้ใช้ไม่เข้าใจแอปพลิเคชัน ตัวอย่างเช่น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 เราส่งการแปลเป็นแผนที่ คีย์คือตัวย่อภาษา ค่าคือค่าการแปล (ชื่อภาพยนตร์) ดีทีโอ:
@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);
   }
}
ไม่มีอะไรพิเศษ ค้นหาด้วยชื่อย่อ ดาว:
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