PHPackages                             czukowski/i18n - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Localization &amp; i18n](/categories/localization)
4. /
5. czukowski/i18n

ActiveLibrary[Localization &amp; i18n](/categories/localization)

czukowski/i18n
==============

I18n package

1.0.0(10y ago)682.8k12MITPHPPHP &gt;=5.3.0

Since May 28Pushed 7y ago5 watchersCompare

[ Source](https://github.com/czukowski/I18n_Plural)[ Packagist](https://packagist.org/packages/czukowski/i18n)[ Docs](https://github.com/czukowski/I18n_Plural)[ RSS](/packages/czukowski-i18n/feed)WikiDiscussions master Synced 1mo ago

READMEChangelogDependenciesVersions (9)Used By (0)

Introduction
============

[](#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
====================

[](#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
-------

[](#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
-------

[](#example-1)

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
==================

[](#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
-------

[](#example-2)

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

[](#example-3)

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
==================

[](#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
========

[](#core-api)

### class I18n\\Core

[](#class-i18ncore)

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

[](#public-function-attachi18nreaderreaderinterface-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)

[](#public-function-translatestring-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)

[](#public-function-formstring-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)

[](#public-function-pluralstring-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)

[](#public-function-use_fallbackboolean--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

[](#interface-i18nreaderreaderinterface)

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)

[](#public-function-getstring-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

[](#interface-i18nreaderprefetchinterface)

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)

[](#public-function-prefetchlang--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

[](#class-i18nreaderprefetchingreader)

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)

[](#public-function-attachi18nreaderreaderinterface-reader-1)

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
=======

[](#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/

```

###  Health Score

36

—

LowBetter than 81% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity31

Limited adoption so far

Community16

Small or concentrated contributor base

Maturity63

Established project with proven stability

 Bus Factor1

Top contributor holds 98.8% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~756 days

Total

2

Last Release

3972d ago

Major Versions

0.1.0 → 1.0.02015-06-24

### Community

Maintainers

![](https://www.gravatar.com/avatar/3a53f9e84b8af6f4e617504c176bae99b56220f35bffba0a499c9db100a3b43f?d=identicon)[czukowski](/maintainers/czukowski)

---

Top Contributors

[![czukowski](https://avatars.githubusercontent.com/u/186792?v=4)](https://github.com/czukowski "czukowski (255 commits)")[![biakaveron](https://avatars.githubusercontent.com/u/95280?v=4)](https://github.com/biakaveron "biakaveron (2 commits)")[![johanlindblad](https://avatars.githubusercontent.com/u/508113?v=4)](https://github.com/johanlindblad "johanlindblad (1 commits)")

---

Tags

i18nlocalizationpluralsi18nplurals

### Embed Badge

![Health badge](/badges/czukowski-i18n/health.svg)

```
[![Health](https://phpackages.com/badges/czukowski-i18n/health.svg)](https://phpackages.com/packages/czukowski-i18n)
```

###  Alternatives

[symfony/string

Provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way

1.8k724.1M823](/packages/symfony-string)[symfony/intl

Provides access to the localization data of the ICU library

2.6k199.8M1.1k](/packages/symfony-intl)[gettext/gettext

PHP gettext manager

70530.2M101](/packages/gettext-gettext)[gettext/languages

gettext languages with plural rules

7530.3M10](/packages/gettext-languages)[inpsyde/multilingual-press

Simply THE multisite-based free open source plugin for your multilingual websites.

2414.0k1](/packages/inpsyde-multilingual-press)[coldtrick/translation_editor

Provide an easy way to edit translations

113.4k1](/packages/coldtrick-translation-editor)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
