{"id":21722696,"url":"https://github.com/czukowski/i18n_plural","last_synced_at":"2025-09-07T20:46:20.149Z","repository":{"id":56961016,"uuid":"924484","full_name":"czukowski/I18n_Plural","owner":"czukowski","description":"I18n module for grammatically correct plural inflections, and maybe even some extra features related to i18n.","archived":false,"fork":false,"pushed_at":"2018-12-11T09:55:31.000Z","size":527,"stargazers_count":68,"open_issues_count":0,"forks_count":12,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-08-07T09:43:13.293Z","etag":null,"topics":["i18n","localization","plurals"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/czukowski.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2010-09-20T09:49:07.000Z","updated_at":"2022-12-27T22:41:51.000Z","dependencies_parsed_at":"2022-08-21T05:10:19.552Z","dependency_job_id":null,"html_url":"https://github.com/czukowski/I18n_Plural","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/czukowski/I18n_Plural","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/czukowski%2FI18n_Plural","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/czukowski%2FI18n_Plural/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/czukowski%2FI18n_Plural/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/czukowski%2FI18n_Plural/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/czukowski","download_url":"https://codeload.github.com/czukowski/I18n_Plural/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/czukowski%2FI18n_Plural/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":274094706,"owners_count":25221424,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-07T02:00:09.463Z","response_time":67,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["i18n","localization","plurals"],"created_at":"2024-11-26T02:32:02.006Z","updated_at":"2025-09-07T20:46:20.127Z","avatar_url":"https://github.com/czukowski.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"Introduction\n============\n\nThis package will help you to do grammatically accurate translations in your application.\n\nBranches for the following frameworks are available:\n\n * [3.3/master](https://github.com/czukowski/I18n_Plural/tree/3.3/master)\n   for [Kohana Framework](http://kohanaframework.org/) with some extra features are available (there are also\n   branches for older Kohana versions, although no more supported).\n * [nette/master](https://github.com/czukowski/I18n_Plural/tree/nette/master)\n   for [Nette Framework](http://nette.org/en/)\n\nFor use with the other frameworks or on its own, there's some work to do as you'll need to implement the I18n\nfiles reader(s). More on them below, following some ideas on what this might be good for.\n\nTranslation contexts\n====================\n\nMany languages use different words or inflections depending on a lot of circumstances, while it isn't much\nproblem in English, we can find an example there, too: suppose you want to display a string, that looks like\nthis: \"His/her name is _name_\" and you know the name of a person and his or her gender. Suppose you have\na function named `__()`, that does your translations and accepts optional arguments for parameters replacement.\nThen the most trivial would be to do this:\n\n\techo __($gender == 'f' ? 'His' : 'Her').__('name is :name', array(':name' =\u003e $name));\n\nAlthough you can probably see it's not flexible at all. This message doesn't have to begin with pronoun in\nother languages. This is already better:\n\n\techo __(':their name is :name', array(':name' =\u003e $name, ':their' =\u003e __($gender == 'f' ? 'His' : 'Her')));\n\nBut what if there is a language, that changes other words as well? That's where the contextual translation\ncomes in handy. Consider just this:\n\n\techo __('Their name is :name', $gender);\n\nFor that to work, we have defined the translation key `Their name is :name` with 2 contexts - `f` and `m`:\n\n\tarray(\n\t\t'Their name is :name' =\u003e array(\n\t\t\t'f' =\u003e 'Her name is :name',\n\t\t\t'm' =\u003e 'His name is :name',\n\t\t),\n\t);\n\nExample\n-------\n\n\tforeach (array('aimee', 'bob') as $username)\n\t{\n\t\t$person = ORM::factory('profile')-\u003efind($username);\n\t\techo __('Their name is :name', $person-\u003egender, array(':name' =\u003e $person-\u003ename));\n\t}\n\n\t// Outputs:\n\t// Her name is Aimee\n\t// His name is Bob\n\nExample\n-------\n\nSome languages distinguish grammatical genders in way more situations, than just pronouns. Also, we can't\ntell what grammatical gender a certain word is in different languages, as it may be quite random. Now we see,\nthat we can't always specify the required form, as we did with the given names. In this case, we can think\nof a context in another way, a context can be just an object we want it to be related to.\n\nLet's take Russian for an example, although many others will have similar translation structure as well.\n\n\tarray(\n\t\t'Enabled' =\u003e array(\n\t\t\t'user' =\u003e 'Включен',\n\t\t\t'role' =\u003e 'Включена',\n\t\t\t'other' =\u003e 'Включено',\n\t\t),\n\t);\n\nSomewhere else:\n\n\techo __('Enabled', 'user');\n\t// Включен\n\nNote the `other` key, that'll be used for any other context than `user` or `role`.\n\nPlural inflections\n==================\n\nIf you've ever been bothered by labels like \"1 file(s)\", there is a solution for you.\n\nNice people at CLDR have taken their time to compile plural rules for a large number of languages. This\nmodule includes all these rules and a function, that converts any number into a proper context for that\nlanguage. The possible contexts are `zero`, `one`, `two`, `few`, `many` and `other`. Most languages will\nonly have 2-3 of these, and any of them will always have `other` context.\n\nThe rules are defined in [these classes](https://github.com/czukowski/I18n_Plural/tree/master/classes/I18n/Plural).\nIf you don't see your language immediately, try looking into One.php, Two.php and other generic names, they\naggregate a large number of languages, that share same rules. All the files include the rules in human\nreadable format and a list of languages they apply to.\n\nIt may be important to note, that the plural context must be numeric (`is_numeric` must return `TRUE` for that\nvalue) in order to be tested against the language plural rules. Otherwise it'll look for the exact translation\nkey.\n\nExample\n-------\n\nEnglish:\n\n\tarray(\n\t\t'You have :count messages' =\u003e array(\n\t\t\t'one' =\u003e 'You have one message',        // 1 message\n\t\t\t'other' =\u003e 'You have :count messages',  // more messages\n\t\t),\n\t);\n\nCzech:\n\n\tarray(\n\t\t'You have :count messages' =\u003e array(\n\t\t\t'one' =\u003e 'Máte jednu zprávu',      // 1 message\n\t\t\t'few' =\u003e 'Máte :count zprávy',     // 2 - 4 messages\n\t\t\t'other' =\u003e 'Máte :count zpráv',    // more messages\n\t\t),\n\t);\n\n*Note:* before doing something like I did above (I've replaced :count with actual 'one' value for the\ncontext `one`), check with the language rules, whether that context really applies only when the number\nis 1. There are languages out there, where this is not the case, for those languages, you'll have to leave\nthe parameter there.\n\nExample\n-------\n\nEnglish:\n\n\tarray(\n\t\t'Hi My Age Is'=\u003e array(\n\t\t\t'one' =\u003e 'Hello world, I\\'m :age year old',\n\t\t\t'other' =\u003e 'Hello world, I\\'m :age years old',\n\t\t),\n\t);\n\nRussian:\n\n\tarray(\n\t\t'Hi My Age Is' =\u003e array(\n\t\t\t'one' =\u003e 'Привет мир, мне уже :age год',\n\t\t\t'few' =\u003e 'Привет мир, мне уже :age года',\n\t\t\t'many' =\u003e 'Привет мир, мне уже :age лет',\n\t\t\t'other' =\u003e 'Привет мир, мне уже :age лет',\n\t\t),\n\t);\n\nIn your code:\n\n\techo __('Hi My Age Is', 1, array(':age' =\u003e 1));\n\t// Hello world, I\\'m 1 year old\n\techo __('Hi My Age Is', 2, array(':age' =\u003e 2));\n\t// Hello world, I\\'m 2 years old\n\techo __('Hi My Age Is', 10, array(':age' =\u003e 10));\n\t// Hello world, I\\'m 10 years old\n\t\n\t// Now suppose we've switched to another language\n\t\n\techo __('hello.myage', 1, array(':age' =\u003e 1));\n\t// Привет мир, мне уже 1 год\n\techo __('hello.myage', 2, array(':age' =\u003e 2));\n\t// Привет мир, мне уже 2 года\n\techo __('hello.myage', 10, array(':age' =\u003e 10));\n\t// Привет мир, мне уже 10 лет\n\nNote how the 2nd and 3rd translations differ between the languages. For English, it's the same form ('years\nold'), while in Russian the translations are totally different.\n\nTranslation models\n==================\n\nThe concept of the translation models is simple: you have a phrase that you need to translate using different\nparameters, contexts and languages. This is fairly easy to achieve using the core translation function, but\nmodels allow you to move this logic to a separate class or object.\n\nExample, of course, with the correct inflections:\n\n\techo $filesInDirsCount-\u003etranslate(123, 56, 'en');\n\t// Found 123 files in 56 directories\n\techo $filesInDirsCount-\u003etranslate(123, 56, 'ru');\n\t// Найдено 123 файла в 56 папках\n\nYou may implement models by taking off from various levels:\n\n  1. By just implementing `I18n\\Model\\ModelInterface` which only requires your class to be castable to string\n     using `__toString()` function. This means you're in the full control of how your model will be working.\n  2. By extending `I18n\\Model\\ModelBase` that has various getter/setter methods to maintain model states,\n     you'll need to implement the `translate()` function where you'll place the translation logic.\n  3. By extending or even using directly the `I18n\\Model\\ParameterModel` where you only define the\n     `translate()` function arguments types and default values and then use it just as in the example above.\n     All arguments are optional, those not passed to the function will default to model states and failing\n     that to the arguments' default values. Using this method may make it easier for common translation cases,\n     but will lack in flexibility for more complex phrases. For more detailed description, look into the class\n     itself for the code comments.\n\nAlso note that there are few sample models under the tests folder.\n\nCore API\n========\n\n### class I18n\\Core\n\n#### public function attach(I18n\\Reader\\ReaderInterface $reader)\n\n  * @param  I18n\\Reader\\ReaderInterface  $reader\n\nThis method takes a class instance that implements `I18n\\Reader\\ReaderInterface`. You'll implement your own\nreaders to provide translations from any source of your choice. If translations in your application come\nfrom files, a `I18n\\Reader\\FileBasedReader` class may be used as a base for the implementation.\n\n#### public function translate($string, $context, $values, $lang = NULL)\n\n * @param   string  $string   String to translate\n * @param   mixed   $context  String form or numeric count\n * @param   array   $values   Param values to insert\n * @param   string  $lang     Target language (optional)\n * @return  string\n\nTranslation/internationalization function with context support. The PHP function\n[strtr](http://php.net/strtr) is used for replacing parameters.\n\n\t$i18n-\u003etranslate(':count user is online', 1000, array(':count' =\u003e 1000));\n\t// 1000 users are online\n\n#### public function form($string, $form = NULL, $lang = NULL)\n\n * @param   string  $string  String to translate\n * @param   string  $form    String context form, if NULL, looking for 'other' form, else the very first form\n * @param   string  $lang    Target language (optional)\n * @return  string\n\nReturns specified form of a string translation. If no translation exists, the original string will be\nreturned. No parameters are replaced.\n\n\t$hello = $i18n-\u003eform('I\\'ve met :name, he is my friend now.', 'fem');\n\t// I've met :name, she is my friend now.\n\n#### public function plural($string, $count = 0, $lang = NULL)\n\n * @param   string  $string  String to translate\n * @param   mixed   $count   Integer context form, 0 by default\n * @param   string  $lang    Target language (optional)\n * @return  string\n\nReturns translation of a string. If no translation exists, the original string will be returned.\nNo parameters are replaced.\n\n\t$hello = $i18n-\u003eplural('Hello, my name is :name and I have :count friend.', 10);\n\t// 'Hello, my name is :name and I have :count friends.'\n\n#### public function use_fallback($boolean = NULL)\n\n * @param   boolean|NULL  $boolean\n * @return  $this|boolean\n\nSwitches the translation retrieval behavior to either request the translation from the readers with\nor without fallback to less specific languages. For example, if translating from 'en-us' and the value\nset to `TRUE`, the readers will be called up to 2 times: once for 'en-us' and once for 'en' in case the\nformer call did not return the translation. If the value set to `FALSE`, the readers will be called only\nfor 'en-us'.\n\nIf called without parameters, the current internal value is returned.\n\n### interface I18n\\Reader\\ReaderInterface\n\nThe Reader must be able to return an associative array, if more than one translation option is available.\nThe 'other' key has a special meaning of a default translation.\n\n#### public function get($string, $lang = NULL)\n\n * @param   string   text to translate\n * @param   string   target language\n * @return  mixed\n\nReturns translation of a string or array of translation options. No parameters are replaced. It is up\nto the implementation where it gets it.\n\n### interface I18n\\Reader\\PrefetchInterface\n\nReaders that are able to load all the translations may implement this interface in order to use\ntranslations loading optimization and caching.\n\n#### public function prefetch($lang = NULL)\n\n * @param   string  $lang  Target language.\n * @return  array\n\nLoad and return all translations in the target language. At the very least an empty array\nmust be returned.\n\n### class I18n\\Reader\\PrefetchingReader\n\nThis is a base 'wrapper' reader class that may contain multiple other readers which implement\n`PrefetchInterface`. The intention is to merge the translations across all the readers into one\ntable (per lang code) and have a possibility to cache these tables.\n\nThis 'combined' reader is then to be attached to a Core object as a single reader.\n\n#### public function attach(I18n\\Reader\\ReaderInterface $reader)\n\nAttach an i18n reader, same as you would to the Core object. The only difference is that the\nreader must also implement `PrefetchInterface` in order to be able to load all translations for\na language at once.\n\nTesting\n=======\n\nAlthough a golden rule says you aren't supposed to test the 3rd party code (that's its authors' responsibility),\nyou may run it using this command from module's root directory:\n\n\tphpunit --bootstrap tests/I18n/bootstrap.php tests/I18n/\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fczukowski%2Fi18n_plural","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fczukowski%2Fi18n_plural","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fczukowski%2Fi18n_plural/lists"}