{"id":13808714,"url":"https://github.com/catamphetamine/relative-time-format","last_synced_at":"2025-04-06T06:14:28.648Z","repository":{"id":57352688,"uuid":"165441899","full_name":"catamphetamine/relative-time-format","owner":"catamphetamine","description":"A convenient `Intl.RelativeTimeFormat` polyfill","archived":false,"fork":false,"pushed_at":"2022-12-04T14:59:33.000Z","size":1923,"stargazers_count":62,"open_issues_count":0,"forks_count":6,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-04-01T00:02:15.700Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://catamphetamine.github.io/relative-time-format/","language":"JavaScript","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/catamphetamine.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-01-12T22:25:01.000Z","updated_at":"2024-03-29T21:37:03.000Z","dependencies_parsed_at":"2023-01-23T09:30:25.750Z","dependency_job_id":null,"html_url":"https://github.com/catamphetamine/relative-time-format","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/catamphetamine%2Frelative-time-format","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/catamphetamine%2Frelative-time-format/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/catamphetamine%2Frelative-time-format/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/catamphetamine%2Frelative-time-format/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/catamphetamine","download_url":"https://codeload.github.com/catamphetamine/relative-time-format/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247441063,"owners_count":20939239,"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":[],"created_at":"2024-08-04T01:01:50.087Z","updated_at":"2025-04-06T06:14:28.625Z","avatar_url":"https://github.com/catamphetamine.png","language":"JavaScript","funding_links":[],"categories":["JavaScript"],"sub_categories":[],"readme":"# relative-time-format\n\n[![npm version](https://img.shields.io/npm/v/relative-time-format.svg?style=flat-square)](https://www.npmjs.com/package/relative-time-format)\n[![npm downloads](https://img.shields.io/npm/dm/relative-time-format.svg?style=flat-square)](https://www.npmjs.com/package/relative-time-format)\n[![npm size](https://img.shields.io/bundlephobia/minzip/relative-time-format.svg?label=size)](https://www.npmjs.com/package/relative-time-format)\n[![coverage](https://img.shields.io/coveralls/catamphetamine/relative-time-format/master.svg?style=flat-square)](https://coveralls.io/r/catamphetamine/relative-time-format?branch=master)\n\nThis library consists of three parts:\n\n* A convenient [`Intl.RelativeTimeFormat`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RelativeTimeFormat) polyfill. No dependencies (doesn't require [`Intl.PluralRules`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/PluralRules) because it's already [built in](https://github.com/catamphetamine/relative-time-format/blob/master/source/PluralRuleFunctions.js)).\n\n* A high-level relative time formatting library.\n\n* A React component for relative time formatting.\n\n[See Demo](https://catamphetamine.github.io/relative-time-format/)\n\n## Install\n\n```\nnpm install relative-time-format --save\n```\n\nIf you're not using a bundler then use a [standalone version from a CDN](#cdn).\n\n## Use\n\n```js\nimport RelativeTimeFormat from \"relative-time-format\"\nimport en from \"relative-time-format/locale/en\"\n\nRelativeTimeFormat.addLocale(en)\n\n// Returns \"2 days ago\"\nnew RelativeTimeFormat(\"en\", {\n  style: \"long\" // \"long\" is the default. Other options: \"short\", \"narrow\".\n}).format(-2, \"day\")\n```\n\n## Locales\n\nThe localization resides in the [`locale`](https://github.com/catamphetamine/relative-time-format/tree/master/locale) folder. The format of a localization is:\n\n```js\n{\n  …\n  \"day\": {\n    \"past\": {\n      \"one\": \"{0} day ago\",\n      \"other\": \"{0} days ago\"\n    },\n    \"future\": {\n      \"one\": \"in {0} day\",\n      \"other\": \"in {0} days\"\n    }\n  },\n  …\n}\n```\n\nThe `past` and `future` can be defined by any of: `zero`, `one`, `two`, `few`, `many` and `other`. For more info on which is which read the [official Unicode CLDR documentation](http://cldr.unicode.org/index/cldr-spec/plural-rules). [Unicode CLDR](http://cldr.unicode.org/) (Common Locale Data Repository) is an industry standard and is basically a collection of formatting rules for all locales (date, time, currency, measurement units, numbers, etc). All localizations come from [`cldr-dates-full`](https://github.com/unicode-cldr/cldr-dates-full) package (for example, [`en-US`](https://github.com/unicode-cldr/cldr-dates-full/blob/master/main/en-US-POSIX/dateFields.json)).\n\nTo determine whether a certain amount of time (number) is `one`, `few`, or something else, `relative-time-format` uses Unicode CLDR rules for formatting plurals. These rules are number quantifying functions (one for each locale) which can tell if a number should be treated as `zero`, `one`, `two`, `few`, `many` or `other`. Knowing how these pluralization rules work is not required but anyway here are some links for curious advanced readers: [rules explanation](http://cldr.unicode.org/index/cldr-spec/plural-rules), [list of rules for all locales](http://www.unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html), [list of rules for all locales in JSON format](https://github.com/unicode-cldr/cldr-core/blob/master/supplemental/plurals.json) (part of `cldr-core/supplemental` package), [converting those rules to javascript functions](https://github.com/eemeli/make-plural). These quantifying functions can be found as `quantify` properties of a locale data.\n\nThe `locale` folder is generated from CLDR data by running:\n\n```sh\nnpm run generate-locales\n```\n\nLocale data is extracted from `cldr-core` (quantifiers) and `cldr-dates-full` (relative time messages) packages which usually get some updates once or twice a year.\n\n```sh\nnpm run update-locales\n```\n\n## Higher-level API\n\n`Intl.RelativeTimeFormat` is intentionally a low-level API. Third-party libraries are supposed to be built on top of this base-level API. An example of such library is [`javascript-time-ago`](https://github.com/catamphetamine/javascript-time-ago/) which uses `Intl.RelativeTimeFormat` internally and provides a higher-level API:\n\n```js\nimport TimeAgo from 'javascript-time-ago'\n\n// Load locale-specific relative date/time formatting rules.\nimport en from 'javascript-time-ago/locale/en'\n\n// Add locale-specific relative date/time formatting rules.\nTimeAgo.addLocale(en)\n\n// Create relative date/time formatter.\nconst timeAgo = new TimeAgo('en-US')\n\ntimeAgo.format(new Date())\n// \"just now\"\n\ntimeAgo.format(Date.now() - 60 * 1000)\n// \"a minute ago\"\n\ntimeAgo.format(Date.now() - 2 * 60 * 60 * 1000)\n// \"2 hours ago\"\n\ntimeAgo.format(Date.now() - 24 * 60 * 60 * 1000)\n// \"a day ago\"\n```\n\n## CDN\n\nOne can use any npm CDN service, e.g. [unpkg.com](https://unpkg.com) or [jsdelivr.net](https://jsdelivr.net)\n\n```html\n\u003cscript src=\"https://unpkg.com/relative-time-format@[version]/bundle/polyfill.js\"\u003e\u003c/script\u003e\n\n\u003cscript\u003e\n  var en = ... // Somehow import `relative-time-format/locale/en`.\n  RelativeTimeFormat.addLocale(en)\n  console.log(new RelativeTimeFormat('en').format(-1, 'days'))\n\u003c/script\u003e\n```\n\nwhere `[version]` is an npm package version range (for example, `0.2.x` or `^0.2.0`).\n\n## Test262\n\nThere's a test suite of about 150 test cases for `Intl.RelativeTimeFormat` specification implementations. It's called \"[Test262](https://github.com/tc39/test262/blob/master/test/intl402/RelativeTimeFormat/)\". These tests check every possible imaginable aspect of formal correctness of a spec implementation including the weirdest artificial cases imaginable like accepting strings instead of numbers, accepting objects having keys `0`, `1`, etc instead of arrays, accepting objects with `toString()` method instead of strings, defining all class methods as special \"non-enumerable\" properties via `Object.defineProperty()` instead of the regular way everyone defines class methods in real life, and so on. Handling all these formal edge cases would result in an unnecessarily convoluted and less readable code and I'd prefer to keep things simple and elegant, so this library intentionally chose not to pass all of the \"Test262\" test cases while still passing most of them: it [passes](https://github.com/catamphetamine/Intl.RelativeTimeFormat-test262) the functional correctness part and skips the not-relevant-in-real-life cases part.\n\n## Tests\n\nThis component comes with a 100% code coverage.\n\nTo run tests:\n\n```\nnpm test\n```\n\nTo generate a code coverage report:\n\n```\nnpm run test-coverage\n```\n\nThe code coverage report can be viewed by opening `./coverage/lcov-report/index.html`.\n\nThe `handlebars@4.5.3` [work](https://github.com/handlebars-lang/handlebars.js/issues/1646#issuecomment-578306544)[around](https://github.com/facebook/jest/issues/9396#issuecomment-573328488) in `devDependencies` is for the test coverage to not produce empty reports:\n\n```\nHandlebars: Access has been denied to resolve the property \"statements\" because it is not an \"own property\" of its parent.\nYou can add a runtime option to disable the check or this warning:\nSee https://handlebarsjs.com/api-reference/runtime-options.html#options-to-control-prototype-access for details\n```\n\n## TypeScript\n\nThis library comes with TypeScript \"typings\". If you happen to find any bugs in those, create an issue.\n\n\u003c!--\n## Contributing\n\nAfter cloning this repo, ensure dependencies are installed by running:\n\n```sh\nnpm install\n```\n\nThis module is written in ES6 and uses [Babel](http://babeljs.io/) for ES5\ntranspilation. Widely consumable JavaScript can be produced by running:\n\n```sh\nnpm run build\n```\n\nOnce `npm run build` has run, you may `import` or `require()` directly from\nnode.\n\nAfter developing, the full test suite can be evaluated by running:\n\n```sh\nnpm test\n```\n\nWhen you're ready to test your new functionality on a real project, you can run\n\n```sh\nnpm pack\n```\n\nIt will `build`, `test` and then create a `.tgz` archive which you can then install in your project folder\n\n```sh\nnpm install [package-name]-[version].tar.gz\n```\n--\u003e\n\n## License\n\n[MIT](LICENSE)","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcatamphetamine%2Frelative-time-format","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcatamphetamine%2Frelative-time-format","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcatamphetamine%2Frelative-time-format/lists"}