本地化应用程序
本地化应用程序
有国际观众,Symfony已经能够处理国际化(i18n)和本地化ob娱乐下载(l10n)开箱即用的因为喜欢。本地化应用程序不仅仅是翻译界面,也是复数,日期和货币格式,网址等等。
国际化的url
国际化的第一步是国际化的网站的url。翻译网站界面时,URL应该每个地区不同的打好与HTTP缓存(不要使用相同的URL,并在会话中存储区域)。
使用特殊的_locale
线路参数参考路线的地区:
1 2 3 4 5 6 7 8 9 10 11
- - - / src /控制器/ ConferenceController.php+ + + b / src /控制器/ ConferenceController.php@@ -28 7 + 28 7 @@类ConferenceController扩展AbstractController) {}- #[路线(“/”,名字:“主页”))+ #[路线(“/ {_locale} /”,名字:“主页”))公共函数指数(ConferenceRepository ConferenceRepository美元):响应{返回$ this - >渲染(会议/ index . html。嫩枝”,(
主页上,地区现在是设置在内部根据URL;例如,如果你的打击/ fr /
,$请求- > getLocale ()
返回fr
。
正如你可能无法翻译的内容在所有有效的地区,你想要支持的限制:
1 2 3 4 5 6 7 8 9 10 11
- - - / src /控制器/ ConferenceController.php+ + + b / src /控制器/ ConferenceController.php@@ -28 7 + 28 7 @@类ConferenceController扩展AbstractController) {}- #[路线(“/ {_locale} /”,名字:“主页”))+ #[路线(' / {_locale < en | fr >} / ',名字:“主页”))公共函数指数(ConferenceRepository ConferenceRepository美元):响应{返回$ this - >渲染(会议/ index . html。嫩枝”,(
每个路由参数可以通过正则表达式限制<
>
。的主页
现在只有比赛的时候_locale
参数是在
或fr
。试着打/ es /
,你应该有一个404年没有匹配的路线。
我们会使用相同的要求几乎所有的路线,让我们把它移动到一个容器参数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
- - - / config / services.yaml+ + + b / config / services.yaml@@ 9 6 + 9 7 @@参数:admin_email:“% env(字符串:默认值:default_admin_email: admin_email) %”default_base_url: router.request_context“http://127.0.0.1”。base_url:“% env(默认值:default_base_url: SYMob娱乐下载FONY_DEFAULT_ROUTE_URL) % '+ app.supported_locales:“en | fr”服务:#在* *文件默认配置服务- - - / src /控制器/ ConferenceController.php+ + + b / src /控制器/ ConferenceController.php@@ -28 7 + 28 7 @@类ConferenceController扩展AbstractController) {}- #[路线(' / {_locale < en | fr >} / ',名字:“主页”))+ #【路线(' / {_locale < %应用。supported_locales % >} /”,名字:“主页”)公共函数指数(ConferenceRepository ConferenceRepository美元):响应{返回$ this - >渲染(会议/ index . html。嫩枝”,(
添加一个语言可以通过更新完成app.supported_languages
参数。
添加相同的地区前缀路由到其他网址:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
- - - / src /控制器/ ConferenceController.php+ + + b / src /控制器/ ConferenceController.php@@ -36 7 + 36 7 @@类ConferenceController延伸AbstractController]) - > setSharedMaxAge (3600);}- #[路线(“/ conference_header”,名字:“conference_header”))+ #【路线(' / {_locale < %应用。supported_locales % >} / conference_header”,名字:“conference_header”)公共函数conferenceHeader (ConferenceRepository ConferenceRepository美元):响应{返回$ this - >渲染(会议/ header.html。嫩枝”,[@@ -44 7 + 44 7 @@类ConferenceController延伸AbstractController]) - > setSharedMaxAge (3600);}- #[路线(“/会议/{蛞蝓}”,名字:“会议”))+ #【路线(' / {_locale < %应用。supported_locales % >} /会议/{蛞蝓}”,名字:“会议”)公共函数显示(请求请求美元,美元会议,会议
我们几乎已经完成了。我们没有匹配的路线/
了。让我们添加它,让它重定向到/ en /
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
- - - / src /控制器/ ConferenceController.php+ + + b / src /控制器/ ConferenceController.php@@ -28年6 + 28日12 @@类ConferenceController扩展AbstractController) {}+ #(路线(“/”))+公共职能indexNoLocale():反应+ {+ $ this - > redirectToRoute返回(“主页”,(“_locale”= >“en”));+}+#(路线(' / {_locale < %应用。supported_locales % >} /”,名字:“主页”)]公共函数指数(ConferenceRepository ConferenceRepository美元):反应{
现在所有航线主要有语言环境意识到,注意到生成的url的页面自动考虑当前语言环境。
添加一个语言环境切换器
允许用户从默认切换在
另一个语言环境,让我们添加一个标题切换器:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
- - - /模板/ base.html.twig+ + + b /模板/ base.html.twig6 + 34 @@ -34年,16 @@李管理< / > < / >+ <李类= " nav-item拉" >+ < class = " nav-link dropdown-toggle " href = " # " id =“dropdown-language”角色=“按钮”+ data-bs-toggle =“下拉”aria-haspopup = " true " aria-expanded =“false”>+英语+ < / >+ < ul类= "下拉菜单dropdown-menu-right”aria-labelledby = " dropdown-language " >+ <李> < class = " dropdown-item " href = "{{路径(“主页”,{_locale:“en”})}} " > < / > < /李>英语+ <李> < class = " dropdown-item " href = "{{路径(“主页”,{_locale:“fr”})}} " > < / > < /李>法语+ < / ul >李+ < / >< / ul > < / div > < / div >
切换到另一个地区,我们显式地通过_locale
线路参数路径()
函数。
更新模板来显示当前语言环境名称而不是硬编码的“英语”:
1 2 3 4 5 6 7 8 9 10 11
- - - /模板/ base.html.twig+ + + b /模板/ base.html.twig@@ -37年,37岁的7 + 7 @@<李class = " nav-item拉" > < class = " nav-link dropdown-toggle " href = " # " id =“dropdown-language”角色=“按钮”data-bs-toggle =“下拉”aria-haspopup = " true " aria-expanded =“false”>- - - - - -英语+ {{app.request.locale | locale_name (app.request.locale)}}< / > < ul类= "下拉菜单dropdown-menu-right”aria-labelledby = " dropdown-language " > <李> < class = " dropdown-item " href = "{{路径(“主页”,{_locale:“en”})}} " > < / > < /李>英语
应用程序
是一个全球性的树枝出访问当前请求变量。将区域设置一个人类可读的字符串,我们使用locale_name
树枝过滤器。
根据不同的语言环境,语言环境名称并不总是大写。利用正确的句子,我们需要一个过滤器是Unicode知道,Symfony提供的字符串组件和它的树枝实现:ob娱乐下载
1
美元ob娱乐下载symfony作曲家点播树枝/ string-extra
1 2 3 4 5 6 7 8 9 10 11
- - - /模板/ base.html.twig+ + + b /模板/ base.html.twig@@ -37年,37岁的7 + 7 @@<李class = " nav-item拉" > < class = " nav-link dropdown-toggle " href = " # " id =“dropdown-language”角色=“按钮”data-bs-toggle =“下拉”aria-haspopup = " true " aria-expanded =“false”>- {{app.request.locale | locale_name (app.request.locale)}}+ {{app.request.locale | locale_name (app.request.locale) | u。标题}}< / > < ul类= "下拉菜单dropdown-menu-right”aria-labelledby = " dropdown-language " > <李> < class = " dropdown-item " href = "{{路径(“主页”,{_locale:“en”})}} " > < / > < /李>英语
您现在可以从法国转到英语通过切换器和整个界面很好地适应本身:
翻译的接口
翻译每个句子在一个大型网站上可能很乏味,但幸运的是,我们只有少量的信息在我们的网站上。让我们先从所有的主页上的句子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17日18 19 20 21日22日23日24日25日26日27 28 29 30 31
- - - /模板/ base.html.twig+ + + b /模板/ base.html.twig7 @@ @@ -20年7 + 20日<导航类= "导航navbar-expand-xl navbar-light bg-light”> < div class = "容器mt-4 mb-3”> < class = " navbar-brand我pr-2 " href = "{{路径(主页)}}" >- & # 128217;会议留言板+ & # 128217;{{“会议留言板”|反式}}< / > <按钮类= " navbar-toggler border-0 " type = "按钮" data-bs-toggle =“崩溃”data-bs-target = " # header-menu " aria-controls =“navbarSupportedContent aria-expanded”=“false”aria-label = "显示/隐藏导航" >- - - /模板/会议/ index.html.twig+ + + b /模板/会议/ index.html.twig@@ 4、7 + 4,7 @@{%块体%}< h2类= " mb-5 " >——给你的反馈!+{{'给你的反馈!“|反式}}< / h2 >{%在会议|行批处理(4)%}7 @@ @@ -21年7 + 21日< a href = "{{路径(“会议”,{蛞蝓:会议。蛞蝓})}}”class = " btn btn-sm btn-primary stretched-link " >——视图+{{‘视图’|反式}}< / > < / div > < / div >
的反式
树枝过滤查找翻译给定输入的当前的语言环境。如果没有找到,则落回缺省语言环境中的配置配置/包/ translation.yaml
:
1 2 3 4 5 6
框架:default_locale:在翻译:default_path:' % kernel.project_dir % /翻译'回退:- - - - - -在
注意web调试工具栏翻译“选项卡”已经变红了:
它告诉我们,3消息还没有翻译。
点击“标签”列表中所有消息的Symfony没有找到一个翻译:ob娱乐下载
提供翻译
正如你所看到的配置/包/ translation.yaml
翻译存储下一个翻译/
根目录,自动创建。
而不是手工创建的翻译文件,使用翻译:提取
命令:
1
美元ob娱乐下载symfony控制台翻译:提取fr -力-域=消息
这个命令生成一个翻译文件(——力
国旗)fr
语言环境和消息
域。的消息
域包含所有应用程序消息不包括那些来自Symfony本身像验证或安全错误。ob娱乐下载
编辑翻译/消息+ intl-icu.fr.xlf
文件和翻译在法国的消息。不讲法语?让我来帮你:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
- - - /翻译/消息+ intl-icu.fr.xlf+ + + + intl-icu.fr.xlf b /翻译/消息15 @@ @@ 7日15 + 7,<身体> < trans-unit id = " eOy4.6V " resname = "会议留言板" > <源>会议留言板源> < /- <目标> __Conference留言板目标> < /+ <目标>里弗d ' or倒会议目标> < /< / trans-unit > < trans-unit id = " LNAVleg " resname = "给你的反馈!> <源>给你反馈! > < /来源——<目标> __Give你反馈! < /目标>+ <目标> Donnez你们认为! < /目标>< / trans-unit > < trans-unit id =“3 mg5paf”resname =“视图”> <源>视图> < /来源- <目标> __View目标> < /+ <目标>选择目标> < /< / trans-unit > < /身体> < /文件>
请注意,我们不会翻译所有模板,但请这样做:
翻译形式
表单标签会自动显示Symfony通过翻译系统。ob娱乐下载去一个会议页面的“翻译”选项卡并单击web调试工具栏;您应该看到所有标签准备好翻译:
本地化的日期
如果你切换到法国,去一个会议网页有一些评论,你会注意到评论日期自动本地化。这种安排是可行的,因为我们使用了format_datetime
树枝过滤器,识别地区({{发表评论。createdAt | format_datetime(“媒介”,“短”)}}
)。
本地化工作日期、时间(format_time
),货币(format_currency
)和数字(format_number
)一般(百分比,持续时间,拼出,…)。
翻译复数
复数总经理翻译是使用更一般的选择基于条件的翻译问题。
会议上的页面,我们显示评论的数量:有两个评论
。1评论,我们显示有1的评论
,这是错误的。修改模板将句子转换成可翻译的信息:
1 2 3 4 5 6 7 8 9 10 11
- - - /模板/会议/ show.html.twig+ + + b /模板/会议/ show.html.twig7 + 44 @@ -44年,7 @@< / div > < / div > {% endfor %}——< div >有{{评论|长度}}评论。< / div >+ < div > {{“nb_of_comments”|反式({长度数:评论|})}}< / div >{%如果先前> = 0%}< a href = "{{路径(“会议”,{蛞蝓:会议。蛞蝓,抵消:以前})之前}}" > < / > {% endif %}
对于这个消息,我们使用了另一种翻译策略。而不是把英文版本的模板,取而代之的是一个惟一的标识符。这一策略更好的适用于复杂,大量的文本。
翻译文件通过添加新的消息更新:
1 2 3 4 5 6 7 8 9 10 11 12 13
- - - /翻译/消息+ intl-icu.fr.xlf+ + + + intl-icu.fr.xlf b /翻译/消息10 @@ @@ -17年6 + 17日<源>会议留言板< /源> <目标>里弗d ' or倒会议< /目标> < / trans-unit >+ < trans-unit id = " Dg2dPd6“resname = " nb_of_comments " >+ <源> nb_of_comments源> < /+ <目标>{数、复数、= 0{没有commentaire。{1 commentaire} = 1。}other {# commentaires.}}< /span>+ < / trans-unit >< /身体> < /文件> < / xliff >
我们还没有完成,因为我们现在需要提供英文翻译。创建翻译/消息+ intl-icu.en.xlf
文件:
更新功能测试
别忘了更新功能测试考虑url和内容更改:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17日18 19 20 21日22日23日24日25日26日27 28 29 30 31 32 33 34 35 36 37
- - - /测试/控制器/ ConferenceControllerTest.php+ + + b /测试/控制器/ ConferenceControllerTest.php@@ -11 7 + 11 7 @@类ConferenceControllerTest WebTestCase延伸公共函数testIndex(){$客户=静态:createClient ();-客户- >请求(‘得到’,‘/’);+ $客户- >请求(‘得到’,' / en / ');$ this - > assertResponseIsSuccessful ();$ this - > assertSelectorTextContains (h2,给你反馈);@@ -20 7 + 20 7 @@类ConferenceControllerTest WebTestCase延伸公共函数testCommentSubmission(){$客户=静态:createClient ();-客户- >请求(‘得到’,' /会议/阿姆斯特丹- 2019 ');+ $客户- >请求(‘得到’,‘/ en /会议/阿姆斯特丹- 2019);$客户- > submitForm(‘提交’,‘comment_form(作者)”= >“法”,“comment_form[文本]= >从自动化功能测试的一些反馈,@@ -41年7 + 41,7 @@类ConferenceControllerTest WebTestCase延伸公共函数testConferencePage(){$客户=静态:createClient ();-履带=美元客户- >请求(‘得到’,‘/’);+ $履带= $客户- >请求(‘得到’,' / en / ');$ this - > assertCount(2 $履带- >过滤器(h4));@@ -50 50 6 + 6 @@类ConferenceControllerTest延伸WebTestCase $ this - > assertPageTitleContains(阿姆斯特丹);$ this - > assertResponseIsSuccessful ();$ this - > assertSelectorTextContains (h2,阿姆斯特丹2019);- $ this - > assertSelectorExists (“div:包含(“有1评论”)');+ $ this - > assertSelectorExists (“div:包含(“有一个评论”)');}}
要进一步