【问题标题】:Storing string templates存储字符串模板
【发布时间】:2016-03-31 22:04:01
【问题描述】:

模板字符串。

此链接可能会有所帮助: Does PHP have a feature like Python's template strings?

我的主要问题是,是知道是否有更好的方法来存储文本字符串。

现在,这通常是通过一个文件夹 (DIR)大量具有不同字符串的单个独立文件 完成的,并且取决于可能需要什么,获取一个文件的内容,处理并将 {tags} 替换为 values

或者,将它们全部定义在单个文件数组[]中更好吗?

greetings.tpl.txt

['welcome'] = 'Welcome {firstname} {lastname}'.
['good_morning'] = 'Good morning {firstname}'.
['good_afternoon'] = 'Good afternoon {firstname}'.

这是另一个例子,https://github.com/oren/string-template-example/blob/master/template.txt

提前谢谢!

包含解决方案的答案,说明应该使用 include("../file.php");这里绝不接受。显示如何将已定义字符串的 LIST 读入数组的解决方案。该定义已经基于数组。

【问题讨论】:

  • 大声思考,像往常一样,这取决于?不管怎样,您可以在PHP 中使用与在“Python”中相同的数据存储技术。因此,只需复制您在 Python 中的存储操作即可。计时。我怀疑它会是simila?你也很熟悉吗?另一种方法是像twigcaching 这样编译的东西。哪些可能值得做“长期”?
  • 我认为,PHP 中的东西与 Python 有点不同。我仍然担心的是,将这些存储起来以便在需要时进行处理,例如加载对象时。
  • 直到你计时你才会知道?说真的,做你习惯的事情并尝试一下。如果客户满意,那么您就完成了。您可以随时切换到“缓存”方法 - 如果需要,稍后再切换。如果没有时间,那只是猜测。即,您不知道任何一个网络事务实际使用了多少 templates。可能是正常的一小部分。为什么要加载你不需要的东西。添加像redis 这样的cache 并不困难,并且会显着加快速度。但是以后再做吗?

标签: php


【解决方案1】:

好的,约翰,我会详细说明。

最好的方法是为每种语言创建一个 php 文件,其中包含文本数组的定义,使用 printf 格式进行字符串替换。 如果文本量非常大,您可以考虑进一步对其进行分区。 (通常几 MB 就可以了)

这在生产中是有效的,假设操作系统有一个经过良好调整的文件现金。更重要的是,您使用数组的数字索引。

让 php 填充数组,然后自己做,读取文本文件会更有效。这毕竟是,我假设,静态文本? 如果生产性能不是问题,请忽略此帖。

greetings_tpl_en.php

$text_tpl={
   'welcome' => 'Welcome %s %s'
  ,'good_morning' => 'Good morning %s'
  ,'good_afternoon' => 'Good afternoon %s'
};

你的.php

$language="en";
require('greetings_tpl_'. $language .'php');
....
printf($text_tpl['welcome'],$first_name,$last_name);

printf 我是 C 语言的一个很好的遗产。 sprintf 返回一个字符串而不是输出它。

您可以在此处找到 php printf 格式的完整说明:http://php.net/manual/en/function.sprintf.php

(当这个问题解决后,请再次阅读 Josef Kufner 的帖子。+1 :c)

希望这有帮助吗?

【讨论】:

  • 如何打开文件而不是 require('...'); ?
  • 只有性能问题。这对你很重要吗?当使用 require/include 并从 php 代码中填充数组时,您可以利用已编译的 php 引擎来完成这项工作。如果您在 php 中处理文本,则会在解释器中完成。对于系统来说,这是一项更繁重的工作,更难兑现。因此,这取决于您对速度的需求与您喜欢编码的方式:c)您对包含的关注是什么?
  • 好像很不专业,我就是有这种感觉,也许我完全错了。
  • 是的 :c) 对我来说,专业就是选择问题的最佳解决方案。如果它是一个 C 程序,我会完全同意。但是与大多数网络编程一样,您必须使用生锈的水桶,让它像地狱一样运行:c)但是请在您的代码中添加 cmets 来解释您的自我!我会 - 而且我经常需要自己稍后阅读它们:c)
【解决方案2】:

您可以将所有模板以及用于替换占位符的变量存储在一个关联数组中,例如

$capt=array('welcome' => 'Welcome {firstname} {lastname}',
            'good_morning' => 'Good morning {firstname}',
            'good_afternoon' => 'Good afternoon {firstname}');

$vars=array('firstname'=>'Harry','lastname'=>'Potter', 'profession'=>'wizzard');

然后,您可以通过简单的preg_replace_callback 调用来转换句子

