Yii2如何强制使用备用MessageFormatter方法?
解决旧版ICU不支持显式Plural匹配的问题
我完全懂你的处境——服务器上的ICU版本(4.2.1)太老旧,不支持你用的=0、=1这种显式数字匹配的plural语法,又没法修改服务器配置。没关系,我们可以通过自定义工具来绕开这个限制,下面给你几个可行的方案:
方案1:写个简单的自定义格式化函数
这个方案最直接,手动解析你的plural模板,根据数字匹配对应的内容:
function customPluralFormatter($number, $pattern) { // 先把所有=数字{文本}的规则提取出来 preg_match_all('/=(\d+)\{([^}]+)\}/', $pattern, $matches); $exactRules = array_combine($matches[1], $matches[2]); // 提取默认的other分支内容 preg_match('/other\{([^}]+)\}/', $pattern, $otherMatch); $defaultText = isset($otherMatch[1]) ? $otherMatch[1] : ''; // 匹配对应的文本,没有匹配到就用默认分支 $targetText = isset($exactRules[(string)$number]) ? $exactRules[(string)$number] : $defaultText; // 把#替换成实际数字 return str_replace('#', $number, $targetText); } // 用起来很简单 echo customPluralFormatter(0, '{number,plural,=0{# available} =1{# available} other{# available}}'); // 输出 "0 available" echo customPluralFormatter(5, '{number,plural,=0{# available} =1{# available} other{# available}}'); // 输出 "5 available"
方案2:封装成类,贴近原生MessageFormatter用法
如果你习惯原生MessageFormatter的调用方式,可以封装一个兼容类,用法和原生几乎一样:
class CompatMessageFormatter { private $pattern; public function __construct($locale, $pattern) { // 这里暂时忽略locale,如果你需要多语言复数规则,可以后续扩展逻辑 $this->pattern = $pattern; } public function format($args) { $number = $args[0]; // 复用前面的解析逻辑 preg_match_all('/=(\d+)\{([^}]+)\}/', $this->pattern, $matches); $exactRules = array_combine($matches[1], $matches[2]); preg_match('/other\{([^}]+)\}/', $this->pattern, $otherMatch); $defaultText = isset($otherMatch[1]) ? $otherMatch[1] : ''; $targetText = isset($exactRules[(string)$number]) ? $exactRules[(string)$number] : $defaultText; return str_replace('#', $number, $targetText); } } // 调用方式和原生一致 $formatter = new CompatMessageFormatter('en_US', '{number,plural,=0{# available} =1{# available} other{# available}}'); echo $formatter->format([1]); // 输出 "1 available" echo $formatter->format([10]); // 输出 "10 available"
方案3:转换格式为旧版ICU支持的语法
如果你的plural规则刚好能对应旧版ICU支持的zero、one等复数类别(比如英语里one对应1,zero对应0),可以先把你的模板转换成旧版支持的格式,再用原生MessageFormatter:
function convertToOldIcuPattern($pattern) { // 把=0替换成zero,=1替换成one $pattern = str_replace('=0{', 'zero{', $pattern); $pattern = str_replace('=1{', 'one{', $pattern); return $pattern; } // 转换后用原生类处理 $oldCompatiblePattern = convertToOldIcuPattern('{number,plural,=0{# available} =1{# available} other{# available}}'); $formatter = new MessageFormatter('en_US', $oldCompatiblePattern); echo $formatter->format([0]); // 旧版ICU现在就能正常处理了
不过这个方案有局限性,只适用于你的数字匹配正好对应ICU标准复数类别的场景,如果是更复杂的数字规则(比如匹配=2、=3这种),还是前两个方案更靠谱。
内容的提问来源于stack exchange,提问作者TheStoryCoder
相关产品推荐
相关产品推荐

