如何国际化目录?

时间:2015-07-13 15:32:42

标签: java sql spring primefaces internationalization

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

国家:

  • ES:México,Alemania,Inglaterra等。
  • EN:墨西哥,德国,英国等

我不想创建像下一个模型:

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。

我希望你能帮助我。

由于

5 个答案:

答案 0 :(得分:2)

老实说,我发现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 数据库可以是摘录,甚至是生成的java ListResourceBundle:字符串数组。

答案 1 :(得分:1)

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

但是,如果排序,分组......数据库查询的功能很重要,那么除了使用字典表之外别无选择,如其他答案中所述。这种方法的缺点是查询性能较低,因为与字典表的连接很多,当然缺少密钥的风险,会使你使用外连接的性能更差!

字典表结构如下:

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

和例如国家/地区表将是这样的:

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是必须根据用户/浏览器请求的语言环境发送给查询的参数。

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

答案 2 :(得分:0)

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

对于不太可能改变的静态文本 - 例如国家/地区名称,最佳做法是使用客户端(而不是DB端)本地化。在这种情况下,您将DB条目视为键并从资源文件(或消息源,根据您希望如何实现它)读取翻译。 JSF在这里不会帮助你,你必须创建自己的bean来阅读翻译的名称。

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

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

再一次,您可以将原始条目视为密钥,但不建议这样做。实际上,即使是静态场景也不建议使用它 - 它会强制您重复使用相同文本的翻译。问题是,翻译可能因上下文而有所不同......所以最好使用独特的翻译键,即使这意味着没有语言中立的翻译。

答案 3 :(得分:0)

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

在我的职业生涯中,我曾两次面对你的问题。

  • 第一次,我记得我们做过你不想要的模特。我们在每个数据表上都有文本来为每种语言翻译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 Translationsid_translation)和SELECT所选语言列。 如果您使用实体(JPA),您将实体Translation包含在实体Country中。使用此对象图,您可以创建一个辅助JSF组件,以根据所选语言显示正确的文本。

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

答案 4 :(得分:0)

正如之前提到的那样(如果我正确地看到其他两个答案),最好的是翻译部分不在数据库中,但由于你想要一切都在数据库中,这里是我的5美分。 我仍然没有想出如何在这里发布时正确格式化代码,所以很抱歉。另外我会写一些伪SQL,但我希望它会很清楚。

共有3个表格:

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`));

表countryInLanguage称为关联表,表示N对N的关系。当然,您的查询必须访问两个表而不是一个但仅才能获得给定语言的国家/地区名称。我会说这并不复杂得多。至少它很容易扩展 - 如果你要添加新的国家或新语言。对于其他一切你将使用id_country。

这里有一些冗余存储空间被占用,例如,有许多语言n元组,其中一些国家名称以相同的方式编写,但不会过多地写入...

此外,您可以在国家/地区表中使用国家/地区名称列,该国家/地区名称列将使用默认语言保留国家/地区名称(默认最常用于特定应用,用户,公司等)。地狱,您甚至可以根据用户选择的默认语言更新这些默认值。

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