{"_id":"@cybernetex/kbn-i18n","_rev":"1-ea8c55bb131b3ad31863727342954632","name":"@cybernetex/kbn-i18n","dist-tags":{"latest":"1.0.0"},"versions":{"1.0.0":{"name":"@cybernetex/kbn-i18n","browser":"./target/web/browser.js","main":"./target/node/index.js","types":"./target/types/index.d.ts","version":"1.0.0","license":"Apache-2.0","scripts":{"build":"node scripts/build","kbn:bootstrap":"node scripts/build --source-maps","kbn:watch":"node scripts/build --watch --source-maps"},"devDependencies":{"@babel/cli":"7.4.4","@babel/core":"7.4.5","@babel/plugin-proposal-class-properties":"7.4.4","@babel/plugin-proposal-object-rest-spread":"7.4.4","@babel/preset-env":"7.4.5","@babel/preset-react":"7.0.0","@babel/preset-typescript":"7.3.3","@kbn/dev-utils":"1.0.0","@types/intl-relativeformat":"^2.1.0","@types/react-intl":"^2.3.15","del":"^4.0.0","getopts":"^2.2.4","supports-color":"^7.0.0","typescript":"3.5.3"},"dependencies":{"intl-format-cache":"^2.1.0","intl-messageformat":"^2.2.0","intl-relativeformat":"^2.1.0","prop-types":"^15.6.2","react":"^16.6.0","react-intl":"^2.8.0"},"description":"Kibana relies on several UI frameworks (ReactJS and AngularJS) and requires localization in different environments (browser and NodeJS). Internationalization engine is framework agnostic and consumable in all parts of Kibana (ReactJS, AngularJS and NodeJS","_id":"@cybernetex/kbn-i18n@1.0.0","_npmVersion":"6.4.1","_nodeVersion":"10.15.2","_npmUser":{"name":"freefood89","email":"freefood89@gmail.com"},"dist":{"integrity":"sha512-1fQpqmaew0lRxgUgwaZuwS0bhEL6rJL20K0QyVvlceWcKsIUFeFYpyEzi0XxcV/EQ4k31I2O9BeQ1nLCu1QsnQ==","shasum":"2ea861d8178ed3b48112782d3315ac96b967fd20","tarball":"https://registry.npmjs.org/@cybernetex/kbn-i18n/-/kbn-i18n-1.0.0.tgz","fileCount":104,"unpackedSize":334656,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdV1ubCRA9TVsSAnZWagAA560QAJD/nQKF+thYNLtqpTlb\npitoiBOfMfxwVEqqmVpBFUViq8FXcXCdBT+kO/D8csOcfhWErd8015NqH0VV\nGvj6sr+TkQfrGc200XASQzhIQrfsF+zQ76RdgKv5N4FdJMgURrrUpqMk6zF9\nwn6SPEMYkGbwkrUlxAB7m/ibZ/NbQ/7xgOIov+3KG2BU80OOy1Sg8svIswmk\nbHnulJx0Di5NkrZVlLZz3cALWhfumE6LcOPywWaDHSLCWoLBjFxTiy8iEh8w\nRmIWa4V6tdtkcDPHFCCW+4vXIzYv9guzoEwLoA9Xw2uIVJ79ktt7p3L9lA2+\n+KYIJ1wmTJ0caKvbvaNJioG+3829t0YH3+qsOjAB+EZuBeHRGLdFwjUW1Vvi\nIBXUMZ0MmsMSAHSsE5ey+bULgpoUx7lq54DFwirk3va5xI28j6zR26elWG+B\nfpR5D9YvTjAmlNkjLweSQgFO9tnIN384DOxr9jm/OeNY3A9Pucxkw0Mv4fC1\nNG6shkb3AoyRVBVdNQ5CN1WCP62IJ4pjZ+7F3h94pCcUyrFle4ZN8Mo2Gj6W\nzrG3q5oQBPbDiz3f48ZbOe7MNxWZwqW02aUHby/PIGxwTRDf80YicV+U0Vqy\nlJWDaeJocf+DirCPJ7uOtjtBTgLaMUFgqW8u1PikGYWWfYMkimhOSrfe92G1\nC2IL\r\n=Qzmv\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIAWVs4I3F+NO3wxQrfedk41V4adDThDAxW50jpsm+F/wAiAyhfT5++62BsseRnKHPzNjYFJTircmvf31/GfWlaIQjA=="}]},"maintainers":[{"name":"freefood89","email":"freefood89@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/kbn-i18n_1.0.0_1566006170352_0.2157048544420499"},"_hasShrinkwrap":false}},"time":{"created":"2019-08-17T01:42:50.168Z","1.0.0":"2019-08-17T01:42:50.497Z","modified":"2022-04-05T02:25:33.815Z"},"maintainers":[{"name":"freefood89","email":"freefood89@gmail.com"}],"description":"Kibana relies on several UI frameworks (ReactJS and AngularJS) and requires localization in different environments (browser and NodeJS). Internationalization engine is framework agnostic and consumable in all parts of Kibana (ReactJS, AngularJS and NodeJS","license":"Apache-2.0","readme":"# I18n\n\nKibana relies on several UI frameworks (ReactJS and AngularJS) and\nrequires localization in different environments (browser and NodeJS).\nInternationalization engine is framework agnostic and consumable in\nall parts of Kibana (ReactJS, AngularJS and NodeJS). In order to simplify\ninternationalization in UI frameworks, the additional abstractions are\nbuilt around the I18n engine: `react-intl` for React and custom\ncomponents for AngularJS. [React-intl](https://github.com/yahoo/react-intl)\nis built around [intl-messageformat](https://github.com/yahoo/intl-messageformat),\nso both React and AngularJS frameworks use the same engine and the same\nmessage syntax.\n\n## Localization files\n\nLocalization files are JSON files.\n\nUsing comments can help to understand which section of the application\nthe localization key is used for. Also `namespaces`\nare used in order to simplify message location search. For example, if\nwe are going to translate the title of `/management/sections/objects/_objects.html`\nfile, we should use message path like this: `'management.objects.objectsTitle'`.\n\nEach Kibana plugin has a separate folder with translation files located at\n```\n{path/to/plugin}/translations/{locale}.json\n```\n\nwhere `locale` is [ISO 639 language code](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes).\n\nFor example:\n```\nsrc/legacy/core_plugins/kibana/translations/fr.json\n```\n\nThe engine scans `x-pack/legacy/plugins/*/translations`, `src/core_plugins/*/translations`, `plugins/*/translations` and `src/legacy/ui/translations` folders on initialization, so there is no need to register translation files.\n\nThe engine uses a `config/kibana.yml` file for locale resolution process. If locale is\ndefined via `i18n.locale` option in `config/kibana.yml` then it will be used as a base\nlocale, otherwise i18n engine will fall back to `en`. The `en` locale will also be used\nif translation can't be found for the base non-English locale.\n\nOne of our technical requirements is to have default messages in the templates\nthemselves, and those messages will always be in English, so we don't have to keep\n`en.json` file in repository. We can generate that file from `defaultMessage`s\ndefined inline.\n\n__Note:__ locale defined in `i18n.locale` and the one used for translation files should\nmatch exactly, e.g. `i18n.locale: zh` and `.../translations/zh-CN.json` won't match and\ndefault English translations will be used, but `i18n.locale: zh-CN` and`.../translations/zh-CN.json`\nor `i18n.locale: zh` and `.../translations/zh.json` will work as expected.\n\n__Note:__ locale should look like `zh-CN` where `zh` - lowercase two-letter or three-letter ISO-639 code\nand `CN` - uppercase two-letter ISO-3166 code (optional).\n[ISO-639](https://www.iso.org/iso-639-language-codes.html) and [ISO-3166](https://www.iso.org/iso-3166-country-codes.html) codes should be separated with `-` character.\n\n## I18n engine\n\nI18n engine is the platform agnostic abstraction that helps to supply locale\ndata to UI frameworks and provides methods for the direct translation.\n\nHere is the public API exposed by this engine:\n\n- `addMessages(messages: Map<string, string>, [locale: string])` - provides a way to register\ntranslations with the engine\n- `getMessages()` - returns messages for the current language\n- `setLocale(locale: string)` - tells the engine which language to use by given\nlanguage key\n- `getLocale()` - returns the current locale\n- `setDefaultLocale(locale: string)` - tells the library which language to fallback\nwhen missing translations\n- `getDefaultLocale()` - returns the default locale\n- `setFormats(formats: object)` - supplies a set of options to the underlying formatter.\nFor the detailed explanation, see the section below\n- `getFormats()` - returns current formats\n- `getRegisteredLocales()` - returns array of locales having translations\n- `translate(id: string, { values: object, defaultMessage: string, description: string })` –\ntranslate message by id. `description` is optional context comment that will be extracted\nby i18n tools and added as a comment next to translation message at `defaultMessages.json`.\n- `init(messages: Map<string, string>)` - initializes the engine\n\n#### I18n engine internals\n\nThe engine uses the ICU Message syntax and works for all CLDR languages which\nhave pluralization rules defined. It's built around `intl-messageformat` package\nwhich exposes `IntlMessageFormat` class. Messages are provided into the constructor\nas a string message, or a pre-parsed AST object.\n\n```js\nimport IntlMessageFormat from 'intl-messageformat';\n\nconst msg = new IntlMessageFormat(message, locales, [formats]);\n```\n\nThe string `message` is parsed, then stored internally in a\ncompiled form that is optimized for the `format()` method to\nproduce the formatted string for displaying to the user.\n\n```js\nconst output = msg.format(values);\n```\n\n`formats` parameter in `IntlMessageFormat` constructor allows formatting numbers\nand dates/times in messages using `Intl.NumberFormat` and `Intl.DateTimeFormat`,\nrespectively.\n\n```js\nconst msg = new IntlMessageFormat('The price is: {price, number, USD}', 'en-US', {\n  number: {\n    USD: {\n      style   : 'currency',\n      currency: 'USD',\n    },\n  },\n});\n\nconst output = msg.format({ price: 100 });\n\nconsole.log(output); // => \"The price is: $100.00\"\n```\n\nIn this example, we're defining a USD number format style which is passed to\nthe underlying `Intl.NumberFormat` instance as its options.\n[Here](https://github.com/yahoo/intl-messageformat/blob/master/src/core.js#L62)\nyou can find default format options used as the prototype of the formats\nprovided to the constructor.\n\nCreating instances of `IntlMessageFormat` is expensive.\n[Intl-format-cache](https://github.com/yahoo/intl-format-cache)\nlibrary is simply to make it easier to create a cache of format\ninstances of a particular type to aid in their reuse. Under the\nhood, this package creates a cache key based on the arguments passed\nto the memoized constructor.\n\n```js\nimport memoizeIntlConstructor from 'intl-format-cache';\n\nconst getMessageFormat = memoizeIntlConstructor(IntlMessageFormat);\n```\n\n## Vanilla JS\n\n`Intl-messageformat` package assumes that the\n[Intl](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl)\nglobal object exists in the runtime. `Intl` is present in all modern\nbrowsers and Node.js 0.10+. In order to load i18n engine\nin Node.js we should simply `import` this module (in Node.js, the\n[data](https://github.com/yahoo/intl-messageformat/tree/master/dist/locale-data)\nfor all 200+ languages is loaded along with the library) and pass the translation\nmessages into `init` method:\n\n```js\nimport { i18n } from '@kbn/i18n';\n\ni18n.init(messages);\n```\n\nOne common use-case is that of internationalizing a string constant. Here's an\nexample of how we'd do that:\n\n```js\nimport { i18n } from '@kbn/i18n';\n\nexport const HELLO_WORLD = i18n.translate('hello.wonderful.world', {\n  defaultMessage: 'Greetings, planet Earth!',\n});\n```\n\nOne more example with a parameter:\n\n```js\nimport { i18n } from '@kbn/i18n';\n\nexport function getGreetingMessage(userName) {\n  return i18n.translate('hello.wonderful.world', {\n    defaultMessage: 'Greetings, {name}!',\n    values: { name: userName },\n    description: 'This is greeting message for main screen.'\n  });\n}\n```\n\nWe're also able to use all methods exposed by the i18n engine\n(see [I18n engine](#i18n-engine) section above for more details).\n\n## React\n\n[React-intl](https://github.com/yahoo/react-intl) library is used for internalization\nReact part of the application. It provides React components and an API to format\ndates, numbers, and strings, including pluralization and handling translations.\n\nReact Intl uses the provider pattern to scope an i18n context to a tree of components.\n`IntlProvider` component is used to setup the i18n context for a tree. After that we\nare able to use `FormattedMessage` component in order to translate messages.\n`IntlProvider` should wrap react app's root component (inside each react render method).\n\nIn order to translate messages we need to use `I18nProvider` component that\nuses I18n engine under the hood:\n\n```js\nimport React from 'react';\nimport ReactDOM from 'react-dom';\nimport { I18nProvider } from '@kbn/i18n/react';\n\nReactDOM.render(\n  <I18nProvider>\n    <RootComponent>\n      ...\n    </RootComponent>\n  </I18nProvider>,\n  document.getElementById('container')\n);\n```\n\nAfter that we can use `FormattedMessage` components inside `RootComponent`:\n```jsx\nimport React, { Component } from 'react';\nimport { FormattedMessage } from '@kbn/i18n/react';\n\nclass RootComponent extends Component {\n  constructor(props) {\n    super(props);\n\n    this.state = {\n      name: 'Eric',\n      unreadCount: 1000,\n    };\n  }\n\n  render() {\n    const {\n      name,\n      unreadCount,\n    } = this.state;\n\n    return (\n      <p>\n        <FormattedMessage\n          id=\"welcome\"\n          defaultMessage=\"Hello {name}, you have {unreadCount, number} {unreadCount, plural,\n            one {message}\n            other {messages}\n          }\"\n          values={{name: <b>{name}</b>, unreadCount}}\n        />\n        ...\n      </p>\n    );\n  }\n}\n```\n\nOptionally we can pass `description` prop into `FormattedMessage` component.\nThis prop is optional context comment that will be extracted by i18n tools\nand added as a comment next to translation message at `defaultMessages.json`\n\n**NOTE:** To minimize the chance of having multiple `I18nProvider` components in the React tree, try to use `I18nProvider` only to wrap the topmost component that you render, e.g. the one that's passed to `reactDirective` or `ReactDOM.render`.\n\n### FormattedRelative\n\n`FormattedRelative` expects several attributes (read more [here](https://github.com/yahoo/react-intl/wiki/Components#formattedrelative)), including\n\n- `value` that can be parsed as a date,\n- `formats` that should be one of `'years' | 'months' | 'days' | 'hours' | 'minutes' | 'seconds'` (this options are configured in [`formats.ts`](./src/core/formats.ts))\n-  etc.\n\nIf `formats` is not provided then it will be chosen automatically:\\\n`x seconds ago` for `x < 60`, `1 minute ago` for `60 <= x < 120`, etc.\n\n```jsx\n<FormattedRelative\n  value={Date.now() - 90000}\n  format=\"seconds\"\n/>\n```\nInitial result: `90 seconds ago`\n```jsx\n<FormattedRelative\n  value={Date.now() - 90000}\n/>\n```\nInitial result: `1 minute ago`\n\n### Attributes translation in React\n\nThe long term plan is to rely on using `FormattedMessage` and `i18n.translate()` by statically importing `i18n` from the `@kbn/i18n` package. **Avoid using `injectI18n` and rely on `i18n.translate()` instead.**\n\nReact wrapper provides an ability to inject the imperative formatting API into a React component via its props using `injectI18n` Higher-Order Component. This should be used when your React component needs to format data to a string value where a React element is not suitable; e.g., a `title` or `aria` attribute. In order to use it you should wrap your component with `injectI18n` Higher-Order Component. The formatting API will be provided to the wrapped component via `props.intl`.\n\nReact component as a pure function:\n\n```js\nimport React from 'react';\nimport { injectI18n, intlShape } from '@kbn/i18n/react';\n\nexport const MyComponent = injectI18n({ intl }) => (\n  <input\n    type=\"text\"\n    placeholder={intl.formatMessage(\n      {\n        id: 'welcome',\n        defaultMessage: 'Hello {name}, you have {unreadCount, number}\\\n{unreadCount, plural, one {message} other {messages}}',\n        description: 'Message description',\n      },\n      { name, unreadCount }\n    )}\n  />\n));\n\nMyComponent.WrappedComponent.propTypes = {\n  intl: intlShape.isRequired,\n};\n```\n\nReact component as a class:\n\n```js\nimport React from 'react';\nimport { injectI18n, intlShape } from '@kbn/i18n/react';\n\nexport const MyComponent = injectI18n(\n  class MyComponent extends React.Component {\n    static propTypes = {\n      intl: intlShape.isRequired,\n    };\n\n    render() {\n      const { intl } = this.props;\n\n      return (\n        <input\n          type=\"text\"\n          placeholder={intl.formatMessage({\n            id: 'kbn.management.objects.searchPlaceholder',\n            defaultMessage: 'Search',\n          })}\n        />\n      );\n    }\n  }\n);\n```\n\n## AngularJS\n\nThe long term plan is to rely on using `i18n.translate()` by statically importing `i18n` from the `@kbn/i18n` package. **Avoid using the `i18n` filter and the `i18n` service injected in controllers, directives, services.**\n\nAngularJS wrapper has 4 entities: translation `provider`, `service`, `directive`\nand `filter`. Both the directive and the filter use the translation `service`\nwith i18n engine under the hood.\n\nThe translation `provider` is used for `service` configuration and\nhas the following methods:\n- `addMessages(messages: Map<string, string>, [locale: string])` - provides a way to register\ntranslations with the library\n- `setLocale(locale: string)` - tells the library which language to use by given\nlanguage key\n- `getLocale()` - returns the current locale\n- `setDefaultLocale(locale: string)` - tells the library which language to fallback\nwhen missing translations\n- `getDefaultLocale()` - returns the default locale\n- `setFormats(formats: object)` - supplies a set of options to the underlying formatter\n- `getFormats()` - returns current formats\n- `getRegisteredLocales()` - returns array of locales having translations\n- `init(messages: Map<string, string>)` - initializes the engine\n\nThe translation `service` provides only one method:\n- `i18n(id: string, { values: object, defaultMessage: string, description: string })` –\ntranslate message by id\n\nThe translation `filter` is used for attributes translation and has\nthe following syntax:\n```\n{{ ::'translationId' | i18n: { values: object, defaultMessage: string, description: string } }}\n```\n\nWhere:\n- `translationId` - translation id to be translated\n- `values` - values to pass into translation\n- `defaultMessage` - will be used unless translation was successful (the final\n  fallback in english, will be used for generating `en.json`)\n- `description` - optional context comment that will be extracted by i18n tools\nand added as a comment next to translation message at `defaultMessages.json`\n\nThe translation `directive` has the following syntax:\n```html\n<ANY\n  i18n-id=\"{string}\"\n  i18n-default-message=\"{string}\"\n  [i18n-values=\"{object}\"]\n  [i18n-description=\"{string}\"]\n></ANY>\n```\n\nWhere:\n- `i18n-id` - translation id to be translated\n- `i18n-default-message` - will be used unless translation was successful\n- `i18n-values` - values to pass into translation\n- `i18n-description` - optional context comment that will be extracted by i18n tools\nand added as a comment next to translation message at `defaultMessages.json`\n\nIf HTML rendering in `i18n-values` is required then value key in `i18n-values` object\nshould have `html_` prefix. Otherwise the value will be inserted to the message without\nHTML rendering.\\\nExample:\n```html\n<p\n  i18n-id=\"namespace.id\"\n  i18n-default-message=\"Text with an emphasized {text}.\"\n  i18n-values=\"{\n    html_text: '<em>text</em>',\n  }\"\n></p>\n```\n\nAngular `I18n` module is placed into `autoload` module, so it will be\nloaded automatically. After that we can use i18n directive in Angular templates:\n```html\n<span\n  i18n-id=\"welcome\"\n  i18n-default-message=\"Hello!\"\n></span>\n```\n\nIn order to translate attributes in AngularJS we should use `i18nFilter`:\n```html\n<input\n  type=\"text\"\n  placeholder=\"{{ ::'kbn.management.objects.searchAriaLabel' | i18n: {\n    defaultMessage: 'Search { title } Object',\n    values: { title }\n  } }}\"\n>\n```\n\n## I18n tools\n\nIn order to simplify localization process, some additional tools were implemented:\n- tool for verifying all translations have translatable strings and extracting default messages from templates\n- tool for verifying translation files and integrating them to Kibana\n\n[I18n tools documentation](../../src/dev/i18n/README.md)\n","readmeFilename":"README.md"}