Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/synacor/preact-i18n
Simple localization for Preact.
https://github.com/synacor/preact-i18n
Last synced: 3 months ago
JSON representation
Simple localization for Preact.
- Host: GitHub
- URL: https://github.com/synacor/preact-i18n
- Owner: synacor
- License: bsd-3-clause
- Created: 2017-06-09T18:32:11.000Z (over 7 years ago)
- Default Branch: master
- Last Pushed: 2023-12-27T12:05:11.000Z (11 months ago)
- Last Synced: 2024-07-18T06:44:19.670Z (4 months ago)
- Language: JavaScript
- Size: 417 KB
- Stars: 206
- Watchers: 10
- Forks: 18
- Open Issues: 10
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# preact-i18n 🌎 [![npm](https://img.shields.io/npm/v/preact-i18n.svg?style=flat)](https://npm.im/preact-i18n) [![travis](https://travis-ci.org/synacor/preact-i18n.svg?branch=master)](https://travis-ci.org/synacor/preact-i18n) [![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fsynacor%2Fpreact-i18n.svg?type=shield)](https://app.fossa.io/projects/git%2Bgithub.com%2Fsynacor%2Fpreact-i18n?ref=badge_shield)
**Simple localization for Preact.**
- Tiny: about 1.3kb gzipped
- Supports dictionary and key scopes/namespaces while maintaining a global dictionary
- Supports nested dictionaries:
- Wrap your component in a default dictionary and scope key
- Wrap it again later on (in an app!) to override the defaults
- Supports pluralization of strings using nested objects.
- Supports template `{{fields}}` in definition values
- Has a companion [ESLint plugin](https://www.npmjs.com/package/eslint-plugin-preact-i18n) to help catch bugs early* * *
- [Installation](#installation)
- [Getting Started](#getting-started)
- [Fallback Text](#fallback-text)
- [Pluralization and Templating](#pluralization-and-templating)
- [ESLint Plugin](#eslint-plugin)
- [API](#api)## Preact Version Support
By default, the `master` branch of this repo supports preact 9 and below, and is published in normal patch/minor/major releases to the `latest` tag in npm. Support for preact X (versions 10+ of preact) is handled in the `preactX` branch and are always published to the `preactx` tag in npm. When preact X obtains widespread adoption, the `master` branch of this project will support preact X and a new major version under `latest` tag will be published to in npm.
## Installation
```sh
npm install --save preact-i18n# For TypeScript Definitions
npm install --save-dev @types/preact-i18n
```## Getting Started
1. Create a definition. Typically JSON files, we'll call ours `fr.json`:
```json
{
"news": {
"title": "Nouvelles du Monde",
"totalStories": {
"none": "Aucun article",
"one": "Un article",
"many": "{{count}} articles"
}
}
}
```2. Expose the definition to your whole app via ``:
```js
import { IntlProvider } from 'preact-i18n';
import definition from './fr.json';render(
);
```3. Use `` to translate string literals:
```js
import { Text } from 'preact-i18n';// Assume the "stories" prop is a list of news stories.
const App = ({ stories=[] }) => (
{/* Default fallback text example: */}
World News
{/* Pluralization example: */}
);
```That's it!
### Fallback Text
Rendering our example app with an empty definition _(or without the Provider)_ will attempt to use any text contained within `..` as fallback text.
In our example, this would mean rendering without a definition for `news.title` would produce `
World News
`.If we provide a definition that has a `title` key inside a `news` object, that value will be rendered instead.
### Pluralization and Templating
In our example, `` is using `` as a convenient way to do pluralization and templating. In our definition, `news.totalStories` is an Object with pluralization keys. The values in that object will be selected based on an integer `plural` prop passed to ``.
Any definition value _(including pluralization values)_ can contain `{{field}}` placeholders. These placeholders get replaced with matched keys in an object passed as the `fields` prop. In our example, the "many" plural form is such a template - it will render `"5 articles"` when `fields={{ count: 5 }}`.
The available forms for specifying pluralization values are as follows:
- `"key": { "singular":"apple", "plural":"apples" }`
- `"key": { "none":"no apples", "one":"apple", "many":"apples" }`
- `"key": { "zero":"no apples", "one":"apple", "other":"apples" }`
- `"key": ["apples", "apple"]`Taking `` from our example:
- `<.. plural={0}>` renders `Aucun article` _(no articles)_
- `<.. plural={1}>` renders `Un article` _(one article)_
- `<.. plural={2} fields={{ count: 2 }}>` renders `2 articles`
- `<.. plural={3} fields={{ count: 3 }}>` renders `3 articles`In addition to [``](#Text), [`withText()`](#withText) and [``](#Localizer) provide ways to translate more than just display text - HTML attributes, component props, arbitrary Strings, etc.
## ESLint Plugin
A companion ESLint plugin exists, [eslint-plugin-preact-i18n](https://www.npmjs.com/package/eslint-plugin-preact-i18n), which has several rules that help spot common issues like un-i18n'd text, misconfigured tags, and missing keys, that are beneficial in spotting defects early and ensuring that your application is properly i18n'd.
* * *
## API
#### Table of Contents
- [IntlProvider](#intlprovider)
- [Parameters](#parameters)
- [Examples](#examples)
- [Localizer](#localizer)
- [Parameters](#parameters-1)
- [Examples](#examples-1)
- [MarkupText](#markuptext)
- [Parameters](#parameters-2)
- [Examples](#examples-2)
- [Text](#text)
- [Parameters](#parameters-3)
- [Examples](#examples-3)
- [withText](#withtext)
- [Parameters](#parameters-4)
- [Examples](#examples-4)
- [intl](#intl)
- [Parameters](#parameters-5)### IntlProvider
`` is a nestable internationalization definition provider.
It exposes an Intl scope & definition into the tree,
making them available to descendant components.> **Note:** When nested, gives precedence to keys higher up the tree!
> This means lower-level components can set their defaults by wrapping themselves
> in an ``, but still remain localizable by their parent components.#### Parameters
- `props`
- `props.scope` **[String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)?** Nest `definition` under a root key, and set the active scope for the tree (essentially prefixing all `` keys).
- `props.mark` **[Boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** If `true`, all `` elements will be shown with a red/green background indicating whether they have valid Intl keys. (optional, default `false`)
- `props.definition` **[Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)** Merge the given definition into the current intl definition, giving the _current_ definition precedence (i.e., only adding keys, acting as defaults) (optional, default `{}`)#### Examples
```javascript
// generally imported from a JSON file:
let definition = {
foo: 'Le Feux'
};The Foo
// This will render the text:
"Le Feux"
```### Localizer
`` is a Compositional Component.
It "renders" out any `` values in its child's props.#### Parameters
- `props` **[Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)**
- `props.children` **[Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)** Child components with props to localize.
- `context` **[Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)**
- `context.intl` **[Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)** [internal] dictionary and scope info#### Examples
```javascript
} />
// produces:
```
```javascript
Open Source Software}>
OSS
// produces:
OSS
```### MarkupText
`` is just like [Text](#text) but it can also contain html markup in rendered strings. It wraps its contents in a `` tag.
#### Parameters
- `props` **[Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)** props
- `props.id` **[String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** Key to look up in intl dictionary, within any parent scopes (`$scope1.$scope2.$id`)
- `props.fields` **[Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)** Values to inject into template `{{fields}}`. Values in the `fields` object will be coerced to strings, with the exception of `` nodes which will be resolved to their translated value (optional, default `{}`)
- `props.plural` **[Number](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number)?** Integer "count", used to select plural forms
- `context` **[Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)**
- `context.intl` **[Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)** [internal] dictionary and scope info#### Examples
```javascript
// If there is no dictionary in context..
The Foo
// ..produces the vnode:
The Foo
``````javascript
// Given a dictionary and some fields..
{{bar}}' }}>
The Foo// ..produces the vnode:
Le Feux BEAR
``````javascript
// Within a scope, both `id` and the definition are namespaced..
Feux' }}>
The Foo// ..produces the vnode:
Le Feux
``````javascript
// renders nothing if there is no key match and no fallback
// ..produces the vnode:
```### Text
`` renders internationalized text.
It attempts to look up translated values from a dictionary in context.Template strings can contain `{{field}}` placeholders,
which injects values from the `fields` prop.When string lookup fails, renders its children as fallback text.
#### Parameters
- `props` **[Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)** props
- `props.id` **[String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** Key to look up in intl dictionary, within any parent scopes (`$scope1.$scope2.$id`)
- `props.plural` **[Number](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number)?** Integer "count", used to select plural forms
- `props.fields` **[Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)** Values to inject into template `{{fields}}`. Values in the `fields` object will be coerced to strings, with the exception of `` nodes which will be resolved to their translated value (optional, default `{}`)
- `props.children`
- `context` **[Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)**
- `context.intl` **[Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)** [internal] dictionary and scope info#### Examples
```javascript
// If there is no dictionary in context..
The Foo
// ..produces the text:
"The Foo"
``````javascript
// Given a dictionary and some fields..The Foo
// ..produces the text:
"Le Feux BEAR"
``````javascript
// Within a scope, both `id` and the definition are namespaced..The Foo
// ..produces the text:
"Le Feux"
```### withText
`@withText()` is a Higher Order Component, often used as a decorator.
It wraps a child component and passes it translations
based on a mapping to the dictionary & scope in context.#### Parameters
- `mapping` **([Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object) \| [Function](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/function) \| [String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String))** Maps prop names to intl keys (or `` nodes).
#### Examples
```javascript
@withText({
placeholder: 'user.placeholder'
})
class Foo {
// now the `placeholder` prop is our localized String:
render({ placeholder }) {
return
}
}
``````javascript
@withText({
placeholder: fallback text
})
class Foo {
render({ placeholder }) {
return
}
}
``````javascript
@withText('user.placeholder')
class Foo {
// for Strings/Arrays, the last path segment becomes the prop name:
render({ placeholder }) {
return
}
}
```Works with functional components, too
```javascript
const Foo = withText('user.placeholder')( props =>
)
```getWrappedComponent() returns wrapped child Component
```javascript
;
const Foo = () =>
const WrappedFoo = withText('user.placeholer')(Foo);
WrappedFoo.getWrappedComponent() === Foo; // true
```### intl
Higher-order function that creates an `` wrapper component for the given component. It
takes two forms depending on how many arguments it's given:
It can take a functional form like:
intl(ComponentToWrap, options)or it can take an annotation form like:
#### Parameters
- `Child`
- `options` **[Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)** If there are two arguments, the second argument is Passed as `props` to ``
- `options.scope` Nest `definition` under a root key, and set the active scope for the tree (essentially prefixing all `` keys).
- `options.definition` Merge the given definition into the current intl definition, giving the _current_ definition precedence (i.e., only adding keys, acting as defaults) (optional, default `{}`)## License
[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fsynacor%2Fpreact-i18n.svg?type=large)](https://app.fossa.io/projects/git%2Bgithub.com%2Fsynacor%2Fpreact-i18n?ref=badge_large)