{"id":15405281,"url":"https://github.com/fnando/i18n","last_synced_at":"2025-04-13T18:35:53.710Z","repository":{"id":42822300,"uuid":"227004901","full_name":"fnando/i18n","owner":"fnando","description":"A small library to provide the I18n translations on the JavaScript.","archived":false,"fork":false,"pushed_at":"2024-10-21T19:24:08.000Z","size":2214,"stargazers_count":164,"open_issues_count":8,"forks_count":20,"subscribers_count":3,"default_branch":"main","last_synced_at":"2024-10-29T22:26:02.232Z","etag":null,"topics":["i18n","internationalization","javascript","localization","typescript"],"latest_commit_sha":null,"homepage":"https://fnando.github.io/i18n/","language":"TypeScript","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/fnando.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE.md","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":["fnando"],"custom":["https://paypal.me/nandovieira/🍕"]}},"created_at":"2019-12-10T01:46:34.000Z","updated_at":"2024-10-28T18:16:49.000Z","dependencies_parsed_at":"2024-06-18T12:39:07.220Z","dependency_job_id":"d698fcc3-c938-4997-984f-68299453e801","html_url":"https://github.com/fnando/i18n","commit_stats":{"total_commits":162,"total_committers":10,"mean_commits":16.2,"dds":0.09876543209876543,"last_synced_commit":"6871e31f75cb9c9c3cb7ca24a417cd03ebd8f07f"},"previous_names":[],"tags_count":28,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fnando%2Fi18n","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fnando%2Fi18n/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fnando%2Fi18n/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fnando%2Fi18n/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fnando","download_url":"https://codeload.github.com/fnando/i18n/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248761441,"owners_count":21157558,"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":["i18n","internationalization","javascript","localization","typescript"],"created_at":"2024-10-01T16:15:52.612Z","updated_at":"2025-04-13T18:35:53.657Z","avatar_url":"https://github.com/fnando.png","language":"TypeScript","readme":"\u003cp align=\"center\"\u003e\n  \u003cimg width=\"250\" height=\"58\" src=\"https://github.com/fnando/i18n-js/raw/main/images/i18njs.png\" alt=\"i18n.js\"\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  A small library to provide the \u003ca href=\"https://rubygems.org/gems/i18n\"\u003ei18n\u003c/a\u003e translations on the JavaScript.\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://github.com/fnando/i18n/actions?query=workflow%3Ajs-tests\"\u003e\u003cimg src=\"https://github.com/fnando/i18n/workflows/js-tests/badge.svg\" alt=\"Tests\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://www.npmjs.com/package/i18n-js\"\u003e\u003cimg src=\"https://img.shields.io/npm/v/i18n-js/latest.svg\" alt=\"npm version\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://www.npmjs.com/package/i18n-js\"\u003e\u003cimg src=\"https://img.shields.io/npm/dt/i18n-js.svg\" alt=\"npm downloads\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://opensource.org/licenses/MIT\"\u003e\u003cimg src=\"https://img.shields.io/badge/License-MIT-yellow.svg\" alt=\"License: MIT\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n## Installation\n\n- Yarn: `yarn add i18n-js@latest`\n- NPM: `npm install i18n-js@latest`\n\n## Usage\n\n### Setting up\n\nFirst, you need to instantiate `I18n` with the translations' object, the main\nclass of this library.\n\n```js\nimport { I18n } from \"i18n-js\";\nimport translations from \"./translations.json\";\n\nconst i18n = new I18n(translations);\n```\n\nThe `translations` object is a direct export of translations defined by\n[Ruby on Rails](https://guides.rubyonrails.org/i18n.html). To export the\ntranslations, you can use [i18n-js](https://github.com/fnando/i18n-js), a Ruby\ngem that's completely disconnected from Rails and that can be used for the\nsolely purpose of exporting the translations, even if your project is written in\na different language. If all you care about is some basic translation mechanism,\nthen you can set the object like this:\n\n```js\nconst i18n = new I18n({\n  en: {\n    hello: \"Hi!\",\n  },\n  \"pt-BR\": {\n    hello: \"Olá!\",\n  },\n});\n```\n\nEach root key is a different locale that may or may not have the script code.\nThis library also supports locales with region code, like `zh-Hant-TW`.\n\nOnce everything is set up, you can then define the locale. `en` is both the\ncurrent and default locale. To override either values, you have to use\n`I18n#defaultLocale` and `I18n#locale`.\n\n```js\ni18n.defaultLocale = \"pt-BR\";\ni18n.locale = \"pt-BR\";\n```\n\n#### Base translations\n\nThis library comes bundled with all base translations made available by\n[rails-i18n](https://github.com/svenfuchs/rails-i18n/tree/master/rails/locale).\nBase translations allow formatting date, numbers, and sentence connectors, among\nother things.\n\nTo load the base translations, use something like the following:\n\n```js\nimport { I18n } from \"i18n-js\";\nimport ptBR from \"i18n-js/json/pt-BR.json\";\nimport en from \"i18n-js/json/en.json\";\n\nconst i18n = new I18n({\n  ...ptBR,\n  ...en,\n});\n```\n\n### Updating translation store\n\nUpdating the translation store is trivial. All you have to do is calling\n`I18n#store` with the translations that need to be merged. Let's assume you've\nexported all your app's translations using\n[i18n-js](https://github.com/fnando/i18n-js) CLI, using a separate file for each\nlanguage, like this:\n\n- `translations/en.json`\n- `translations/pt-BR.json`\n\nThis is how you could update the store:\n\n```js\nimport { I18n } from \"i18n-js\";\nimport ptBR from \"translations/pt-BR.json\";\nimport en from \"translations/en.json\";\n\nconst i18n = new I18n();\n\ni18n.store(en);\ni18n.store(ptBR);\n```\n\nThis method will allow you to lazy load translations and them updating the store\nas needed.\n\n```js\nimport { I18n } from \"i18n-js\";\n\nasync function loadTranslations(i18n, locale) {\n  const response = await fetch(`/translations/${locale}.json`);\n  const translations = await response.json();\n\n  i18n.store(translations);\n}\n\nconst i18n = new I18n();\nloadTranslations(i18n, \"es\");\n```\n\n### Events\n\nA change event is triggered whenever `I18n#store` or `I18n#update` is called, or\nwhen `I18n#locale`/`I18n#defaultLocale` is set. To subscribe to these changes,\nuse the method `I18n#onChange(i18n: I18n)`.\n\n```js\nconst i18n = new I18n();\ni18n.onChange(() =\u003e {\n  console.log(\"I18n has changed!\");\n});\n```\n\nEvery change will increment the property `I18n#version`, so you can use it as a\ncache key. Also, when you subscribe to change events,\n`I18n#onChange(i18n: I18n)` will return another function that can be used to\nremove the event handler.\n\n```js\nuseEffect(() =\u003e {\n  const unsubscribe = i18n.onChange(() =\u003e {\n    // do something\n  });\n\n  return unsubscribe;\n}, []);\n\nuseEffect(() =\u003e {\n  console.log(\"I18n has been updated!\");\n}, [i18n.version]);\n```\n\n### Translating messages\n\nTo translate messages, you have to use the `I18n#translate`, or its `I18n#t`\nalias.\n\n```js\ni18n.locale = \"en\";\ni18n.t(\"hello\"); //=\u003e Hi!\n\ni18n.locale = \"pt-BR\";\ni18n.t(\"hello\"); //=\u003e Olá!\n```\n\nYou can also provide an array as scope. Both calls below are equivalent.\n\n```js\ni18n.t([\"greetings\", \"hello\"]);\ni18n.t(\"greetings.hello\");\n```\n\nYour translations may have dynamic values that should be interpolated. Here's a\ngreeting message that takes a name:\n\n```js\nconst i18n = new I18n({\n  en: { greetings: \"Hi, %{name}!\" },\n  \"pt-BR\": { greetings: \"Olá, %{name}!\" },\n});\n\ni18n.t(\"greetings\", { name: \"John\" });\n```\n\nIf the translation is an array and the entry is a string, values will be\ninterpolated in a shallow way.\n\n```js\nconst i18n = new I18n({\n  en: { messages: [\"Hello there!\", \"Welcome back, %{name}!\"] },\n});\n\ni18n.t(\"messages\", { name: \"John\" });\n//=\u003e [\"Hello there!\", \"Welcome back, John!\"]\n```\n\nYou may want to override the default\n[`interpolate`](https://github.com/fnando/i18n/blob/main/src/helpers/interpolate.ts)\nfunction with your own, if for instance you want these dynamic values to be\nReact elements:\n\n```jsx\nconst i18n = new I18n({\n  en: { greetings: \"Hi, %{name}!\" },\n  \"pt-BR\": { greetings: \"Olá, %{name}!\" },\n});\n\ni18n.interpolate = (i18n, message, options) =\u003e {\n  // ...\n};\n\nreturn \u003cText\u003e{i18n.t(\"greetings\", { name: \u003cBoldText\u003eJohn\u003c/BoldText\u003e })}\u003c/Text\u003e;\n```\n\n#### Missing translations\n\nA translation may be missing. In that case, you may set the default value that's\ngoing to be returned.\n\n```js\ni18n.t(\"missing.scope\", { defaultValue: \"This is a default message\" });\n```\n\nDefault messages can also have interpolation.\n\n```js\ni18n.t(\"noun\", { defaultValue: \"I'm a {{noun}}\", noun: \"Mac\" });\n```\n\nAlternatively, you can define a list of scopes that will be searched instead.\n\n```js\n// As a scope\ni18n.t(\"some.missing.scope\", { defaults: [{ scope: \"some.existing.scope\" }] });\n\n// As a simple translation\ni18n.t(\"some.missing.scope\", { defaults: [{ message: \"Some message\" }] });\n```\n\nDefault values must be provided as an array of objects where the key is the type\nof desired translation, a `scope` or a `message`. The returned translation will\nbe either the first scope recognized, or the first message defined.\n\nThe translation will fall back to the `defaultValue` translation if no scope in\n`defaults` matches and if no `message` default is found.\n\nYou can enable translation fallback with `I18n#enableFallback`.\n\n```js\ni18n.enableFallback = true;\n```\n\nBy default missing translations will first be looked for in less specific\nversions of the requested locale and if that fails by taking them from your\n`I18n#defaultLocale`.\n\n```js\n// if i18n.defaultLocale = \"en\" and translation doesn't exist\n// for i18n.locale = \"de-DE\" this key will be taken from \"de\" locale scope\n// or, if that also doesn't exist, from \"en\" locale scope\ni18n.t(\"some.missing.scope\");\n```\n\nCustom fallback rules can also be specified for a specific language. The locale\nhandler must be registered using `i18n.locales.register()`.\n\n```js\ni18n.locales.register(\"no\", [\"nb\", \"en\"]);\n```\n\nBy default a missing translation will be displayed as\n`[missing \"name of scope\" translation]`. You can override this behavior by\nsetting `i18n.missingBehavior` to `\"guess\"`.\n\n```js\ni18n.missingBehavior = \"guess\";\n```\n\nThe \"guess\" behavior will take the last section of the scope and apply some\nreplace rules; camel case becomes lower case and underscores are replaced with\nspace. In practice, it means that a scope like\n`questionnaire.whatIsYourFavorite_ChristmasPresent` becomes\n`what is your favorite Christmas present`.\n\nThere's also a strategy called `error`, which will throw an exception every time\nyou fetch a missing translation. This is great for development. It'll even end\nup on your error tracking!\n\n```js\ni18n.missingBehavior = \"error\";\n```\n\nTo detect missing translations, you can also set\n`i18n.missingTranslationPrefix`.\n\n```js\ni18n.missingTranslationPrefix = \"EE: \";\n```\n\nThe same `questionnaire.whatIsYourFavorite_ChristmasPresent` scope would\nconverted into `EE: what is your favorite Christmas present`. This is helpful if\nyou want to add a check to your automated tests.\n\nIf you need to specify a missing behavior just for one call, you can provide a\ncustom `missingBehavior` option.\n\n```js\ni18n.t(\"missing.key\", { missingBehavior: \"error\" });\n```\n\nYou can completely override the missing translation strategy by setting it to a\nfunction. The following example will return `null` for every missing\ntranslation.\n\n```js\ni18n.missingTranslation = () =\u003e null;\n```\n\nFinally, you can also create your own missing translation behavior. The example\nbelow registers a new behavior that returns an empty string in case a\ntranslation is missing.\n\n```js\ni18n.missingTranslation.register(\"empty\", (i18n, scope, options) =\u003e \"\");\n```\n\n#### Pluralization\n\nThis library has support for pluralization and by default works with English,\nand similar pluralized languages like Portuguese.\n\nFirst, you have to define your translations with special keywords defined by the\npluralization handler. The default keywords are `zero`, `one`, and `other`.\n\n```js\nconst i18n = new I18n({\n  en: {\n    inbox: {\n      zero: \"You have no messages\",\n      one: \"You have one message\",\n      other: \"You have %{count} messages\",\n    },\n  },\n\n  \"pt-BR\": {\n    inbox: {\n      zero: \"Você não tem mensagens\",\n      one: \"Você tem uma mensagem\",\n      other: \"Você tem %{count} mensagens\",\n    },\n  },\n});\n```\n\nTo retrieve the pluralized translation you must provide the `count` option with\na numeric value.\n\n```js\ni18n.t(\"inbox\", { count: 0 }); //=\u003e You have no messages\ni18n.t(\"inbox\", { count: 1 }); //=\u003e You have one message\ni18n.t(\"inbox\", { count: 2 }); //=\u003e You have 2 messages\n```\n\nYou may need to define new rules for other languages like Russian. This can be\ndone by registering a handler with `i18n.pluralization.register()`. The\nfollowing example defines a Russian pluralizer.\n\n```js\ni18n.pluralization.register(\"ru\", (_i18n, count) =\u003e {\n  const mod10 = count % 10;\n  const mod100 = count % 100;\n  let key;\n\n  const one = mod10 === 1 \u0026\u0026 mod100 !== 11;\n  const few = [2, 3, 4].includes(mod10) \u0026\u0026 ![12, 13, 14].includes(mod100);\n  const many =\n    mod10 === 0 ||\n    [5, 6, 7, 8, 9].includes(mod10) ||\n    [11, 12, 13, 14].includes(mod100);\n\n  if (one) {\n    key = \"one\";\n  } else if (few) {\n    key = \"few\";\n  } else if (many) {\n    key = \"many\";\n  } else {\n    key = \"other\";\n  }\n\n  return [key];\n});\n```\n\nYou can find all rules on\n[http://www.unicode.org/](http://www.unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html).\n\nYou can also leverage [make-plural](https://github.com/eemeli/make-plural/),\nrather than writing all your pluralization functions. For this, you must wrap\nmake-plural's function by using\n`useMakePlural({ pluralizer, includeZero, ordinal })`:\n\n```js\nimport { ru } from \"make-plural\";\nimport { useMakePlural } from \"i18n-js\";\n\ni18n.pluralization.register(\"ru\", useMakePlural({ pluralizer: ru }));\n```\n\n#### Other options\n\nIf you're providing the same scope again and again, you can reduce the\nboilerplate by setting the `scope` option.\n\n```js\nconst options = { scope: \"activerecord.attributes.user\" };\n\ni18n.t(\"name\", options);\ni18n.t(\"email\", options);\ni18n.t(\"username\", options);\n```\n\n### Number Formatting\n\nSimilar to Rails helpers, you can have localized number and currency formatting.\n\n```js\ni18n.l(\"currency\", 1990.99);\n// $1,990.99\n\ni18n.l(\"number\", 1990.99);\n// 1,990.99\n\ni18n.l(\"percentage\", 123.45);\n// 123.450%\n```\n\nTo have more control over number formatting, you can use the\n`I18n#numberToHuman`, `I18n#numberToPercentage`, `I18n#numberToCurrency`,\n`I18n#numberToHumanSize`, `I18n#numberToDelimited` and `I18n#numberToRounded`\nfunctions.\n\n#### `I18n#numberToCurrency`\n\nFormats a `number` into a currency string (e.g., $13.65). You can customize the\nformat in the using an `options` object.\n\nThe currency unit and number formatting of the current locale will be used\nunless otherwise specified in the provided options. No currency conversion is\nperformed. If the user is given a way to change their locale, they will also be\nable to change the relative value of the currency displayed with this helper.\n\n##### Options\n\n- `precision` - Sets the level of precision (defaults to 2).\n- `roundMode` - Determine how rounding is performed (defaults to `default`.)\n- `unit` - Sets the denomination of the currency (defaults to \"$\").\n- `separator` - Sets the separator between the units (defaults to \".\").\n- `delimiter` - Sets the thousands delimiter (defaults to \",\").\n- `format` - Sets the format for non-negative numbers (defaults to \"%u%n\").\n  Fields are `%u` for the currency, and `%n` for the number.\n- `negativeFormat` - Sets the format for negative numbers (defaults to\n  prepending a hyphen to the formatted number given by `format`). Accepts the\n  same fields than `format`, except `%n` is here the absolute value of the\n  number.\n- `stripInsignificantZeros` - If `true` removes insignificant zeros after the\n  decimal separator (defaults to `false`).\n- `raise` - If `true`, raises exception for non-numeric values like NaN and\n  Infinite values.\n\n##### Examples\n\n```js\ni18n.numberToCurrency(1234567890.5);\n// =\u003e \"$1,234,567,890.50\"\n\ni18n.numberToCurrency(1234567890.506);\n// =\u003e \"$1,234,567,890.51\"\n\ni18n.numberToCurrency(1234567890.506, { precision: 3 });\n// =\u003e \"$1,234,567,890.506\"\n\ni18n.numberToCurrency(\"123a456\");\n// =\u003e \"$123a456\"\n\ni18n.numberToCurrency(\"123a456\", { raise: true });\n// =\u003e raises exception (\"123a456\" is not a valid numeric value)\n\ni18n.numberToCurrency(-0.456789, { precision: 0 });\n// =\u003e \"$0\"\n\ni18n.numberToCurrency(-1234567890.5, { negativeFormat: \"(%u%n)\" });\n// =\u003e \"($1,234,567,890.50)\"\n\ni18n.numberToCurrency(1234567890.5, {\n  unit: \"\u0026pound;\",\n  separator: \",\",\n  delimiter: \"\",\n});\n// =\u003e \"\u0026pound;1234567890,50\"\n\ni18n.numberToCurrency(1234567890.5, {\n  unit: \"\u0026pound;\",\n  separator: \",\",\n  delimiter: \"\",\n  format: \"%n %u\",\n});\n// =\u003e \"1234567890,50 \u0026pound;\"\n\ni18n.numberToCurrency(1234567890.5, { stripInsignificantZeros: true });\n// =\u003e \"$1,234,567,890.5\"\n\ni18n.numberToCurrency(1234567890.5, { precision: 0, roundMode: \"up\" });\n// =\u003e \"$1,234,567,891\"\n```\n\n#### `I18n#numberToPercentage`\n\nFormats a `number` as a percentage string (e.g., 65%). You can customize the\nformat in the `options` hash.\n\n##### Options\n\n- `precision` - Sets the level of precision (defaults to 3).\n- `roundMode` - Determine how rounding is performed (defaults to `default`.)\n- `separator` - Sets the separator between the units (defaults to \".\").\n- `delimiter` - Sets the thousands delimiter (defaults to \"\").\n- `format` - Sets the format for non-negative numbers (defaults to \"%n%\"). The\n  number field is represented by `%n`.\n- `negativeFormat` - Sets the format for negative numbers (defaults to\n  prepending a hyphen to the formatted number given by `format`). Accepts the\n  same fields than `format`, except `%n` is here the absolute value of the\n  number.\n- `stripInsignificantZeros` - If `true` removes insignificant zeros after the\n  decimal separator (defaults to `false`).\n\n##### Examples\n\n```js\ni18n.numberToPercentage(100);\n// =\u003e \"100.000%\"\n\ni18n.numberToPercentage(\"98\");\n// =\u003e \"98.000%\"\n\ni18n.numberToPercentage(100, { precision: 0 });\n// =\u003e \"100%\"\n\ni18n.numberToPercentage(1000, { delimiter: \".\", separator: \",\" });\n// =\u003e \"1.000,000%\"\n\ni18n.numberToPercentage(302.24398923423, { precision: 5 });\n// =\u003e \"302.24399%\"\n\ni18n.numberToPercentage(1000, { precision: null });\n// =\u003e \"1000%\"\n\ni18n.numberToPercentage(\"98a\");\n// =\u003e \"98a%\"\n\ni18n.numberToPercentage(100, { format: \"%n  %\" });\n// =\u003e \"100.000  %\"\n\ni18n.numberToPercentage(302.24398923423, { precision: 5, roundMode: \"down\" });\n// =\u003e \"302.24398%\"\n```\n\n#### `I18n#numberToDelimited`\n\nFormats a `number` with grouped thousands using `delimiter` (e.g., 12,324). You\ncan customize the format in the `options` object.\n\n##### Options\n\n- `delimiter` - Sets the thousands delimiter (defaults to \",\").\n- `separator` - Sets the separator between the fractional and integer digits\n  (defaults to \".\").\n- `delimiterPattern` - Sets a custom regular expression used for deriving the\n  placement of delimiter. Helpful when using currency formats like INR. The\n  regular expression must be global (i.e. it has the `g` flag).\n\n##### Examples\n\n```js\ni18n.numberToDelimited(12345678);\n// =\u003e \"12,345,678\"\n\ni18n.numberToDelimited(\"123456\");\n// =\u003e \"123,456\"\n\ni18n.numberToDelimited(12345678.05);\n// =\u003e \"12,345,678.05\"\n\ni18n.numberToDelimited(12345678, { delimiter: \".\" });\n// =\u003e \"12.345.678\"\n\ni18n.numberToDelimited(12345678, { delimiter: \",\" });\n// =\u003e \"12,345,678\"\n\ni18n.numberToDelimited(12345678.05, { separator: \" \" });\n// =\u003e \"12,345,678 05\"\n\ni18n.numberToDelimited(\"112a\");\n// =\u003e \"112a\"\n\ni18n.numberToDelimited(98765432.98, { delimiter: \" \", separator: \",\" });\n// =\u003e \"98 765 432,98\"\n\ni18n.numberToDelimited(\"123456.78\", {\n  delimiterPattern: /(\\d+?)(?=(\\d\\d)+(\\d)(?!\\d))/g,\n});\n// =\u003e \"1,23,456.78\"\n```\n\n#### `I18n#numberToRounded`\n\nFormats a `number` with the specified level of `precision` (e.g., 112.32 has a\nprecision of 2 if `significant` is `false`, and 5 if `significant` is `true`).\nYou can customize the format in the `options` object.\n\n##### Options\n\n- `locale` - Sets the locale to be used for formatting (defaults to current\n  locale).\n- `precision` - Sets the precision of the number (defaults to 3). Keeps the\n  number's precision if `null`.\n- `RoundMode` - Determine how rounding is performed (defaults to :default).\n- `significant` - If `true`, precision will be the number of significant_digits.\n  If `false`, the number of fractional digits (defaults to `false`).\n- `separator` - Sets the separator between the fractional and integer digits\n  (defaults to \".\").\n- `delimiter` - Sets the thousands delimiter (defaults to \"\").\n- `stripInsignificantZeros` - If `true` removes insignificant zeros after the\n  decimal separator (defaults to `false`).\n\n##### Examples\n\n```js\ni18n.numberToRounded(111.2345);\n// =\u003e \"111.235\"\n\ni18n.numberToRounded(111.2345, { precision: 2 });\n// =\u003e \"111.23\"\n\ni18n.numberToRounded(13, { precision: 5 });\n// =\u003e \"13.00000\"\n\ni18n.numberToRounded(389.32314, { precision: 0 });\n// =\u003e \"389\"\n\ni18n.numberToRounded(111.2345, { significant: true });\n// =\u003e \"111\"\n\ni18n.numberToRounded(111.2345, { precision: 1, significant: true });\n// =\u003e \"100\"\n\ni18n.numberToRounded(13, { precision: 5, significant: true });\n// =\u003e \"13.000\"\n\ni18n.numberToRounded(13, { precision: null });\n// =\u003e \"13\"\n\ni18n.numberToRounded(389.32314, { precision: 0, roundMode: \"up\" });\n// =\u003e \"390\"\n\ni18n.numberToRounded(13, {\n  precision: 5,\n  significant: true,\n  stripInsignificantZeros: true,\n});\n// =\u003e \"13\"\n\ni18n.numberToRounded(389.32314, { precision: 4, significant: true });\n// =\u003e \"389.3\"\n\ni18n.numberToRounded(1111.2345, {\n  precision: 2,\n  separator: \",\",\n  delimiter: \".\",\n});\n// =\u003e \"1.111,23\"\n```\n\n#### `I18n#numberToHumanSize`\n\nFormats the bytes in `number` into a more understandable representation (e.g.,\ngiving it 1500 yields 1.46 KB). This method is useful for reporting file sizes\nto users. You can customize the format in the `options` object.\n\nSee `I18n#numberToHuman` if you want to pretty-print a generic number.\n\n##### Options\n\n- `precision` - Sets the precision of the number (defaults to 3).\n- `roundMode` - Determine how rounding is performed (defaults to `default`)\n- `significant` - If `true`, precision will be the number of significant_digits.\n  If `false`, the number of fractional digits (defaults to `true`)\n- `separator` - Sets the separator between the fractional and integer digits\n  (defaults to \".\").\n- `delimiter` - Sets the thousands delimiter (defaults to \"\").\n- `stripInsignificantZeros` - If `true` removes insignificant zeros after the\n  decimal separator (defaults to `true`)\n\n##### Examples\n\n```js\ni18n.numberToHumanSize(123)\n// =\u003e \"123 Bytes\"\n\ni18n.numberToHumanSize(1234)\n// =\u003e \"1.21 KB\"\n\ni18n.numberToHumanSize(12345)\n// =\u003e \"12.1 KB\"\n\ni18n.numberToHumanSize(1234567)\n// =\u003e \"1.18 MB\"\n\ni18n.numberToHumanSize(1234567890)\n// =\u003e \"1.15 GB\"\n\ni18n.numberToHumanSize(1234567890123)\n// =\u003e \"1.12 TB\"\n\ni18n.numberToHumanSize(1234567890123456)\n// =\u003e \"1.1 PB\"\n\ni18n.numberToHumanSize(1234567890123456789)\n// =\u003e \"1.07 EB\"\n\ni18n.numberToHumanSize(1234567, {precision: 2})\n// =\u003e \"1.2 MB\"\n\ni18n.numberToHumanSize(483989, precision: 2)\n// =\u003e \"470 KB\"\n\ni18n.numberToHumanSize(483989, {precision: 2, roundMode: \"up\"})\n// =\u003e \"480 KB\"\n\ni18n.numberToHumanSize(1234567, {precision: 2, separator: \",\"})\n// =\u003e \"1,2 MB\"\n\ni18n.numberToHumanSize(1234567890123, {precision: 5})\n// =\u003e \"1.1228 TB\"\n\ni18n.numberToHumanSize(524288000, {precision: 5})\n// =\u003e \"500 MB\"\n```\n\n#### `I18n#numberToHuman`\n\nPretty prints (formats and approximates) a number in a way it is more readable\nby humans (e.g.: 1200000000 becomes \"1.2 Billion\"). This is useful for numbers\nthat can get very large (and too hard to read).\n\nSee `I18n#numberToHumanSize` if you want to print a file size.\n\nYou can also define your own unit-quantifier names if you want to use other\ndecimal units (e.g.: 1500 becomes \"1.5 kilometers\", 0.150 becomes \"150\nmilliliters\", etc). You may define a wide range of unit quantifiers, even\nfractional ones (centi, deci, mili, etc).\n\n##### Options\n\n- `precision` - Sets the precision of the number (defaults to 3).\n- `roundMode` - Determine how rounding is performed (defaults to `default`).\n- `significant` - If `true`, precision will be the number of significant_digits.\n  If `false`, the number of fractional digits (defaults to `true`)\n- `separator` - Sets the separator between the fractional and integer digits\n  (defaults to \".\").\n- `delimiter` - Sets the thousands delimiter (defaults to \"\").\n- `stripInsignificantZeros` - If `true` removes insignificant zeros after the\n  decimal separator (defaults to `true`)\n- `units` - A Hash of unit quantifier names. Or a string containing an i18n\n  scope where to find this hash. It might have the following keys:\n  - _integers_: `unit`, `ten`, `hundred`, `thousand`, `million`, `billion`,\n    `trillion`, `quadrillion`\n  - _fractionals_: `deci`, `centi`, `mili`, `micro`, `nano`, `pico`, `femto`\n- `format` - Sets the format of the output string (defaults to \"%n %u\"). The\n  field types are:\n  - %u - The quantifier (ex.: 'thousand')\n  - %n - The number\n\n##### Examples\n\n```js\ni18n.numberToHuman(123);\n// =\u003e \"123\"\n\ni18n.numberToHuman(1234);\n// =\u003e \"1.23 Thousand\"\n\ni18n.numberToHuman(12345);\n// =\u003e \"12.3 Thousand\"\n\ni18n.numberToHuman(1234567);\n// =\u003e \"1.23 Million\"\n\ni18n.numberToHuman(1234567890);\n// =\u003e \"1.23 Billion\"\n\ni18n.numberToHuman(1234567890123);\n// =\u003e \"1.23 Trillion\"\n\ni18n.numberToHuman(1234567890123456);\n// =\u003e \"1.23 Quadrillion\"\n\ni18n.numberToHuman(1234567890123456789);\n// =\u003e \"1230 Quadrillion\"\n\ni18n.numberToHuman(489939, { precision: 2 });\n// =\u003e \"490 Thousand\"\n\ni18n.numberToHuman(489939, { precision: 4 });\n// =\u003e \"489.9 Thousand\"\n\ni18n.numberToHuman(489939, { precision: 2, roundMode: \"down\" });\n// =\u003e \"480 Thousand\"\n\ni18n.numberToHuman(1234567, { precision: 4, significant: false });\n// =\u003e \"1.2346 Million\"\n\ni18n.numberToHuman(1234567, {\n  precision: 1,\n  separator: \",\",\n  significant: false,\n});\n// =\u003e \"1,2 Million\"\n\ni18n.numberToHuman(500000000, { precision: 5 });\n// =\u003e \"500 Million\"\n\ni18n.numberToHuman(12345012345, { significant: false });\n// =\u003e \"12.345 Billion\"\n```\n\nNon-significant zeros after the decimal separator are stripped out by default\n(set `stripInsignificantZeros` to `false` to change that):\n\n```js\ni18n.numberToHuman(12.00001);\n// =\u003e \"12\"\n\ni18n.numberToHuman(12.00001, { stripInsignificantZeros: false });\n// =\u003e \"12.0\"\n```\n\nYou can also use your own custom unit quantifiers:\n\n```js\ni18n.numberToHuman(500000, units: { unit: \"ml\", thousand: \"lt\" })\n// =\u003e \"500 lt\"\n```\n\nIf in your I18n locale you have:\n\n```yaml\n---\nen:\n  distance:\n    centi:\n      one: \"centimeter\"\n      other: \"centimeters\"\n    unit:\n      one: \"meter\"\n      other: \"meters\"\n    thousand:\n      one: \"kilometer\"\n      other: \"kilometers\"\n    billion: \"gazillion-distance\"\n```\n\nThen you could do:\n\n```js\ni18n.numberToHuman(543934, { units: \"distance\" });\n// =\u003e \"544 kilometers\"\n\ni18n.numberToHuman(54393498, { units: \"distance\" });\n// =\u003e \"54400 kilometers\"\n\ni18n.numberToHuman(54393498000, { units: \"distance\" });\n// =\u003e \"54.4 gazillion-distance\"\n\ni18n.numberToHuman(343, { units: \"distance\", precision: 1 });\n// =\u003e \"300 meters\"\n\ni18n.numberToHuman(1, { units: \"distance\" });\n// =\u003e \"1 meter\"\n\ni18n.numberToHuman(0.34, { units: \"distance\" });\n// =\u003e \"34 centimeters\"\n```\n\n### Date Formatting\n\nThe `I18n#localize` (or its alias `I18n#l`) can accept a string, epoch time\ninteger or a `Date` object. You can see below the accepted formats:\n\n```js\n// yyyy-mm-dd\ni18n.l(\"date.formats.short\", \"2009-09-18\");\n\n// yyyy-mm-dd hh:mm:ss\ni18n.l(\"time.formats.short\", \"2009-09-18 23:12:43\");\n\n// JSON format with local Timezone (part of ISO-8601)\ni18n.l(\"time.formats.short\", \"2009-11-09T18:10:34\");\n\n// JSON format in UTC (part of ISO-8601)\ni18n.l(\"time.formats.short\", \"2009-11-09T18:10:34Z\");\n\n// Epoch time\ni18n.l(\"date.formats.short\", 1251862029000);\n\n// mm/dd/yyyy\ni18n.l(\"date.formats.short\", \"09/18/2009\");\n\n// Date object\ni18n.l(\"date.formats.short\", new Date());\n```\n\nYou can also add placeholders to the date format:\n\n```js\nconst i18n = new I18n({\n  date: {\n    formats: {\n      ordinalDay: \"%B %{day}\",\n    },\n  },\n});\n\ni18n.l(\"date.formats.ordinalDay\", \"2009-09-18\", { day: \"18th\" }); // Sep 18th\n```\n\nIf you prefer, you can use the `I18n#toTime` and `I18n#strftime` functions\ndirectly to format dates.\n\n```js\nvar date = new Date();\ni18n.toTime(\"date.formats.short\", \"2009-09-18\");\ni18n.toTime(\"date.formats.short\", date);\ni18n.strftime(date, \"%d/%m/%Y\");\n```\n\nThe accepted formats for `i18n.strftime` are:\n\n```\n%a  - The abbreviated weekday name (Sun)\n%A  - The full weekday name (Sunday)\n%b  - The abbreviated month name (Jan)\n%B  - The full month name (January)\n%c  - The preferred local date and time representation\n%d  - Day of the month (01..31)\n%-d - Day of the month (1..31)\n%H  - Hour of the day, 24-hour clock (00..23)\n%-H - Hour of the day, 24-hour clock (0..23)\n%k  - Hour of the day, 24-hour clock (0..23)\n%I  - Hour of the day, 12-hour clock (01..12)\n%-I - Hour of the day, 12-hour clock (1..12)\n%l  - Hour of the day, 12-hour clock (1..12)\n%m  - Month of the year (01..12)\n%-m - Month of the year (1..12)\n%M  - Minute of the hour (00..59)\n%-M - Minute of the hour (0..59)\n%p  - Meridian indicator (AM  or  PM)\n%P  - Meridian indicator (am  or  pm)\n%S  - Second of the minute (00..60)\n%-S - Second of the minute (0..60)\n%w  - Day of the week (Sunday is 0, 0..6)\n%y  - Year without a century (00..99)\n%-y - Year without a century (0..99)\n%Y  - Year with century\n%z  - Timezone offset (+0545)\n%Z  - Timezone offset (+0545)\n```\n\nCheck out\n[\\_\\_tests\\_\\_/strftime.test.ts](https://github.com/fnando/i18n/blob/main/__tests__/strftime.test.ts)\nfile for more examples!\n\nFinally, you can also diplay relative time strings using `I18n#timeAgoInWords`.\n\n```js\nconst to = new Date();\nconst from = to.getTime() - 60 * 60 * 1000; // ~1h ago.\n\ni18n.timeAgoInWords(from, to);\n//=\u003e about 1 hour\n```\n\n#### Using pluralization and number formatting together\n\nSometimes you might want to display translation with formatted number, like\nadding thousand delimiters to displayed number You can do this:\n\n```js\nconst i18n = new I18n({\n  en: {\n    points: {\n      one: \"1 Point\",\n      other: \"{{points}} Points\",\n    },\n  },\n});\n\nconst points = 1234;\n\ni18n.t(\"points\", {\n  count: points,\n  points: i18n.formatNumber(points),\n});\n```\n\nOutput should be `1,234 points`.\n\n### Other helpers\n\n#### `I18n#toSentence(list, options)`\n\n```js\ni18n.toSentence([\"apple\", \"banana\", \"pineapple\"]);\n//=\u003e apple, banana, and pineapple.\n```\n\n## Troubleshooting\n\n### I'm getting an error like `Unable to resolve \"make-plural\" from \"node modules/i18n-js/dist/import/Pluralization.js\"`\n\n[make-plural](https://www.npmjs.com/package/make-plural) uses `.mjs` files. You\nneed to change your build pipeline to also consider these files.\n\nIf you're using [react-native](https://reactnative.dev), you need to change your\nmetro config to consider `.mjs`. Try doing something like this (you may need to\nadapt your code based on existing changes).\n\n```js\nconst { getDefaultConfig } = require(\"metro-config\");\n\nmodule.exports = (async () =\u003e {\n  const {\n    resolver: { assetExts, sourceExts },\n  } = await getDefaultConfig();\n\n  return {\n    resolver: {\n      sourceExts: [...sourceExts, \"mjs\"],\n    },\n  };\n})();\n```\n\n### I'm getting an error like `SyntaxError: Unexpected end of JSON input` or `Uncaught SyntaxError: Unexpected token ;`\n\nYou may get such error if you're trying to load empty JSON files with\n`import data from \"file.json\"`. This has nothing to do with I18n and is related\nto how your JSON file is loaded. **JSON files must contain valid JSON data.**\n\nSimilarly, make sure you're writing valid JSON, and not JavaScript. For\ninstance, if you write something like `{};`, you'll get an error like\n`Uncaught SyntaxError: Unexpected token ;`.\n\n### My JSON contains a flat structure. How can I load and use it with I18n.js?\n\nI18n.js expects a nested object to represent the translation tree. For this\nreason, you cannot use an object like the following by default:\n\n```json\n{\n  \"en.messages.hello\": \"hello\",\n  \"pt-BR.messages.hello\": \"olá\"\n}\n```\n\nOne solution is using something like the following to transform your flat into a\nnested object:\n\n```js\nconst { set } = require(\"lodash\");\n\nconst from = {\n  \"en.messages.hello\": \"hello\",\n  \"pt-BR.messages.hello\": \"olá\",\n};\n\nfunction flatToNestedObject(target) {\n  const nested = {};\n\n  Object.keys(target).forEach((path) =\u003e set(nested, path, target[path]));\n\n  return nested;\n}\n\nconsole.log(flatToNestedObject(from));\n// {\n//   en: { messages: { hello: 'hello' } },\n//   'pt-BR': { messages: { hello: 'olá' } }\n// }\n```\n\nYou can also use something like [flat](https://github.com/hughsk/flat) to\nperform the same transformation.\n\n## Maintainer\n\n- [Nando Vieira](https://github.com/fnando)\n\n## Contributors\n\n- https://github.com/fnando/i18n/contributors\n\n## Contributing\n\nFor more details about how to contribute, please read\nhttps://github.com/fnando/i18n/blob/main/CONTRIBUTING.md.\n\n## License\n\nThe gem is available as open source under the terms of the\n[MIT License](https://opensource.org/licenses/MIT). A copy of the license can be\nfound at https://github.com/fnando/i18n/blob/main/LICENSE.md.\n\n## Code of Conduct\n\nEveryone interacting in the i18n project's codebases, issue trackers, chat rooms\nand mailing lists is expected to follow the\n[code of conduct](https://github.com/fnando/i18n/blob/main/CODE_OF_CONDUCT.md).\n","funding_links":["https://github.com/sponsors/fnando","https://paypal.me/nandovieira/🍕"],"categories":["TypeScript"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffnando%2Fi18n","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffnando%2Fi18n","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffnando%2Fi18n/lists"}