{"id":16112353,"url":"https://github.com/loctools/plurr","last_synced_at":"2026-01-11T23:57:27.758Z","repository":{"id":3354205,"uuid":"4399478","full_name":"loctools/plurr","owner":"loctools","description":"Cross-platform format specification + libraries for handling plurals/genders/conditionals for Go, Java, JS, Obj-C, Perl, PHP, Python, and Rust","archived":false,"fork":false,"pushed_at":"2021-02-01T03:04:36.000Z","size":321,"stargazers_count":81,"open_issues_count":4,"forks_count":11,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-02-27T05:56:09.159Z","etag":null,"topics":["format","gender","go","golang","java","javascript","multi-language","named-placeholders","objective-c","perl","php","pluralization","plurals","plurr","python","rust"],"latest_commit_sha":null,"homepage":"","language":"Rust","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/loctools.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGES","contributing":null,"funding":null,"license":"MIT-LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2012-05-21T22:24:19.000Z","updated_at":"2024-05-23T13:36:22.000Z","dependencies_parsed_at":"2022-08-29T16:40:42.553Z","dependency_job_id":null,"html_url":"https://github.com/loctools/plurr","commit_stats":null,"previous_names":["iafan/plurr"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/loctools%2Fplurr","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/loctools%2Fplurr/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/loctools%2Fplurr/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/loctools%2Fplurr/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/loctools","download_url":"https://codeload.github.com/loctools/plurr/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243807357,"owners_count":20350989,"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","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":["format","gender","go","golang","java","javascript","multi-language","named-placeholders","objective-c","perl","php","pluralization","plurals","plurr","python","rust"],"created_at":"2024-10-09T20:07:09.836Z","updated_at":"2026-01-11T23:57:27.740Z","avatar_url":"https://github.com/loctools.png","language":"Rust","readme":"About Plurr\r\n===========\r\n\r\nHandling plurals, genders and conditionals in strings is not a particularly\r\nfavorite task for programmers for many reasons. There's no common agreement\r\non how to handle such variants, so all existing approaches are either\r\nplatform-specific (like gettext/po), or have limitations (for example you\r\ncan't have multiple plurals in one string), or not particularly translator-\r\nfriendly, like Java's MessageFormat/ChoiceFormat.\r\n\r\n**Plurr is a universal format specification for handling plurals, genders,\r\nconditionals and placeholders** designed to be easy to support for\r\ndevelopers and understandable for translators yet robust to support different\r\nlanguage requirements. Plurr formatters are implemented in:\r\n**Go, Java, JavaScript, Objective-C, Perl, PHP, Python, and Rust**. Feel free to\r\ncontribute to this project and provide support for your favorite languages.\r\n\r\n[Try the live demo \u0026rarr;](https://iafan.github.io/plurr-demo/)\r\n===============\r\n\r\nAdvantages\r\n----------\r\n\r\n 1. You can use Plurr with any L10N library of your choice: you can store and\r\n    read Plurr-formatted messages the same way as you do for any other strings.\r\n 2. Same string format across multiple languages means that strings can be\r\n    reused more effectively. This all reduces the time and cost of translation.\r\n 3. Named placeholders provide a great context for translators, and this means\r\n    better translation quality.\r\n 4. Named placeholders allow to change their order in the final string if this\r\n    is more appropriate for a particular target language.\r\n 5. Less programmatic string concatenation also helps understand the message as\r\n    a whole.\r\n\r\n### Syntax Example\r\n\r\n```elm\r\nDo you want to delete {N_PLURAL:this {N} file|these {N} files} permanently?\r\n```\r\n\r\nWhich, depending on the provided `N` value, will render as (for English):\r\n\r\n  * N = 1, N_PLURAL = 0: `Do you want to delete this 1 file permanently?`\r\n  * N = 5, N_PLURAL = 1: `Do you want to delete these 5 files permanently?`\r\n\r\nThe value of N_PLURAL is determined by calling a plural() function with the\r\nvalue of N, and is language-dependent. By default, plurals are calculated\r\nautomatically: when `FOO_PLURAL` placeholder is found and its value is not\r\nprovided to the formatting function, Plurr will try to do\r\n`FOO_PLURAL = plurals(FOO)` internally, taking into consideration the current\r\nlocale defined for the Plurr object. Below is a sample JavaScript code:\r\n\r\n```javascript\r\nvar p = new Plurr();  // create a Plurr object (once). Default locale is English\r\n...\r\nalert(p.format(\r\n  \"Do you want to delete {N_PLURAL:this {N} file|these {N} files} permanently?\",  // message\r\n  {'N': 5}  // parameters\r\n));\r\n```\r\n\r\nThe syntax itself is not something new, it is similar to the one used in the\r\nalready mentioned Java's MessageFormat, but it is minimalistic and contains no\r\nsensitive words that translators can inadvertently change (and break).\r\n\r\nFormat specification\r\n--------------------\r\n\r\n### 1. Simple named placeholders\r\n\r\n#### Format\r\n\r\n```elm\r\n{NAME}\r\n```\r\n\r\n#### Example\r\n\r\n```elm\r\n{FOO} and {BAR}\r\n```\r\n\r\nHere `{FOO}` will be substituted with the provided FOO value, and `{BAR}` —\r\nwith the value of BAR.\r\n\r\n\r\nRecommended is the use of capital `A..Z` and `_` symbol — this makes\r\nplaceholders stand out in the text, which gives some additional clue to\r\ntranslators that these sequences are something special and should not be\r\ntranslated.\r\n\r\nThere are no restrictions on placeholder names, except that they must not\r\ncontain `}` or `:` symbol.\r\n\r\nWhen you need to represent symbols `{` or `}` themselves in the final string,\r\nreplace them with named placeholders with corresponding values, for example:\r\n\r\n```javascript\r\nalert(p.format(\r\n  \"I love {\u003c}curly{\u003e} braces.\",\r\n  {\r\n    '\u003c': '{',\r\n    '\u003e': '}'\r\n  }\r\n));\r\n```\r\n\r\n### 2. Placeholders with alternatives\r\n\r\n```elm\r\n{CHOICE:FORM0[|FORM1][|FORM2][|FORM3][|...]}\r\n```\r\n\r\nwhere:\r\n\r\n  * `CHOICE` is a zero or a positive integer.\r\n  * `FORM0`, `FORM1` and so on are the alternative versions of the string for\r\n    each value of CHOICE (starting from 0).\r\n\r\nIf less forms are provided than the value of `CHOICE`, the last form is used.\r\n\r\nAs `|` is used to delimit different alternatives, in order to display such\r\nsymbol in the final string, replace it with named placeholder with the\r\ncorresponding value (same as for `{` and `}` in the section above).\r\n\r\n#### Example in English:\r\n\r\n```elm\r\n{N_PLURAL:{N} file|{N} files}\r\n```\r\n\r\nwill render as:\r\n\r\n  * N = 0, N_PLURAL = 1: `0 files`\r\n  * N = 1, N_PLURAL = 0: `1 file`\r\n  * N = 2, N_PLURAL = 1: `2 files`\r\n  * N = 5, N_PLURAL = 1: `5 files`\r\n\r\n#### Example of the same string translated into Russian:\r\n\r\n```elm\r\n{N_PLURAL:{N} файл|{N} файла|{N} файлов}\r\n```\r\n\r\nwill render as:\r\n\r\n  * N = 0, N_PLURAL = 2: `0 файлов`\r\n  * N = 1, N_PLURAL = 0: `1 файл`\r\n  * N = 2, N_PLURAL = 1: `2 файла`\r\n  * N = 5, N_PLURAL = 2: `5 файлов`\r\n\r\n### 3. Multiple placeholders in the same string\r\n\r\nInside a string, there can be multiple placeholders of any kind.\r\n\r\n#### Example:\r\n\r\n```elm\r\n{X_PLURAL:{X} file|{X} files} found in {Y_PLURAL:{Y} folder|{Y} folders}.\r\nDo you want to {COMMAND:copy|move|delete} {X:them|it|them}?\r\n```\r\n\r\nHere, in addition to handling plurals, we use a value of `COMMAND` placeholder\r\nto display different verbs.\r\n\r\n#### Same example in Russian:\r\n\r\n```elm\r\nВ {Y_PLURAL:{Y} папке|{Y} папках|{Y} папках} {X_PLURAL:найден {X} файл|найдены {X} файла|найдено {X} файлов}.\r\nХотите {X:его|их} {COMMAND:скопировать|переместить|удалить}?\r\n```\r\n\r\n### 4. Handling genders\r\n\r\nHandling genders is the same as handling any other type of placeholders. You\r\njust need to provide a parameter (let's name it `GENDER`), which evaluates to,\r\nsay, `0` for male, `1` for female, and `2` in case the gender is unknown (the\r\nway you number genders is purely arbitrary, but we recommend sticking to some\r\nscheme that you use consistently across your application). Then all you need to\r\ndo is to construct a message like this:\r\n\r\n```elm\r\nDo you want to leave {GENDER:him|her|them} a message?\r\n{GENDER:He|She|They} will see it when {GENDER:he|she|they} {GENDER:logs|logs|log} in.\r\n```\r\n\r\n### 5. Nested placeholders and special cases\r\n\r\nSometimes one would like to say \"One file\" instead of \"1 file\", and \"No files\"\r\ninstead of \"0 files\". That's (and other scenarios) are possible with nested\r\nplaceholders:\r\n\r\n```elm\r\n{X:No files|One file|{X} {X_PLURAL:file|files}} found.\r\n```\r\n\r\nHere we first make a choice based on the value of `X`, where for values `0` and `1` we render\r\nspecial messages, and for values `2` and above we render the nested plural-aware placeholder.\r\n\r\n#### Same example in Russian:\r\n\r\n```elm\r\n{X:Не найдено файлов|Найден один файл|{X_PLURAL:Найден {X} файл|Найдено {X} файла|Найдено {X} файлов|}}.\r\n```\r\n\r\nSuch an approach allows translators to provide most natural translation\r\npossible, and gives some peace of mind to developers helping them reduce the\r\namount of supporting `if...else` code in their applications.\r\n\r\nSyntax Highlighting\r\n-------------------\r\n\r\nPlurr also has a [syntax highlighter](https://github.com/iafan/Plurr/tree/master/demo/js/codemirror/mode/plurr)\r\navailable for [CodeMirror](http://codemirror.net/), which is a part of the live demo.\r\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Floctools%2Fplurr","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Floctools%2Fplurr","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Floctools%2Fplurr/lists"}