如何国际化目录?
How do I internationalize catalogs?
我要国际化一个项目,不仅是应用程序的标签,我也必须国际化目录,例如
国家:
- 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。
希望你能帮助我。
谢谢
是的,这是一个常见问题,并且有最佳做法。
对于不太可能更改的静态文本(如国家名称),最佳做法是使用客户端(而非数据库端)本地化。在这种情况下,您将数据库条目视为键并从资源文件(或消息源,取决于您希望如何实现)读取翻译。 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、键值文件...),那么这对他们来说很容易。
我要国际化一个项目,不仅是应用程序的标签,我也必须国际化目录,例如
国家:
- 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。
希望你能帮助我。
谢谢
是的,这是一个常见问题,并且有最佳做法。
对于不太可能更改的静态文本(如国家名称),最佳做法是使用客户端(而非数据库端)本地化。在这种情况下,您将数据库条目视为键并从资源文件(或消息源,取决于您希望如何实现)读取翻译。 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、键值文件...),那么这对他们来说很容易。