如何国际化目录?

How do I internationalize catalogs?

我要国际化一个项目,不仅是应用程序的标签,我也必须国际化目录,例如

国家:

我不想创建下一个模型:

CREATE TABLE country (
  id_country INT NOT NULL AUTO_INCREMENT,
  name_es VARCHAR(100) NOT NULL,
  name_en VARCHAR(100) NOT NULL,
  ....................,
  PRIMARY KEY (`id_country`));

是否有任何最佳实践、模式设计或框架来解决这个问题?因为我认为这是一个常见问题。我正在考虑下一个模型 :

CREATE TABLE country (
  id_country INT NOT NULL AUTO_INCREMENT,
  name VARCHAR(100) NOT NULL,
  languaje VARCHAR(100) NOT NULL,
  PRIMARY KEY (`id_country`));

问题是我将只有一个国家/地区的许多外键,因此查询会变得更加复杂。

我正在使用 Java、Spring 启动、Spring 数据、JavaServer Faces、Primefaces。

希望你能帮助我。

谢谢

是的,这是一个常见问题,并且有最佳做法。

对于不太可能更改的静态文本(如国家名称),最佳做法是使用客户端(而非数据库端)本地化。在这种情况下,您将数据库条目视为键并从资源文件(或消息源,取决于您希望如何实现)读取翻译。 JSF 在这里帮不了您太多,您必须创建自己的 bean 才能读取翻译后的名称。

对于动态文本(即经常更改或可以由用户输入的内容),最佳做法是使用具有复合键的查找表:

CREATE TABLE translation (
  key VARCHAR(100) NOT NULL,
  languageid VARCHAR(20) NOT NULL,
  translation VARCHAR(100) NOT NULL,
  PRIMARY KEY (`key`, `languageid`));

再说一次,你可以把原始条目当作key,但是不推荐。实际上,即使对于静态场景也不推荐这样做——它会迫使您重复使用相同文本的翻译。问题是,根据上下文翻译可能会有所不同...所以最好使用唯一的翻译键,即使这意味着没有语言中立的翻译。

首先,对不起我的英语水平。

在我的职业生涯中,我遇到过两次你的问题。

  • 第一次,我记得我们做了你不想要的模型。我们在每个数据表上都有文本来为每种语言翻译 N 个额外的列。
  • 第二次,我们开发了其他型号。我们有一个所有翻译的数据表 + 缓存系统(我们必须显示大量动态文本,我们需要提高性能)。

在这两种情况下,在开发之前我们就知道我们将使用哪些语言。第二个模型是这样的:

CREATE TABLE Translations (
    id_translation INT NOT NULL AUTO_INCREMENT,
    es_ES VARCHAR(200),
    en_UK VARCHAR(200),
    ...(more languages)
    PRIMARY KEY ('id_translation')
);

CREATE TABLE Countries (
    id_country INT NOT NULL AUTO_INCREMENT,
    id_translation INT NOT NULL,
    ...
    PRIMARY KEY ('id_country'),
    FOREIGN KEY ('id_translation')
);

使用此模型,您只有一个键 (id_country) 和此键的 N 翻译,其中 N 是 Translations 数据表中语言列的数量。将来,如果您需要添加一种新语言,则必须在 Translations 数据表中添加一个新列。在您的查询 中,您必须join Countries with Translations (id_translation) 和SELECT 选择语言列。 如果您使用 Entities (JPA),您将有一个实体 Translation 包含在一个实体 Country 中。使用此对象图,您可以创建辅助 JSF 组件以根据所选语言显示正确的文本。

P.S。如果您的应用程序将多次访问您的数据库以显示翻译,我建议您使用像 Ehcache、Memcached 或类似的缓存系统 来提高性能.

老实说,我发现在 XML 中进行翻译最灵活,也更适合纳入版本控制。人类实践也更容易。

然而,数据库允许灵活使用、过滤、排序等。

可以用于评估的东西:报告、完整性检查、统计数据。