function repl($a){ global $vars;  
  return $vars[$a[1]];
}
function getcapt($type){ global $capt; 
  $str=$capt[$type];
  $str=preg_replace_callback('/\{([^}]+)\}/','repl' ,$str);
  echo "$str<br>";                      
}
getcapt('welcome');
getcapt('good_afternoon');

这个例子会产生

Welcome Harry Potter
Good afternoon Harry

【讨论】:

  • 我已经有了处理标签并将其替换为值的代码,所以我最初关心的不是代码本身,我的问题仍然是字符串存储。例如,有活动提要,通常包含预定义的字符串文本,并且标签被替换为值,这是一个示例:raw.githubusercontent.com/caseyscarborough/github-activity/…
【解决方案3】:

首先,看看gettext。它被广泛使用,并且有很多工具可以处理翻译过程,例如 xgettext 和POEdit。在源代码中使用真正的英文字符串,然后使用 xgettext 工具提取它们会更舒服。 Gettext 可以处理几乎所有语言的复数形式,这在使用简单的字符串数组时是不可能的。

与gettext结合的非常有用的函数是sprintf()(或者printf(),如果你想直接输出文本)。

例子:

printf(gettext('Welcome %s %s.'), $firstname, $lastname);
printf(ngettext('You have %d new message.', 'You have %d new messages.',
    $number_of_new_messages), $number_of_new_messages);

然后,当您想将其翻译成姓通常在名字之前的语言时,您可以使用:'Welcome %2$s, %1$s.'

第二个例子,复数形式,可以使用两个以上的字符串进行翻译,因为本地化文件的一部分是复数形式的排列方式。而英语是nplurals=2; plural=(n != 1);,例如在捷克语中是nplurals=3; plural=(n==1) ? 0 : (n&gt;=2 &amp;&amp; n&lt;=4) ? 1 : 2;(三种形式,第一种是一个项目,第二个是2到4个项目,第三个是其余的)。例如爱尔兰语has five plural forms

要从源代码中提取字符串,请使用xgettext -L php ...。我建议使用适合您项目的确切命令编写简短的脚本,例如:

# assuming this file is in locales directory
# and source code in src directory
find ../src -type f -iname '*.php' > "files.list"
xgettext -L php --from-code 'UTF-8' -f "files.list" -o messages.pot

您可能希望使用 -k 参数添加自定义函数名称。

【讨论】:

  • 我知道gettext。目前,对它不感兴趣。目前,这与翻译关系不大。
【解决方案4】:

要向模板添加值,您可以使用strtr。下面的例子:

$msg = strtr('Welcome {firstname} {lastname}', array(
    '{firstname}' => $user->getFistName(),
    '{lastname}' => $user->getLastName()
));

关于存储字符串,您可以为每种语言保存一个数组,然后只加载相关的一个。例如。您将拥有一个包含 2 个文件的目录:

  • 语言
    • zh.php
    • de.php

每个文件应包含以下内容:

<?php

return (object) array(
    'WELCOME' => 'Welcome {firstname} {lastname}'
);

当您需要翻译时,您只需执行以下操作:

$dictionary = include('language/en.php');

然后字典就会有一个你可以寻址的对象。改变上面的例子,它会是这样的:

$dic = include('language/en.php');
$msg = strtr($dic->WELCOME, array(
    '{firstname}' => $user->getFistName(),
    '{lastname}' => $user->getLastName()
));

为避免字典中没有模板的情况,可以使用带默认文本的三元运算符:

$dic = include('language/en.php');
$tpl = $dic->WELCOME ?: 'Welcome {firstname} {lastname}';
$msg = strtr($tpl, array(
    '{firstname}' => $user->getFistName(),
    '{lastname}' => $user->getLastName()
));

人们通常会做什么来编辑数据库中的文本,您可以使用简单的导出(例如var_export)脚本从数据库同步到文件。

希望这会有所帮助。

【讨论】:

  • 非常感谢您的回复。我仍然质疑这一点,真的是这样吗?甚至做大型网站,例如Twitter、Instagram 等也这样做?
  • 在 50 万用户群中,每天大约有 40K 的页面浏览量(每个页面浏览量都会加载字典)。最高的负载是大约 150K 的页面浏览量,并且字典没有问题,即使我们在 3 台服务器上使用 NFS。
  • 我们有 5 种语言,所以有 5 个文件。它是我们本地化系统的一部分。不,我们没有提要,但这有什么关系?
  • 这是一个有效的解决方案。它只加载相关的语言。通常在操作系统上有一个有效的文件追踪,它会处理最常用的文件并将它们保存在内存中。此解决方案适用于这种行为。
  • 我个人更喜欢使用 printf 格式,而不是发明字符串替换。
猜你喜欢
  • 2011-07-13
  • 1970-01-01
  • 1970-01-01
  • 2016-11-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-19
  • 2011-09-08
相关资源
最近更新 更多