1.0.0 2015-06-24 05:58 UTC

README

此包可以帮助您在应用程序中进行语法准确的翻译。

以下框架的分支可用

用于其他框架或独立使用时,您需要实现 I18n 文件读取器。以下将详细介绍,并介绍一些可能的应用场景。

翻译上下文

许多语言根据很多情境使用不同的单词或变位形式,虽然这在英语中不是大问题,我们也可以找到一个例子:假设您要显示一个字符串,如下所示:“他的/她的名字是 name”,您知道一个人的名字和性别。假设您有一个名为 __() 的函数,它执行翻译并接受可选参数替换。那么最简单的方法是这样做

echo __($gender == 'f' ? 'His' : 'Her').__('name is :name', array(':name' => $name));

尽管您可能已经看到,这根本不灵活。这条消息在其他语言中不必以代词开头。这已经更好了

echo __(':their name is :name', array(':name' => $name, ':their' => __($gender == 'f' ? 'His' : 'Her')));

但如果有语言改变其他单词怎么办?这就是上下文翻译派上用场的时候。考虑以下内容

echo __('Their name is :name', $gender);

为了使其工作,我们定义了翻译键 Their name is :name,包含 2 个上下文 - fm

array(
	'Their name is :name' => array(
		'f' => 'Her name is :name',
		'm' => 'His name is :name',
	),
);

示例

foreach (array('aimee', 'bob') as $username)
{
	$person = ORM::factory('profile')->find($username);
	echo __('Their name is :name', $person->gender, array(':name' => $person->name));
}

// Outputs:
// Her name is Aimee
// His name is Bob

示例

一些语言在更多情况下区分语法性别,而不仅仅是代词。此外,我们无法确定不同语言中某个词的语法性别,因为它可能相当随机。现在我们看到了,我们无法总是指定所需的形式,就像我们处理给定名字时那样。在这种情况下,我们可以将上下文视为另一种方式,上下文可以是我们希望与之相关联的对象。

以俄语为例,尽管许多其他语言也将有类似的翻译结构。

array(
	'Enabled' => array(
		'user' => 'Включен',
		'role' => 'Включена',
		'other' => 'Включено',
	),
);

其他地方

echo __('Enabled', 'user');
// Включен

注意 other 键,它将用于除 userrole 之外的所有上下文。

复数变位

如果您曾因“1 个/些文件”这样的标签而烦恼,这里有一个解决方案。

CLDR 中的好人花了时间为大量语言编写复数规则。此模块包括所有这些规则和一个将任何数字转换为该语言适当上下文的函数。可能的上下文有 zeroonetwofewmanyother。大多数语言将只有 2-3 个这些,并且它们都会始终包含 other 上下文。

规则定义在这些类中:这些类。如果您立即看不到您的语言,请尝试查看One.php、Two.php和其他通用名称,它们聚合了大量的语言,它们共享相同的规则。所有文件都以可读格式包含规则以及它们应用的语种列表。

需要注意的是,复数上下文必须是数字的(对于该值,is_numeric必须返回TRUE),才能与语言复数规则进行测试。否则,它将寻找确切的翻译键。

示例

英语

array(
	'You have :count messages' => array(
		'one' => 'You have one message',        // 1 message
		'other' => 'You have :count messages',  // more messages
	),
);

捷克语

array(
	'You have :count messages' => array(
		'one' => 'Máte jednu zprávu',      // 1 message
		'few' => 'Máte :count zprávy',     // 2 - 4 messages
		'other' => 'Máte :count zpráv',    // more messages
	),
);

注意:在执行像上面那样的事情之前(我已经将上下文中的:count替换为实际的“one”值),请检查语言规则,看看该上下文是否仅在数字为1时适用。有些语言并非如此,对于这些语言,您必须保留该参数。

示例

英语

array(
	'Hi My Age Is'=> array(
		'one' => 'Hello world, I\'m :age year old',
		'other' => 'Hello world, I\'m :age years old',
	),
);

俄语

array(
	'Hi My Age Is' => array(
		'one' => 'Привет мир, мне уже :age год',
		'few' => 'Привет мир, мне уже :age года',
		'many' => 'Привет мир, мне уже :age лет',
		'other' => 'Привет мир, мне уже :age лет',
	),
);

在您的代码中

echo __('Hi My Age Is', 1, array(':age' => 1));
// Hello world, I\'m 1 year old
echo __('Hi My Age Is', 2, array(':age' => 2));
// Hello world, I\'m 2 years old
echo __('Hi My Age Is', 10, array(':age' => 10));
// Hello world, I\'m 10 years old

// Now suppose we've switched to another language

echo __('hello.myage', 1, array(':age' => 1));
// Привет мир, мне уже 1 год
echo __('hello.myage', 2, array(':age' => 2));
// Привет мир, мне уже 2 года
echo __('hello.myage', 10, array(':age' => 10));
// Привет мир, мне уже 10 лет

注意第2次和第3次翻译在语言之间的差异。对于英语,形式相同('years old'),而在俄语中,翻译完全不同。