table Texts
    id       int auto_incr -- internally
    key      varchar 30 -- public key in software
    comment  varchar 80 -- translator info, like noun, in menu
    categ    varchar 20 -- glossar entry / menu / help / tooltip
    sortkey  varchar 20 -- to order the translation
    ...

table Locales
    locale   varchar 10

table Translations
    textid   int
    locale   varchar 160

想法是准备协调翻译工作。 还可以为翻译服务导出/导入翻译记忆库格式。 词汇表对于拥有一致的术语非常重要。 开发人员在翻译方面付出的努力提高了质量,并节省了所有工作。

production 数据库可以是摘录,甚至是生成的 javaListResourceBundle: 字符串数组。

如果按目录标题排序对您来说不是问题,最好的方法是将翻译保留在您的属性文件中,而不是 table 中的标题列,在您的 table 并使用该键根据语言环境引用标题。这种方法的缺点是您无法根据标题对数据进行排序。好处是您不受想要支持的语言数量的限制。

但是,如果排序、分组...数据库查询的功能很重要,那么除了使用字典 table,您别无选择,如其他答案中所述。这种方法的缺点是查询性能较低,因为与字典的连接太多 table,当然还有丢失键的风险,这将使您使用外部连接时性能更差!

字典table结构将是这样的:

CREATE TABLE dictionary(
  id INT NOT NULL,
  locale VARCHAR(2) NOT NULL,
  value VARCHAR(100) NOT NULL,
  PRIMARY KEY (id, locale);

例如国家 table 将是这样的:

CREATE TABLE country (
  id_country INT NOT NULL AUTO_INCREMENT,
  name_dictionary_id INT NOT NULL,
  ....................,
  PRIMARY KEY (`id_country`));

按本地检索国家/地区列表的查询将如下所示:

select 
   c.id_country, d.value
from 
   country c
left outer join dictionary d
   on (c.name_dictionary_id = d.id and d.locale = :locale)
order by d.value asc

:locale 是必须根据 user/browser 请求的语言环境发送到查询的参数。

当您创建新的国家/地区时,您需要获取支持的语言环境的所有名称,并为每个名称插入一本字典,所有名称都具有相同的 ID,但语言环境不同。

正如之前提到的(如果我没看错的话,在其他两个答案中),最好是翻译部分不在数据库中,但是由于您希望所有内容都在数据库中,所以这是我的5 美分。 我仍然没有想出如何在此处发布时正确格式化代码,对此深表歉意。另外我会写一些伪SQL,但我希望它会清楚。

有3个table:

CREATE TABLE country (
  id_country INT NOT NULL AUTO_INCREMENT,
  //--optionally you could have name VARCHAR in default language
  PRIMARY KEY (`id_country`));

CREATE TABLE language(
  id_lang INT NOT NULL AUTO_INCREMENT,
  name VARCHAR(50),
  PRIMARY KEY (`id_lang`));

CREATE TABLE countryInLanguage(
  id_country REFERENCES country.id_country, //-- FK to country table
  id_lang REFERENCES language.id_lang, //-- FK to language table
  nameInLang VARCHAR(100),
  PRIMARY KEY (`id_country, id_lang`));

Table countryInLanguage 称为关联 table 并表示 N 对 N 关系。当然,您的查询必须访问两个 table 而不是一个 ,但只需 即可获取给定语言的国家/地区名称。我会说这并不复杂。至少它很容易扩展——以防你添加新的国家或新的语言。对于其他所有内容,您将使用 id_country.

这里有一些多余的存储被占用了,比如有很多语言的n元组,​​其中一些国家的名字是用同样的方式写的,但不去太多...

您还可以在国家 table 中拥有国家名称列,该列将以默认语言保存国家名称(默认最常用于特定应用程序、用户、公司等)。该死,您甚至可以根据用户选择的默认语言更新这些默认值。

但是,我必须(我自己和其他人)重申,翻译最好保存在人类可读的文件中。为什么?翻译您的应用程序的人通常不知道如何处理数据库和编写 SQL 语句和查询,但如果他们有文本文件(可以是 XML、键值文件...),那么这对他们来说很容易。