我认为gettext 更适合用于消息、按钮、标题等的翻译。而不是动态内容。为此,您可以根据项目要求采用几种不同的方式。首先,你应该决定:
- 翻译机制应该有多灵活。您是否需要经常添加新的翻译表或更新现有表结构?您是否需要经常添加新语言?
- 您是否需要跟踪原始内容的更改并在更改原始内容时停用所有翻译。
- 您是否需要后端来对翻译进行预审(如果有多个人参与翻译)
对于具有最大灵活性和可扩展性的解决方案,您可以按照以下方式进行。原始表保持原样,没有变化。对于翻译,您可以添加一个带有列的表 translations:
-
id主键
-
object_table翻译后的表名
-
object_id 对翻译对象的引用
-
language 或 language_id 如果您需要动态管理语言
-
field翻译字段名称
-
original_md5原始字段值的哈希(如果您需要跟踪更改)
translation
-
author_id、published、date 以及审核所需的其他字段(如果需要)。
然后,在另一个表或配置文件中描述要翻译的表和字段。您还可以描述字段的类型,例如text、textarea、html、file等等。
例如:
$translatedFields = array(
// here key stands for translated table name
'posts' => array(
// here key stands for translated field
// and value for field's type
'title' => 'text',
'body' => 'html',
),
);
然后,在您的数据访问层中,您确定当前语言并将所有 SELECT 查询替换为要翻译的表。一点正则表达式的魔力和查询的严格语法可以在这里为您提供帮助。查询SELECT title, body FROM posts WHERE posts.id='1'变成了
SELECT
IF(posts_title_translation.translation IS NULL,
posts.title,
posts_title_translation.translation) AS title,
IF(posts_body_translation.translation IS NULL,
posts.body,
posts_body_translation.translation) AS body
FROM posts
LEFT JOIN translations AS posts_title_translation
ON posts_title_translation.object_id = posts.id
AND posts_title_translation.object_table = 'posts'
AND posts_title_translation.language = '$language'
AND posts_title_translation.field = 'title'
---- And if you need premoderation, then filter off unpublished translations
--AND posts_title_translation.published
LEFT JOIN translations AS posts_body_translation
ON posts_body_translation.object_id = posts.id
AND posts_body_translation.object_table = 'posts'
AND posts_body_translation.language = '$language'
AND posts_body_translation.field = 'body'
--AND posts_body_translation.published
WHERE posts.id = '1'
(SELECT 部分中的 IF 表达式允许您在没有翻译完成或发布时选择原始字段。
这就是您可以拥有灵活的 i18n 系统的方式。为每个单独的字段进行翻译,并在选择时自动在数据访问层中替换。
这有点棘手,而且必须说,部分受到 Joomla! 的 Joom!Fish 扩展的影响,但我就是这样做的。
我将为更简单的解决方案添加另一个答案,因为这已经太大了。