尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Yii 2 国际化(I18N)实战指南:Locale 配置、消息翻译与多语言格式化

Yii 2 国际化(I18N)实战指南:Locale 配置、消息翻译与多语言格式化 Yii 2 国际化I18N实战指南Locale 配置、消息翻译与多语言格式化【免费下载链接】yii2Yii 2: The Fast, Secure and Professional PHP Framework项目地址: https://gitcode.com/gh_mirrors/yi/yii2本文以 Yii 2 框架的国际化Internationalisation, I18N能力为核心系统讲解如何在应用中引入语言环境Locale与目标语言、使用Yii::t()与消息源MessageSource完成文本翻译、借助 ICU 消息格式对数字、日期、复数与性别选择进行本地化格式化并深入message命令行工具的配置与使用。读完本文你将能够独立为一个 Yii 2 应用搭建完整的多语言体系并理解其底层实现原理。Locale 与语言环境配置Locale语言环境是一组定义用户语言、国家/地区及界面显示偏好的参数集合通常由一个 ID 标识该 ID 由语言标识与地区标识组成例如en-US表示英语美国。为保证一致性Yii 要求所有标识符使用规范形式ll-CC其中ll是符合 ISO-639 标准的 2 或 3 字母语言代码CC是符合 ISO-3166 标准的 2 字母国家/地区代码。关于 Locale 的完整概念可参考 ICU 项目文档。在 Yii 的语境中语言langue一词经常被用来指代 Locale。一个 Yii 应用会涉及两种语言源语言sourceLanguage源代码中消息文本所使用的语言即开发者书写消息原文的语言目标语言language用于向最终用户展示文本的语言。消息翻译服务message translation service正是负责把消息从源语言翻译到目标语言的核心服务。在配置文件中设置两种语言在应用配置中可同时指定目标语言与源语言return [ // 设定目标语言为法语法国 language fr-FR, // 设定源语言为英语美国 sourceLanguage en-US, ...... ];源语言的默认值是en-US。官方建议保持该值不变因为通常更容易找到能将英语翻译成其他语言的译者而非将一种非英语语言翻译成另一种非英语语言。动态修改目标语言目标语言常常需要根据用户偏好等因素动态设置。此时可以不修改配置文件而在代码中直接赋值// 将目标语言改为法语法国 \Yii::$app-language fr-FR;Tip: 如果你的代码不同部分使用不同的源语言可以按下一节所述的方式在局部修改源语言的值。从源码结构看language与sourceLanguage分别对应yii\base\Application::$language与yii\base\Application::$sourceLanguage两个属性前者默认值即en-US二者在组件初始化时被读取并传递给 i18n 组件使用。消息翻译服务与Yii::t()消息翻译服务负责把文本消息从一种语言通常是源语言翻译为另一种语言通常是目标语言。其工作方式是在消息源message source中检索待翻译消息消息源中存储着原文与译文的对应关系若找到则返回对应译文否则原样返回消息原文。使用消息翻译服务需要完成三步将待翻译文本包裹在Yii::t()方法调用中配置一个或多个消息源供翻译服务检索译文让译者翻译消息并存入消息源。Yii::t()的调用方式echo \Yii::t(app, This is a string to translate!);其中第二个参数是要翻译的文本消息第一个参数是消息所属的**类别category**名称。从 BaseYii::t() 源码 可以看到其底层调用链Yii::t()实际会调用应用组件i18n的translate()方法将类别、消息、参数与目标语言一并传入public static function t($category, $message, $params [], $language null) { if (static::$app ! null) { return static::$app-getI18n()-translate($category, $message, $params, $language ?: static::$app-language); } // 应用未初始化时的降级处理仅做简单的占位符替换 $placeholders []; foreach ((array) $params as $name $value) { $placeholders[{ . $name . }] $value; } return ($placeholders []) ? $message : strtr($message, $placeholders); }配置 i18n 组件与消息源i18n是 Yii 内置的应用组件可在应用配置中如下配置components [ // ... i18n [ translations [ app* [ class yii\i18n\PhpMessageSource, //basePath app/messages, //sourceLanguage en-US, fileMap [ app app.php, app/error error.php, ], ], ], ], ],上述配置注册了一个由yii\i18n\PhpMessageSource支撑的消息源。类别模式app*表示所有以app开头的消息类别都使用该消息源翻译。PhpMessageSource使用 PHP 文件存放翻译每个 PHP 文件对应一个类别的消息。默认情况下文件名必须与类别名相同但你可以通过配置fileMap文件映射表将某个类别映射到采用其他命名方式或拆分到子目录的 PHP 文件。以上面示例来说类别app/error会对应 PHP 文件app/messages/fr-FR/error.php假设fr-FR为目标语言若不配置fileMap该类别则对应app/messages/fr-FR/app/error.php。从 PhpMessageSource 源码 看消息文件路径由basePath、语言代码与类别名拼接而成{basePath}/{语言}/{类别}.php类别中的/或\会被视为命名空间分隔符。同时该实现会对语言代码与类别名做合法性校验防止路径穿越如拒绝包含..段、绝对路径或php://流包装器的类别这从安全角度保证了消息文件不会逃逸出basePath。消息源的三种存储形态除 PHP 文件外Yii 还提供两种消息源yii\i18n\GettextMessageSource使用 GNU Gettext 的 MO/PO 文件维护译文可通过basePath、catalog、useMoFile是否优先读取编译后的 MO 文件与useBigEndian字节序等属性配置yii\i18n\DbMessageSource使用数据库存储译文。DbMessageSource依赖两张表source_message待翻译源消息与message译文表名可通过sourceMessageTable与messageTable自定义数据库连接由db属性指定。表结构可通过框架自带的迁移初始化迁移文件yii migrate --migrationPathyii/i18n/migrations/该消息源还支持通过enableCaching、cache与cachingDuration属性对译文做缓存避免每次翻译都查询数据库。消息源解析与回退机制在 I18N::translate() 源码 中翻译流程分两步先由消息源完成查找译文再对译文做参数格式化public function translate($category, $message, $params, $language) { $messageSource $this-getMessageSource($category); $translation $messageSource-translate($category, $message, $language); if ($translation false) { // 未找到译文时直接用源语言格式化源消息 return $this-format($message, $params, $messageSource-sourceLanguage); } return $this-format($translation, $params, $language); }类别与消息源的匹配逻辑在 getMessageSource() 中先精确匹配类别名再按模式后缀通配符*匹配如app*最后才尝试全局通配*。另外在 I18N::init() 中框架默认注册了yii与app两个类别分别使用yii/messages与app/messages作为basePath。值得注意的还有 MessageSource::translate() 的优化除非设置forceTranslation true当目标语言与源语言相同时消息不会被翻译直接返回false交由上层按源语言格式化。而 PhpMessageSource::loadMessages() 还实现了语言回退合并请求fr-FR时若找不到完整地区文件会尝试加载更通用的fr译文再将精确地区译文覆盖其上。消息格式化占位符与 ICU 消息格式翻译消息时可以在消息中嵌入占位符valeurs à remplacer运行时根据参数值动态替换还可以使用特殊的占位符语法让替换值按目标语言进行格式化。下面逐一介绍各种格式化方式。消息占位符参数在待翻译消息中可以嵌入一个或多个占位符通过传入不同参数值动态改变消息内容。下面的示例中消息Hello, {username}!的占位符{username}分别被替换为Alexander与Qiang$username Alexander; // 输出翻译后的消息将 {username} 替换为 Alexander echo \Yii::t(app, Hello, {username}!, [ username $username, ]); $username Qiang; // 输出翻译后的消息将 {username} 替换为 Qiang echo \Yii::t(app, Hello, {username}!, [ username $username, ]);译者在翻译包含占位符的消息时必须原样保留占位符因为占位符会在调用Yii::t()时才被真实值替换。同一消息中命名占位符与位置占位符不能混用只能二选一。命名占位符形如{nom}调用时传入关联数组键为占位符名不含花括号值为替换值位置占位符使用从 0 开始的整数作为占位符名调用时按数组位置依次替换。下面示例中{0}、{1}、{2}分别被$price、$count、$subtotal替换$price 100; $count 2; $subtotal 200; echo \Yii::t(app, Price: {0}, Count: {1}, Subtotal: {2}, [$price, $count, $subtotal]);只有一个占位符时替换值可以不用数组包裹echo \Yii::t(app, Price: {0}, $price);Tip: 大多数情况下应优先使用命名占位符因为名称能让译者更准确地理解待翻译消息的含义。从 I18N::format() 源码 可以看到当参数数组为空时直接返回原文当消息中包含 ICU 格式特征正则{\s*[\w.]\s*,时走MessageFormatter格式化否则执行简单的strtr()占位符替换。占位符的格式化语法可以在占位符中附加格式化规则作用于替换值。下面的示例把price当作数字并按货币格式输出$price 100; echo \Yii::t(app, Price: {0,number,currency}, $price);Note: 占位符的格式化需要安装 PHP 的 intl 扩展。占位符格式化支持短格式与完整格式两种写法短格式{name,type} 完整格式{name,type,style}Note: 如果消息中需要{、}、、#等特殊字符请用单引号包起来echo Yii::t(app, Example of string with -escaped characters: { } {test} {count,plural,other{count value is # #{}}}, [count 3]);完整的格式规范由 ICU MessageFormat 定义。在 MessageFormatter 源码 中格式化优先使用 PHP intl 扩展的\MessageFormatter类并对命名参数做了预处理replaceNamedArguments会把命名参数映射为数字参数再交给 intl若 intl 未安装则退回到fallbackFormat()实现。数字number占位符被当作数字处理$sum 42; echo \Yii::t(app, Balance: {0,number}, $sum);可以指定可选样式integer整数、currency货币或percent百分比$sum 42; echo \Yii::t(app, Balance: {0,number,currency}, $sum);也可以指定自定义数字模式$sum 42; echo \Yii::t(app, Balance: {0,number,,000,000000}, $sum);自定义模式中可用的特殊字符参见 ICU DecimalFormat 文档的 Special Pattern Characters 一节。注意占位符总是按目标语言环境格式化也就是说你无法在不改变翻译 Locale 的情况下修改千分位/小数点分隔符、货币符号等。若需要这类自定义能力应改用yii\i18n\Formatter::asDecimal()与yii\i18n\Formatter::asCurrency()。日期date占位符按日期格式化echo \Yii::t(app, Today is {0,date}, time());可指定short短、medium中、long长或full完整等样式echo \Yii::t(app, Today is {0,date,short}, time());也可以指定自定义日期模式echo \Yii::t(app, Today is {0,date,yyyy-MM-dd}, time());时间time占位符按时间时、分、秒格式化echo \Yii::t(app, It is {0,time}, time());同样支持short、medium、long、full样式与自定义模式echo \Yii::t(app, It is {0,time,short}, time()); echo \Yii::t(app, It is {0,date,HH:mm}, time());数字拼读spellout占位符被当作数字并格式化为拼读形式// 输出 42 is spelled as forty-two echo \Yii::t(app, {n,number} is spelled as {n,spellout}, [n 42]);默认按基数cardinal拼读可以修改为序数拼读// 输出 I am forty-seventh agent echo \Yii::t(app, I am {n,spellout,%spellout-ordinal} agent, [n 47]);注意spellout,与%之间不能有空格。要查询某个 Locale 可用的选项列表可参考 ICU 文档 Numbering schemas, Spellout 部分。序数ordinal占位符被当作数字并格式化为序数// 输出 You are the 42nd visitor here! echo \Yii::t(app, You are the {n,ordinal} visitor here!, [n 42]);序数对某些语言如西班牙语支持更多格式// 输出 471ª echo \Yii::t(app, {n,ordinal,%digits-ordinal-feminine}, [n 471]);注意ordinal,与%之间不能有空格。时长duration占位符被当作秒数并格式化为时长// 输出 You are here for 47 sec. already! echo \Yii::t(app, You are here for {n,duration} already!, [n 47]);时长也支持其他格式// 输出 130:53:47 echo \Yii::t(app, {n,duration,%in-numerals}, [n 471227]);注意duration,与%之间不能有空格。复数plural不同语言对复数的标记规则差异很大。Yii 提供了一种便捷的方式让消息可以按不同复数形式翻译即使面对非常复杂的规则也能工作。你无需直接处理词的屈折变化规则只需提供某些情境下的屈折词翻译即可。例如// $n 0 时输出 There are no cats! // $n 1 时输出 There is one cat! // $n 42 时输出 There are 42 cats! echo \Yii::t(app, There {n,plural,0{are no cats} 1{is one cat} other{are # cats}}!, [n $n]);上述复数规则参数中表示精确值0表示恰好为 01表示恰好为 1other表示其他任意值#会被替换为按目标语言格式化后的n值。有些语言的复数形式非常复杂。下面的俄语示例中1表示n恰好为 1而one对应 21 或 101 这类值Здесь {n,plural,0{котов нет} 1{есть один кот} one{# кот} few{# кота} many{# котов} other{# кота}}!other、few、many等特殊参数名随语言而异具体某个 Locale 应使用哪些参数名可参考 Unicode CLDR 的复数规则文档Plural Rules, Cardinal。Note: 上面的俄语消息主要用于译文而非源消息除非你把应用的源语言设为ru-RU并从俄语翻译。当Yii::t()调用中的源消息找不到对应翻译时将应用源语言的复数规则对源消息进行格式化。当字符串包含offset时复数规则还支持偏移量参数$likeCount 2; echo Yii::t(app, You {likeCount,plural, offset: 1 0{did not like this} 1{liked this} one{and one other person liked this} other{and # others liked this} }, [ likeCount $likeCount ]); // 输出You and one other person liked this偏移量offset: 1意味着#将替换为n - 1因此当likeCount 2时命中one分支2 - 1 1输出 You and one other person liked this。在 MessageFormatter 的 fallback 实现 中可以看到即使没有 intl 扩展plural也支持offset、精确值n、one与other分支的简单处理但更复杂的few、many等规则依赖 intl 才能正确工作。序数选择selectordinalselectordinal参数用于根据目标语言的序数语言规则从多个字符串中选择一个。例如$n 3; echo \Yii::t(app, You are the {n,selectordinal,one{#st} two{#nd} few{#rd} other{#th}} visitor, [n $n]);英文输出You are the 3rd visitor俄语译文与输出You are the {n,selectordinal,one{#st} two{#nd} few{#rd} other{#th}} visitor Вы {n,selectordinal,other{#-й}} посетитель,输出Вы 3-й посетитель法语译文与输出You are the {n,selectordinal,one{#st} two{#nd} few{#rd} other{#th}} visitor Vous êtes le {n,selectordinal,one{#er} other{#e}} visiteur输出Vous êtes le 3e visiteur该格式与复数格式非常接近。具体某个 Locale 应使用哪些参数名可参考 Unicode CLDR 的 Plural Rules, Ordinal 部分。选择selectselect参数可以根据替换值从多个短语中选择其一。例如// 可能输出 Snoopy is a dog and it loves Yii! echo \Yii::t(app, {name} is a {gender} and {gender,select,female{she} male{he} other{it}} loves Yii!, [ name Snoopy, gender dog, ]);上例中female与male是参数可能取值other兜底其余取值每个取值后面要用花括号包裹对应的短语片段。默认消息源与通配符配置可以指定一个默认消息源作为未匹配到任何已配置类别的回退。该消息源必须用通配符*标记。在应用配置中添加// 配置 i18n 组件 i18n [ translations [ * [ class yii\i18n\PhpMessageSource ], ], ],此后你可以直接使用未配置过的类别这与 Yii 1.1 的行为一致。该类别消息来自默认消息源所在的basePath即app/messagesecho Yii::t(not_specified_category, message from unspecified category);该消息将从app/messages/LanguageCode/not_specified_category.php加载。结合 I18N::getMessageSource() 的实现可以确认匹配顺序精确类别名 → 带*前缀模式如app*→ 全局*最后仍无法匹配时才抛出InvalidConfigException。模块消息的翻译如果希望翻译某个模块的消息、并避免把所有模块消息堆进同一个翻译文件可以这样组织?php namespace app\modules\users; use Yii; class Module extends \yii\base\Module { public $controllerNamespace app\modules\users\controllers; public function init() { parent::init(); $this-registerTranslations(); } public function registerTranslations() { Yii::$app-i18n-translations[modules/users/*] [ class yii\i18n\PhpMessageSource, sourceLanguage en-US, basePath app/modules/users/messages, fileMap [ modules/users/validation validation.php, modules/users/form form.php, ... ], ]; } public static function t($category, $message, $params [], $language null) { return Yii::t(modules/users/ . $category, $message, $params, $language); } }上例用通配符进行类别匹配再用fileMap把每个类别映射到所需文件也可以不使用fileMap改用同名文件的默认映射约定。此后可以直接调用Module::t(validation, your custom validation message)或Module::t(form, some form label)。这里用到的技巧是模块在init()阶段动态地向Yii::$app-i18n-translations数组中注册自己的消息源——这正是 I18N::$translations 被设计为可随时修改的原因源码注释明确说明该属性可被扩展在运行时注册自己的消息源。Widget 消息的翻译上述模块规则同样适用于 Widget例如?php namespace app\widgets\menu; use yii\base\Widget; use Yii; class Menu extends Widget { public function init() { parent::init(); $this-registerTranslations(); } public function registerTranslations() { $i18n Yii::$app-i18n; $i18n-translations[widgets/menu/*] [ class yii\i18n\PhpMessageSource, sourceLanguage en-US, basePath app/widgets/menu/messages, fileMap [ widgets/menu/messages messages.php, ], ]; } public function run() { echo $this-render(index); } public static function t($category, $message, $params [], $language null) { return Yii::t(widgets/menu/ . $category, $message, $params, $language); } }同样也可以不用fileMap而采用同名文件约定。此后可直接调用Menu::t(messages, new messages {messages}, [{messages} 10])。Note: 对 Widget 而言你还可以使用 i18n 视图view规则与控制器视图一致见下文视图翻译一节。覆盖框架自带消息Yii 自带验证错误等默认消息的翻译这些消息全部属于yii类别。框架的真实翻译文件存放在 framework/messages/ 下每个语言一个子目录如 framework/messages/fr/ 即框架内置的法语翻译。如需修正框架默认翻译可如下配置i18n组件i18n [ translations [ yii [ class yii\i18n\PhpMessageSource, sourceLanguage en-US, basePath app/messages ], ], ],然后将修正后的翻译放入app/messages/language/yii.php即可。这与 I18N::init() 中默认注册的yii类别配置同构——框架默认将yii类别指向yii/messages你的配置会覆盖它。处理缺失的翻译即使消息源中找不到翻译Yii 也会原样显示请求的消息内容。只要源消息本身是完整通顺的句子这种原样回退行为就非常实用。但有时这还不够——你可能希望在消息缺失时做一些额外处理。为此可以使用yii\i18n\MessageSource::EVENT_MISSING_TRANSLATIONmissingTranslation 事件。例如你希望把所有缺失翻译标记上醒目的内容以便在页面上快速定位。首先在应用配置中注册事件处理器components [ // ... i18n [ translations [ app* [ class yii\i18n\PhpMessageSource, fileMap [ app app.php, app/error error.php, ], on missingTranslation [app\components\TranslationEventHandler, handleMissingTranslation] ], ], ], ],然后实现事件处理器?php namespace app\components; use yii\i18n\MissingTranslationEvent; class TranslationEventHandler { public static function handleMissingTranslation(MissingTranslationEvent $event) { $event-translatedMessage MISSING: {$event-category}.{$event-message} FOR LANGUAGE {$event-language} ; } }若处理器设置了yii\i18n\MissingTranslationEvent::translatedMessage该值将作为翻译结果被输出。Note: 每个消息源独立处理各自的缺失翻译。如果使用多个消息源并希望它们以相同方式处理缺失消息需要给每个消息源都绑定对应的事件处理器。结合 MessageSource::translateMessage() 的源码可以看到完整机制查不到译文时触发EVENT_MISSING_TRANSLATION若事件对象携带了translatedMessage则作为译文缓存并返回否则返回false交由上层按源语言直接格式化。使用message命令提取与管理翻译翻译可以存放在 PHP 文件、.po 文件或数据库中具体选项请参考对应类。命令的完整实现位于 framework/console/controllers/MessageController.php。生成配置文件模板首先需要创建一个配置文件。确定存放位置后执行./yii message/config-template path/to/config.php该命令会将框架自带的模板源码中actionConfigTemplate()通过复制yii/views/messageConfig.php实现拷贝到目标路径。打开生成的文件并按需调整参数特别注意以下两项languages应用需要翻译成的语言代码数组messagePath消息文件存放目录必须与应用配置中i18n的basePath保持一致。动态生成配置文件也可以使用./yii message/config命令通过命令行参数动态生成配置文件。例如./yii message/config --languagesde,ja --messagePathmessages path/to/config.php查看全部可用选项./yii help message/config从 actionConfig() 源码 看该命令会把当前命令的所有选项值导出为 PHP 数组并写入目标文件若文件已存在会交互式询问是否覆盖。提取消息配置完成后用下面的命令真正提取消息./yii message path/to/config.php也可以附加选项动态覆盖提取参数。提取完成后如果选择的是文件型翻译译文文件会出现在messagePath目录下每个语言一个子目录如messagePath/fr-FR/。提取配置参数详解actionExtract() 源码 展示了提取流程扫描sourcePath下的源码文件 → 通过translator标记默认为Yii::t/\Yii::t定位待翻译消息 → 按languages逐个语言写出译文文件。框架自身就使用该机制维护翻译其真实配置见 framework/messages/config.php常用参数包括参数说明sourcePath源码根目录字符串必填默认yiimessagePath译文存放根目录字符串必填languages目标语言代码数组例如[zh-CN, de]translator用于定位待翻译消息的函数名标记可传字符串或数组sort是否按键排序新老消息false时未翻译新消息与已翻译旧消息分离存放overwrite是否用合并结果覆盖消息文件默认trueremoveUnused是否删除源码中已不存在的消息默认falsemarkUnused是否用一对包裹不再使用的消息默认trueexcept不需要处理的文件/目录模式列表如/messages、/tests、/vendoronly只处理匹配的文件模式如*.phpformat生成文件格式可为php、db或podbdb格式使用的数据库连接组件 IDsourceMessageTable/messageTabledb格式的源消息表与译文表名catalogpo格式的目录名catalogphpFileHeader/phpDocBlock生成 PHP 文件时的文件头与 DocBlock 注释2.0.13视图翻译除了逐条翻译消息文本有时你可能希望翻译整个视图脚本。做法很简单翻译视图并保存在以目标语言代码命名的子目录中。例如你翻译了视图views/site/index.php且目标语言为fr-FR就把译文保存为views/site/fr-FR/index.php。此后每次调用yii\base\View::renderFile()或任何调用它的方法如yii\base\Controller::render()渲染views/site/index.php时实际渲染的将是views/site/fr-FR/index.php。Note: 当目标语言与源语言相同时会渲染原始视图而不管是否存在已翻译的视图。日期与数字格式化关于yii\i18n\Formatter组件对日期、时间与数字的完整格式化能力如asDate()、asTime()、asDecimal()、asCurrency()等方法详见数据格式化一节。PHP 运行环境intl 扩展与 ICU 版本Yii 依赖 PHP 的 intl 扩展 提供大部分国际化功能包括yii\i18n\Formatter的日期/数字格式化与yii\i18n\MessageFormatter的消息格式化。两个类都在 intl 未安装时提供降级实现但降级实现只在目标语言为英语时才能正常工作因此强烈建议按需安装intl。PHP intl 扩展基于 ICU 库后者提供了各种 Locale 的知识库与格式化规则。不同版本的 ICU 可能导致日期与数字格式化的结果不同。为确保网站在所有环境中输出一致建议在所有环境安装相同版本的intl扩展从而使用相同版本的 ICU。可以用下面的脚本查看当前 PHP 与 ICU 的版本?php echo PHP: . PHP_VERSION . \n; echo ICU: . INTL_ICU_VERSION . \n; echo ICU Data: . INTL_ICU_DATA_VERSION . \n;建议使用大于等于 48 的 ICU 版本这能保证本文描述的所有功能可用。例如ICU 49 之前的版本不支持复数规则中的#占位符。注意 ICU 在 4.8 之后改变了版本编号方式如 ICU 4.8、ICU 49、ICU 50……。此外ICU 库自带的时区数据库信息可能过时。虽然格式化使用的是 ICU 的时区数据库但 PHP 自带的时区数据也可能需要更新可以通过安装最新版的 pecltimezonedb包来更新。小结至此你已经掌握 Yii 2 国际化的完整脉络语言环境模型sourceLanguage源语言与language目标语言两个属性共同驱动整个翻译流程前者默认en-US翻译入口Yii::t()→i18n组件 → 消息源消息源支持 PHP 文件、Gettext 文件与数据库三种形态并通过通配符模式、fileMap与语言回退机制灵活组织格式化体系基于 ICU MessageFormat 的占位符系统覆盖了数字、货币、日期、时间、拼读、序数、时长、复数、序数选择与性别选择等场景MessageFormatter在缺少 intl 时提供有限降级工程化工具message命令config-template/config/extract负责从源码扫描并生成各语言译文文件环境要求建议统一安装 intl 扩展并使用 ICU ≥ 48以保证格式化行为在各环境一致。相关实现均可在此仓库中直接查阅I18N 组件、消息源基类、PHP 消息源、消息格式化器、message 命令以及框架自身使用的消息提取配置与内置多语言翻译。【免费下载链接】yii2Yii 2: The Fast, Secure and Professional PHP Framework项目地址: https://gitcode.com/gh_mirrors/yi/yii2创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表