第13章- I18n和L10n
如果您曾经开发过国际应用程序,就会知道处理文本翻译、本地标准和本地化内容的各个方面可能是一场噩梦。幸运的是,symfony本ob娱乐下载机自动化了国际化的所有方面。
由于国际化是一个很长的单词,开发人员通常将其称为i18n(数一数单词中的字母就知道为什么了)。本地化被称为l10n。它们涵盖了多语言web应用程序的两个不同方面。
国际化的应用程序包含相同内容的不同语言或格式的多个版本。例如,web邮件界面可以用几种语言提供相同的服务;只是界面发生了变化。
本地化应用程序根据所浏览的国家包含不同的信息。考虑一下新闻门户的内容:从美国浏览时,它显示关于美国的最新标欧宝平台是合法的吗题,但从法国浏览时,标题涉及法国新闻。因此l10n应用程序不仅提供内容翻译,而且内容可以在不同的本地化版本之间有所不同。
总而言之,处理i18n和l10n意味着应用程序可以处理以下问题:
- 文本翻译(界面、资产和内容)
- 标准和格式(日期、金额、数字等)
- 本地化内容(根据国家的不同,给定对象的许多版本)
本章介绍symfony处理这些元素的方式,以及如何使用它ob娱乐下载来开发国际化和本地化的应用程序。
用户的文化
symfony中所有内置的i18n特性都基于用户会话的一个称为区域性ob娱乐下载的参数。文化是国家和用户语言的组合,它决定了如何显示文本和依赖于文化的信息。因为它是在用户会话中序列化的,所以区域性在页面之间是持久的。
设置默认区域性
默认情况下,新用户的区域性为default_culture
.方法中更改此设置i18n.yml
配置文件,如清单13-1所示。
清单13-1 -设置默认区域性,在myapp / config / i18n.yml
all: default_culture: fr_FR
请注意
在开发过程中,您可能会惊讶于企业文化的变化i18n.yml
文件不会改变浏览器中的当前区域性。这是因为会话已经具有来自前一页的区域性。如果希望看到具有新的默认区域性的应用程序,则需要清除域cookie或重新启动浏览器。
在文化中同时保留语言和国家是必要的,因为对于来自法国、比利时或加拿大的用户可能有不同的法语翻译,而对于来自西班牙或墨西哥的用户可能有不同的西班牙语内容。根据ISO 639-1标准,该语言以两个小写字符编码(例如,在
英语)。根据ISO 3166-1标准,国家由两个大写字符编码(例如,GB
英国)。
改变用户的文化
用户文化可以在浏览会话期间更改——例如,当用户决定从应用程序的英语版本切换到法语版本时,或者当用户登录到应用程序并使用存储在首选项中的语言时。这就是为什么sfUser
类为用户区域性提供getter和setter方法。清单13-2展示了如何在操作中使用这些方法。
清单13-2 -在动作中设置和检索区域性
//文化设置这个美元->getUser()->setCulture(“en_US”);//文化getter美元的文化=这个美元->getUser()->getCulture();= > en_US
侧边栏
URL中的文化
在使用symfony的ob娱乐下载本地化和国际化特性时,单个URL的页面往往有不同的版本——这完全取决于用户会话。这可以防止您在搜索引擎中缓存或索引您的页面。
一种解决方案是让文化出现在每个URL中,这样被翻译的页面就可以被外界视为不同的URL。要做到这一点,请添加: sf_culture
标记应用程序的每个规则routing.yml
:
Page: url: /:sf_culture/: Page requirements: {sf_culture:(?:fr| z| de)} param:…文章:url: /:sf_culture/:年/:月/:日/:段码要求:{sf_culture:(?:fr| z| de)}参数:…
避免手动设置sf_culture请求参数link_to ()
, ob娱乐下载symfony会自动将用户区域性添加到默认路由参数中。它也可以在入站工作,因为symfony将自动更改用户区域性ob娱乐下载sf_culture
参数在URL中找到。
自动确定文化
在许多应用程序中,用户区域性是在第一次请求期间根据浏览器首选项定义的。用户可以在浏览器中定义可接受的语言列表,并且该数据随每个请求一起发送到服务器接收语言
HTTP报头。可以在symfony中通过ob娱乐下载sfRequest
对象。例如,要在操作中获得用户的首选语言列表,键入以下内容:
美元的语言=这个美元->getRequest()->getLanguages();
HTTP报头是一个字符串,但symfony会自动解析它并将其转换为ob娱乐下载一个数组。因此,用户的首选语言是可访问的语言[0]美元
在前面的例子中。
在站点主页或所有页面的过滤器中自动将用户区域性设置为首选浏览器语言是很有用的。
谨慎
的接收语言
HTTP报头不是非常可靠的信息,因为用户很少知道如何在浏览器中修改它。大多数情况下,首选的浏览器语言是界面语言,而浏览器并非支持所有语言。如果您决定根据浏览器首选语言自动设置区域性,请确保为用户提供一种选择替代语言的方法。
标准及格式
web应用程序的内部并不关心文化的特殊性。例如,数据库使用国际标准来存储日期、数量等。但是当向用户发送数据或从用户检索数据时,需要进行转换。用户不理解时间戳,他们更愿意将自己的母语声明为Français而不是法语。因此,您将需要帮助来根据用户文化自动进行转换。
输出用户区域性中的数据
一旦定义了区域性,依赖于区域性的助手将自动获得正确的输出。例如,format_number ()
helper根据其区域性自动以用户熟悉的格式显示数字,如清单13-3所示。
清单13-3 -显示用户区域性的数字
<?phpuse_helper(“数量”)? ><?phpsf_user美元->setCulture(“en_US”)? ><?php回声format_number(12000.10)? >= >12000 .10<?phpsf_user美元->setCulture(“fr_FR”)? ><?php回声format_number(12000.10)? >= >的12 000年10
您不需要显式地将区域性传递给helper。它们将自己在当前会话对象中查找它。清单13-4列出了在输出时考虑用户文化的帮助器。
清单13-4 -依赖区域性的helper
<?phpuse_helper(“日期”)? ><?php回声format_date(时间())? >= >“9/14/06”<?php回声format_datetime(时间())? >= >“2006年9月14日美国东部时间晚上6:11:07”<?phpuse_helper(“数量”)? ><?php回声format_number(12000.10)? >= >12000 .10<?php回声format_currency(1350,“美元”)? >= >“1350美元”<?phpuse_helper(“国际化”)? ><?php回声format_country(“我们”)? >= >“美国”<?phpformat_language(“en”)? >= >“英语”<?phpuse_helper(“形式”)? ><?php回声input_date_tag(“birth_date”,mktime(0,0,0,9,14,2006))? >=>输入类型=“文本”name =“birth_date”id =“birth_date”值=“9/14/06”大小=“十一”/><?php回声select_country_tag(“国家”,“我们”)? >=>
日期帮助程序可以接受额外的格式参数,以强制使用与区域性无关的显示,但如果应用程序是国际化的,就不应该使用它。
从本地化的输入中获取数据
如果有必要在用户区域性中显示数据,至于检索数据,您应该尽可能地让应用程序的用户输入已经国际化的数据。这种方法将使您避免尝试如何转换具有不同格式和不确定位置的数据。例如,谁会在输入框中用逗号分隔符输入货币值?
您可以通过隐藏实际数据(如控件中所示)来构造用户输入格式select_country_tag ()
)或将复杂数据的不同组成部分分割成几个简单的输入。
然而,对于日期来说,这通常是不可能的。用户习惯于以其文化格式输入日期,而您需要能够将此类数据转换为内部(和国际)格式。这就是sfI18N
类应用。清单13-5演示了如何使用这个类。
清单13-5 -从动作的本地化格式中获取日期
美元的日期=这个美元->getRequestParameter(“birth_date”);user_culture美元=这个美元->getUser()->getCulture();//获取时间戳美元的时间戳= sfI18N::getTimestampForCulture(美元的日期,user_culture美元);//获取一个结构化的约会列表(美元d,m美元,$ y)= sfI18N::getDateForCulture(美元的日期,user_culture美元);
数据库中的文本信息
本地化的应用程序根据用户的文化提供不同的内容。例如,在线商店可以以相同的价格在全球范围内提供产品,但对每个国家都有自定义描述。这意味着数据库必须能够存储给定数据的不同版本,为此,您需要以特定的方式设计您的模式,并在每次操作本地化模型对象时使用区域性。
创建本地化模式
对于每个包含一些本地化数据的表,应该将表分成两部分:一个表没有任何i18n列,另一个表只有i18n列。这两个表将通过一对多关系连接起来。这种设置允许您在需要时添加更多语言,而无需更改模型。让我们考虑一个使用a的例子产品
表格
方法中创建表schema.yml
文件,如清单13-6所示。
清单13-6 - i18n Data的样例模式配置/ schema.yml
my_connection: my_product: _attributes: {phpName: Product, isI18N: true, i18nTable: my_product_i18n} id: {type: integer, required: true, primaryKey: true,自动增值:true} price: {type: float} my_product_i18n: _attributes: {phpName: ProductI18n} id: {type: integer, required: true, primaryKey: true, foreignTable: my_product, foreignReference: id} culture: {isCulture: true, type: varchar, size: 7, required: true, primaryKey: true} name: {type: varchar, size: 50}
注意到isI18N
而且i18nTable
属性在第一个表,和特殊文化
第二列。所有这些都是针对symfonob娱乐下载y的驱动增强。
symfob娱乐下载ony自动化可以使编写速度更快。如果包含国际化数据的表与的主表名称相同_i18n
作为后缀,并且它们与名为id
在这两个表中,都可以省略id
而且文化
中的列_i18n
表以及主表的特定i18n属性;ob娱乐下载Symfony会推断出它们。这意味着symfony将看到ob娱乐下载清单13-7中的模式与清单13-6中的模式相同。
清单13-7 - i18n数据(短版本)的样例模式配置/ schema.yml
my_connection: my_product: _attributes: {phpName: Product} id: price: float my_product_i18n: _attributes: {phpName: ProductI18n} name: varchar(50)
使用生成的I18n对象
一旦构建了相应的对象模型(不要忘记调用ob娱乐下载
propel-build-model
并清除缓存ob娱乐下载symfony cc
每次修改后schema.yml
),你可以使用你的产品
使用i18n支持的类,就好像只有一个表,如清单13-8所示。
清单13-8 -处理i18n对象
美元的产品= ProductPeer::retrieveByPk(1);美元的产品->setCulture(“fr”);美元的产品->setName(“Nom du product”);美元的产品->保存();美元的产品->setCulture(“en”);美元的产品->setName(“产品名称”);美元的产品->保存();回声美元的产品->getName();= >“产品名称”美元的产品->setCulture(“fr”);回声美元的产品->getName();= >“Nom du product”
如果不希望每次使用i18n对象时都记得更改区域性,也可以更改水合物()
方法。请参见清单13-9中的示例。
清单13-9 -重写水合物()
设置区域性的方法,在myproject / lib /模型/ Product.php
公共函数水合物(结果集rs美元,startcol美元=1){这个美元->setCulture(sfContext::getInstance()->getUser()->getCulture());返回父::水合物(rs美元,startcol美元);}
对于使用对等对象的查询,可以将结果限制为具有当前区域性翻译的对象doSelectWithI18n
方法,而不是通常的方法doSelect
,如清单13-10所示。此外,它将在创建常规对象的同时创建相关的i18n对象,从而减少获取完整内容的查询次数(有关此方法对性能的积极影响的更多信息,请参阅第18章)。
清单13-10 -检索带有i18n的对象标准
$ c=新标准();$ c->添加(ProductPeer::价格,One hundred.标准::LESS_THAN);美元的产品= ProductPeer::doSelectWithI18n($ c,美元的文化);// $culture参数是可选的//如果没有给定区域性,则使用当前用户区域性
因此,基本上,您永远不必直接处理i18n对象,而是在每次对常规对象进行查询时将区域性传递给模型(或让模型自己猜测)。
界面翻译
用户界面需要适应i18n应用程序。模板必须能够以多种语言显示标签、消息和导航,但具有相同的表示方式。ob娱乐下载Symfony建议使用默认语言构建模板,并在字典文件中为模板中使用的短语提供翻译。这样,您就不需要在每次修改、添加或删除翻译时都更改模板。
配置翻译
模板默认情况下不进行翻译,这意味着您需要激活settings.yml
文件优先于其他文件,如清单13-11所示。
清单13-11 -激活接口转换,在myapp / config / settings.yml
所有:.settings: i18n:开启
使用翻译助手
假设你想用英语和法语创建一个网站,英语是默认语言。在考虑翻译站点之前,您可能已经编写了类似清单13-12所示示例的模板。
清单13-12 -一个单一语言模板
欢迎访问我们的网站。今天的日期是
symfob娱乐下载ony要翻译模板中的短语,必须将它们标识为要翻译的文本。这就是我们的目的__ ()
helper(两个下划线),是I18N helper组的成员。因此,所有模板都需要在这样的函数调用中包含要翻译的短语。例如,清单13-12可以被修改为清单13-13所示(正如您将在本章后面的“处理复杂翻译需求”一节中看到的,在本例中有更好的方法调用翻译助手)。
清单13-13 -一个多语言模板
<?phpuse_helper(“国际化”)? ><?php回声__(“欢迎来到我们的网站。”)? ><?php回声__(“今天的日期是”)? ><?php回声format_date(日期())? >
提示
如果应用程序对每个页面都使用I18N帮助组,则将其包含在standard_helpers
在settings.yml
文件,以避免重复use_helper (I18N)
对于每个模板。
使用字典文件
每次__ ()
函数被调用时,symfony将在当前用户ob娱乐下载区域性的字典中查找其参数的翻译。如果它找到相应的短语,翻译将被发回并显示在响应中。所以用户界面的转换依赖于一个字典文件。
字典文件以XML本地化交换文件格式(XLIFF)编写,根据模式命名消息。(语言代码). xml
,并存储在应用程序中i18n /
目录中。
XLIFF是一种基于XML的标准格式。众所周知,您可以使用第三方翻译工具引用您网站中的所有文本并进行翻译。翻译公司知道如何处理这样的文件,以及如何通过添加一个新的XLIFF翻译来翻译整个网站。
提示
除了XLIFF标准外,symfony还支持字典的其他几个翻译后端:geob娱乐下载ttext、MySQL、SQLite和Creole。有关配置这些后端的更多信息,请参阅欧宝官网下载appAPI文档。
的XLIFF语法示例,如清单13-14所示messages.fr.xml
将清单13-13翻译成法语所必需的文件。
清单13-14 -一个XLIFF字典,在myapp / i18n / messages.fr.xml
<?xml版本=“1.0”? >< xliff版本=“1.0”><文件原始=“全球”通过读=“en_US”数据类型=“明文”><身体>< trans-unitid=“1”><源>欢迎访问我们的网站。< /来源><目标>Bienvenue sur notre site网站。< /目标>< / trans-unit>< trans-unitid=“2”><源>今天的日期是< /来源><目标>La date d'aujourd'hui est< /目标>< / trans-unit>< /身体>< /文件>< / xliff>
的通过读
属性必须始终包含默认区域性的完整ISO代码。每一个译文都是用一种trans-unit
带有唯一id
属性。
使用默认用户区域性(设置为en_US)时,短语不会被转换,而__ ()
显示通话记录。清单13-13的结果与清单13-12类似。但是,如果将文化更改为fr_FR
或fr_BE
的翻译messages.fr.xml
文件,结果如清单13-15所示。
清单13-15 -翻译模板
Bienvenue sur notre site网站。拉日期d“今天”回族是<?php回声format_date(日期())? >
如果需要进行额外的翻译,只需添加一个newmessages. ' XX ' ' . xml
同一目录下的翻译文件。
管理字典
如果你的messages.XX.xml
文件变得太长而无法阅读,您总是可以将翻译分成几个字典文件,按主题命名。例如,您可以分割messages.fr.xml
文件放入应用程序中的这三个文件中i18n /
目录:
navigation.fr.xml
terms_of_service.fr.xml
search.fr.xml
注意,as soon的翻译是不会在默认情况下找到的messages.XX.xml
文件时,必须声明每次调用时要使用哪个字典__ ()
Helper,使用其第三个参数。类中转换的字符串navigation.fr.xml
字典,这样写:
<?php回声__(“欢迎浏览我们的网站”,零,“导航”)? >
组织翻译词典的另一种方法是按模块拆分。而不是写一首单曲messages.XX.xml
对于整个应用程序,您可以在每个文件中编写一个模块/ [module_name] / i18n /
目录中。它使模块更加独立于应用程序,如果你想重用它们,比如在插件中(参见第17章),这是必要的。
处理其他需要翻译的元素
以下是可能需要翻译的其他元素:
图像、文本文档或任何其他类型的资产也可以根据用户区域性而有所不同。最好的例子是一段带有特殊排版的文本,实际上是一幅图像。对于这些目录,可以创建以用户命名的子目录
文化
:<?php回声image_tag(sf_user美元->getCulture().' / myText.gif ')? >
方法自动输出来自验证文件的错误消息
__ ()
,所以你只需要把它们的翻译添加到字典中就可以翻译了。- 默认的symfony页面ob娱乐下载(找不到页面、内部服务器错误、访问受限等等)是英文的,必须在i18n应用程序中重写。你应该自己创建一个
默认的
模块,并在应用程序中使用__ ()
在模板中。参考第19章了解如何定制这些页面。
处理复杂的翻译需求
翻译只有在__ ()
Argument是一个完整的句子。然而,由于有时格式或变量与单词混合在一起,您可能会被诱惑将句子切成几个块,从而在毫无意义的短语上调用helper。幸运的是,__ ()
Helper提供了一个基于标记的替代特性,这将帮助您拥有一个更容易由翻译人员处理的有意义的字典。与HTML格式一样,您也可以将其保留在helper调用中。清单13-16给出了一个示例。
清单13-16 -翻译包含代码的句子
//基本示例欢迎所有new用户。
有<?php回声count_logged()? >人记录。//启用文本翻译的错误方式<?php回声__(欢迎来到所有的)? >< b > < ?php回声__(“新”)? > < / b ><?php回声__(“用户”)? >。< br / ><?php回声__(“有”)? ><?php回声count_logged()? ><?php回声__(“个人登录”)? >//启用文本翻译的好方法<?php回声__(“欢迎来到所有new用户”)? >< br / ><?php回声__(“有%1%的人登录”,数组(“% 1%”= > count_logged()))? >
在本例中,令牌为% 1%
,但它可以是任何东西,因为翻译助手使用的替换函数是strtr ()
.
翻译中常见的一个问题是使用复数形式。根据结果的数量,文本会根据语言发生变化,但方式不同。例如,清单13-16中的最后一句是不正确的count_logged ()
返回0或1。您可以对该函数的返回值进行测试,并选择相应的语句,但这将代表大量代码。此外,不同的语言有不同的语法规则,复数的词形变化规则可能相当复杂。由于这个问题非常常见,symfony提供了一个帮助程序来处理它,ob娱乐下载称为format_number_choice ()
.清单13-17演示了如何使用这个helper。
清单13-17 -根据参数的值翻译句子
<?php回声format_number_choice('[0]没有人被记录|[1]有1人被记录|(1,+Inf]有%1%的人被记录',数组(“% 1%”= > count_logged()), count_logged())? >
第一个参数是文本的多种可能性。第二个参数是替换模式(与__ ()
Helper),是可选的。第三个参数是用于测试以确定所取文本的数字。
消息/字符串选择由管道(|
)字符后跟可接受值的数组,使用以下语法:
[1,2]
:接受1到2之间的值,包括1和2(1、2)
:取值为1 ~ 2,不包括1 ~ 2{1, 2, 3, 4}
:只接受集合中定义的值(负无穷,0)
:接受大于或等于负无穷且严格小于0的值
方括号和圆括号分隔符的任何非空组合都是可以接受的。
该消息需要显式地出现在XLIFF文件中,以便翻译能够正常工作。清单13-18给出了一个示例。
清单13-18 - XLIFF字典format_number_choice ()
论点
...… [0]Personne n'est connecté|[1]Une Personne est connectée|(1,+Inf) Il y %1% personnes en ligne
侧边栏
简单讲一下字符集
在模板中处理国际化内容通常会导致字符集问题。如果使用本地化字符集,则每次用户更改区域性时都需要更改它。此外,用给定字符集编写的模板将不能正确地显示另一个字符集的字符。
这就是为什么一旦处理了多个区域性,所有模板都必须以UTF-8格式保存,并且布局必须使用此字符集声明内容。如果您总是使用UTF-8,您将不会有任何不愉快的惊喜,并且您将避免自己头痛。
ob娱乐下载Symfony应用程序依赖于字符集的一个中心设置settings.yml
文件。更改此参数将更改内容类型
所有响应的头。
所有:.settings: charset: utf-8
在模板外部调用翻译助手
并非页面中显示的所有文本都来自模板。这就是为什么您经常需要调用__ ()
应用程序的其他部分中的Helper:操作、过滤器、模型类等等。类的当前实例,清单13-19显示了如何在操作中调用helperI18N
对象通过context单例。
清单13-19 -呼叫__ ()
在行动中
这个美元->getContext()->getI18N()- > __(美元的文本,args美元,“消息”);
总结
如果你知道如何处理用户文化,在web应用程序中处理国际化和本地化是轻松的。helper会自动考虑输出正确格式化的数据,并且将数据库中的本地化内容视为简单表的一部分。至于界面翻译,__ ()
helper和XLIFF字典确保您以最少的工作获得最大的通用性。
本作品在GFDL许可下获得许可。