翻译模型

翻译模型的概念很简单:您有一个需要使用不同的参数、上下文和语言进行翻译的短语。使用核心翻译函数可以轻松实现这一点,但模型允许您将此逻辑移动到单独的类或对象中。

当然,有正确的屈折变化示例

echo $filesInDirsCount->translate(123, 56, 'en');
// Found 123 files in 56 directories
echo $filesInDirsCount->translate(123, 56, 'ru');
// Найдено 123 файла в 56 папках

您可以从多个级别实现模型

  1. 只需实现I18n\Model\ModelInterface,该接口要求您的类可以由__toString()函数转换为字符串。这意味着您完全控制模型的工作方式。
  2. 通过扩展I18n\Model\ModelBase,该类具有各种getter/setter方法来维护模型状态,您需要在其中实现translate()函数,并将翻译逻辑放在那里。
  3. 通过扩展或直接使用I18n\Model\ParameterModel,您只需定义translate()函数的参数类型和默认值,然后就像上面的示例一样使用它。所有参数都是可选的,未传递给函数的参数将默认为模型状态,如果失败,则默认为参数的默认值。使用此方法可以更容易地处理常见的翻译情况,但对于更复杂的短语来说,将缺乏灵活性。有关更详细的说明,请查看类本身的代码注释。

请注意,在测试文件夹下有几个示例模型。

核心API

class I18n\Core

public function attach(I18n\Reader\ReaderInterface $reader)

  • @param I18n\Reader\ReaderInterface $reader

此方法接受一个实现I18n\Reader\ReaderInterface的类实例。您将实现自己的读取器,以从您选择的任何来源提供翻译。如果应用程序中的翻译来自文件,可以使用I18n\Reader\FileBasedReader类作为实现的基础。

public function translate($string, $context, $values, $lang = NULL)

  • @param string $string 要翻译的字符串
  • @param mixed $context 字符串形式或数值计数
  • @param array $values 要插入的参数值
  • @param string $lang 目标语言(可选)
  • @return string

支持上下文的翻译/国际化函数。使用PHP函数strtr替换参数。

$i18n->translate(':count user is online', 1000, array(':count' => 1000));
// 1000 users are online

public function form($string, $form = NULL, $lang = NULL)

  • @param string $string 要翻译的字符串
  • @param string $form 字符串上下文形式,如果为NULL,则查找'other'形式,否则查找第一个形式
  • @param string $lang 目标语言(可选)
  • @return string

返回字符串的指定形式翻译。如果没有翻译存在,则返回原始字符串。不替换任何参数。

$hello = $i18n->form('I\'ve met :name, he is my friend now.', 'fem');
// I've met :name, she is my friend now.

public function plural($string, $count = 0, $lang = NULL)

  • @param string $string 要翻译的字符串
  • @param mixed $count 整数上下文形式,默认为0
  • @param string $lang 目标语言(可选)
  • @return string

返回字符串的翻译。如果没有翻译存在,则返回原始字符串。不替换任何参数。

$hello = $i18n->plural('Hello, my name is :name and I have :count friend.', 10);
// 'Hello, my name is :name and I have :count friends.'

public function use_fallback($boolean = NULL)

  • @param boolean|NULL $boolean
  • @return $this|布尔值

切换翻译检索行为,可选择请求翻译时是否回退到更通用的语言。例如,如果从 'en-us' 翻译,且设置为 TRUE,则读者将被调用两次:一次为 'en-us',一次为 'en'(如果前一次调用没有返回翻译)。如果设置为 FALSE,则读者只调用 'en-us'。

如果没有参数调用,则返回当前内部值。

接口 I18n\Reader\ReaderInterface

如果提供了多个翻译选项,则Reader必须能够返回一个关联数组。'other' 键具有特殊含义,表示默认翻译。

public function get($string, $lang = NULL)

  • @param string 要翻译的文本
  • @param string 目标语言
  • @return mixed

返回字符串或翻译选项数组的翻译。参数不会被替换。具体实现细节取决于实现方式。

接口 I18n\Reader\PrefetchInterface

能够加载所有翻译的Reader可以实现此接口,以使用翻译加载优化和缓存。

public function prefetch($lang = NULL)

  • @param string $lang 目标语言。
  • @return array

加载并返回目标语言中的所有翻译。至少必须返回一个空数组。

类 I18n\Reader\PrefetchingReader

这是一个基本的 '包装' 读者类,可能包含多个其他实现 PrefetchInterface 的读者。目的是将所有读者的翻译合并到一个表中(每个语言代码一个表)并能够缓存这些表。

然后将此 '组合' 读者附加到Core对象作为单个读者。

public function attach(I18n\Reader\ReaderInterface $reader)

附加i18n读者,与附加到Core对象的方式相同。唯一的区别是,读者必须实现 PrefetchInterface 以一次加载一种语言的全部翻译。

测试

虽然有一条金律说不应该测试第三方代码(这是其作者的职责),但你可以在模块根目录中运行此命令。

phpunit --bootstrap tests/I18n/bootstrap.php tests/I18n/