JavaRush /Java 博客 /Random-ZH /多语言应用的实施

多语言应用的实施

已在 Random-ZH 群组中发布
多语言应用程序的实现 - 1

今天我们来谈谈多语言。那么它是什么?

多语言,换句话说,国际化,是开发可以在不改变程序逻辑的情况下适应多种语言的应用程序的一部分。考虑一下这种情况:您正在为一家大型贸易公司创建一个 Web 应用程序,该公司的用户来自许多国家,例如使用俄语、英语和西班牙语等语言的国家。您需要为所有用户提供方便。这个想法是这样的:讲俄语的读者应该能够看到俄语的数据,美国人会更舒服地阅读英语的材料,而西班牙人则应该能够看到西班牙语的数据(出乎意料,对吧?)今天让我们考虑几种国际 多语言应用程序的实现 - 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.各表的辅助翻译表

我认为这是最灵活的解决方案。这种方法的本质是为语言创建一个单独的表。当需要对相关表实现翻译的可能性时,会创建与语言表的链接,并且链接表包含语言 id、元素 id 和带有翻译的列。它并不像听起来那么可怕。这种方法允许支持的语言相当灵活的可扩展性。让我们仔细看看。 UML: 多语言应用程序的实施 - 18电影表: 多语言应用程序的实施 - 19语言表: 实施多语言应用程序 - 20翻译表: 多语言应用程序的实施 - 21而且,正如我上面所说,让我们看看 Java 代码中的一个选项的实现(如您所知,这将是最后一个选项)。应用程序本身没有类似的东西:我们将从控制器转到 dao 层。我们将看看 create 方法 - 作为一个例子,这就足够了。所以我们走吧))我们的本质是一部电影:
@Builder
@Getter
public class Movie {

   private Long id;

   private String producer;
}
没什么有趣的,只是实现第一个表的模型。 带有 dto(数据传输对象)转换器的控制器:
@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 服务通过缩写来检索语言 id。通过这个标识符,我们将翻译(也以映射的形式)保存到连接表中。 让我们看看 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