I18n_Plural
文件大小: unknow
源码售价: 5 个金币 积分规则     积分充值
资源说明:I18n module for grammatically correct plural inflections, and maybe even some extra features related to i18n.
Introduction
============

This package will help you to do grammatically accurate translations in your application.

Branches for the following frameworks are available:

 * [3.3/master](https://github.com/czukowski/I18n_Plural/tree/3.3/master)
   for [Kohana Framework](http://kohanaframework.org/) with some extra features are available (there are also
   branches for older Kohana versions, although no more supported).
 * [nette/master](https://github.com/czukowski/I18n_Plural/tree/nette/master)
   for [Nette Framework](http://nette.org/en/)

For use with the other frameworks or on its own, there's some work to do as you'll need to implement the I18n
files reader(s). More on them below, following some ideas on what this might be good for.

Translation contexts
====================

Many languages use different words or inflections depending on a lot of circumstances, while it isn't much
problem in English, we can find an example there, too: suppose you want to display a string, that looks like
this: "His/her name is _name_" and you know the name of a person and his or her gender. Suppose you have
a function named `__()`, that does your translations and accepts optional arguments for parameters replacement.
Then the most trivial would be to do this:

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

Although you can probably see it's not flexible at all. This message doesn't have to begin with pronoun in
other languages. This is already better:

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

But what if there is a language, that changes other words as well? That's where the contextual translation
comes in handy. Consider just this:

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

For that to work, we have defined the translation key `Their name is :name` with 2 contexts - `f` and `m`:

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

Example
-------

	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

Example
-------

Some languages distinguish grammatical genders in way more situations, than just pronouns. Also, we can't
tell what grammatical gender a certain word is in different languages, as it may be quite random. Now we see,
that we can't always specify the required form, as we did with the given names. In this case, we can think
of a context in another way, a context can be just an object we want it to be related to.

Let's take Russian for an example, although many others will have similar translation structure as well.

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

Somewhere else:

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

Note the `other` key, that'll be used for any other context than `user` or `role`.

Plural inflections
==================

If you've ever been bothered by labels like "1 file(s)", there is a solution for you.

Nice people at CLDR have taken their time to compile plural rules for a large number of languages. This
module includes all these rules and a function, that converts any number into a proper context for that
language. The possible contexts are `zero`, `one`, `two`, `few`, `many` and `other`. Most languages will
only have 2-3 of these, and any of them will always have `other` context.

The rules are defined in [these classes](https://github.com/czukowski/I18n_Plural/tree/master/classes/I18n/Plural).
If you don't see your language immediately, try looking into One.php, Two.php and other generic names, they
aggregate a large number of languages, that share same rules. All the files include the rules in human
readable format and a list of languages they apply to.

It may be important to note, that the plural context must be numeric (`is_numeric` must return `TRUE` for that
value) in order to be tested against the language plural rules. Otherwise it'll look for the exact translation
key.

Example
-------

English:

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

Czech:

	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
		),
	);

*Note:* before doing something like I did above (I've replaced :count with actual 'one' value for the
context `one`), check with the language rules, whether that context really applies only when the number
is 1. There are languages out there, where this is not the case, for those languages, you'll have to leave
the parameter there.

Example
-------

English:

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

Russian:

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

In your code:

	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 лет

Note how the 2nd and 3rd translations differ between the languages. For English, it's the same form ('years
old'), while in Russian the translations are totally different.

Translation models
==================

The concept of the translation models is simple: you have a phrase that you need to translate using different
parameters, contexts and languages. This is fairly easy to achieve using the core translation function, but
models allow you to move this logic to a separate class or object.

Example, of course, with the correct inflections:

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

You may implement models by taking off from various levels:

  1. By just implementing `I18n\Model\ModelInterface` which only requires your class to be castable to string
     using `__toString()` function. This means you're in the full control of how your model will be working.
  2. By extending `I18n\Model\ModelBase` that has various getter/setter methods to maintain model states,
     you'll need to implement the `translate()` function where you'll place the translation logic.
  3. By extending or even using directly the `I18n\Model\ParameterModel` where you only define the
     `translate()` function arguments types and default values and then use it just as in the example above.
     All arguments are optional, those not passed to the function will default to model states and failing
     that to the arguments' default values. Using this method may make it easier for common translation cases,
     but will lack in flexibility for more complex phrases. For more detailed description, look into the class
     itself for the code comments.

Also note that there are few sample models under the tests folder.

Core API
========

### class I18n\Core

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

  * @param  I18n\Reader\ReaderInterface  $reader

This method takes a class instance that implements `I18n\Reader\ReaderInterface`. You'll implement your own
readers to provide translations from any source of your choice. If translations in your application come
from files, a `I18n\Reader\FileBasedReader` class may be used as a base for the implementation.

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

 * @param   string  $string   String to translate
 * @param   mixed   $context  String form or numeric count
 * @param   array   $values   Param values to insert
 * @param   string  $lang     Target language (optional)
 * @return  string

Translation/internationalization function with context support. The PHP function
[strtr](http://php.net/strtr) is used for replacing parameters.

	$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  String to translate
 * @param   string  $form    String context form, if NULL, looking for 'other' form, else the very first form
 * @param   string  $lang    Target language (optional)
 * @return  string

Returns specified form of a string translation. If no translation exists, the original string will be
returned. No parameters are replaced.

	$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  String to translate
 * @param   mixed   $count   Integer context form, 0 by default
 * @param   string  $lang    Target language (optional)
 * @return  string

Returns translation of a string. If no translation exists, the original string will be returned.
No parameters are replaced.

	$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|boolean

Switches the translation retrieval behavior to either request the translation from the readers with
or without fallback to less specific languages. For example, if translating from 'en-us' and the value
set to `TRUE`, the readers will be called up to 2 times: once for 'en-us' and once for 'en' in case the
former call did not return the translation. If the value set to `FALSE`, the readers will be called only
for 'en-us'.

If called without parameters, the current internal value is returned.

### interface I18n\Reader\ReaderInterface

The Reader must be able to return an associative array, if more than one translation option is available.
The 'other' key has a special meaning of a default translation.

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

 * @param   string   text to translate
 * @param   string   target language
 * @return  mixed

Returns translation of a string or array of translation options. No parameters are replaced. It is up
to the implementation where it gets it.

### interface I18n\Reader\PrefetchInterface

Readers that are able to load all the translations may implement this interface in order to use
translations loading optimization and caching.

#### public function prefetch($lang = NULL)

 * @param   string  $lang  Target language.
 * @return  array

Load and return all translations in the target language. At the very least an empty array
must be returned.

### class I18n\Reader\PrefetchingReader

This is a base 'wrapper' reader class that may contain multiple other readers which implement
`PrefetchInterface`. The intention is to merge the translations across all the readers into one
table (per lang code) and have a possibility to cache these tables.

This 'combined' reader is then to be attached to a Core object as a single reader.

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

Attach an i18n reader, same as you would to the Core object. The only difference is that the
reader must also implement `PrefetchInterface` in order to be able to load all translations for
a language at once.

Testing
=======

Although a golden rule says you aren't supposed to test the 3rd party code (that's its authors' responsibility),
you may run it using this command from module's root directory:

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

本源码包内暂不包含可直接显示的源代码文件,请下载源码包。