From 69ec477ffdcfc50f8d33e90c7e77700732c5d5e8 Mon Sep 17 00:00:00 2001 From: Christian Kaisermann Date: Wed, 15 Jan 2020 23:06:42 -0300 Subject: [PATCH] =?UTF-8?q?docs:=20=E2=9C=8F=EF=B8=8F=20move=20docs=20out?= =?UTF-8?q?=20of=20wiki?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 3 +- README.md | 2 +- docs/CLI.md | 13 +++ docs/Dictionary.md | 31 ++++++ docs/FAQ.md | 34 +++++++ docs/Formatting.md | 179 +++++++++++++++++++++++++++++++++++ docs/Getting Started.md | 124 ++++++++++++++++++++++++ docs/Locale.md | 60 ++++++++++++ docs/Methods.md | 202 ++++++++++++++++++++++++++++++++++++++++ docs/Migration.md | 112 ++++++++++++++++++++++ 10 files changed, 757 insertions(+), 3 deletions(-) create mode 100644 docs/CLI.md create mode 100644 docs/Dictionary.md create mode 100644 docs/FAQ.md create mode 100644 docs/Formatting.md create mode 100644 docs/Getting Started.md create mode 100644 docs/Locale.md create mode 100644 docs/Methods.md create mode 100644 docs/Migration.md diff --git a/.gitignore b/.gitignore index 191e7e4..ee1bb96 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ node_modules *.log dist/ -coverage/ -docs/ \ No newline at end of file +coverage/ \ No newline at end of file diff --git a/README.md b/README.md index 780adcd..88f2fd3 100644 --- a/README.md +++ b/README.md @@ -45,4 +45,4 @@ } ``` -### [Go see the documentation](https://github.com/kaisermann/svelte-i18n/wiki) +### [Go see the documentation](https://github.com/kaisermann/svelte-i18n/blob/master/docs) diff --git a/docs/CLI.md b/docs/CLI.md new file mode 100644 index 0000000..3cca63e --- /dev/null +++ b/docs/CLI.md @@ -0,0 +1,13 @@ +`svelte-i18n` provides a command-line interface to extract all your messages to the `stdout` or to a specific JSON file. + +```bash +$ svelte-i18n extract [options] [output-file] +``` + +### Options + +- `-s, --shallow` - extract all messages to a shallow object, without creating nested objects. Default: `false`. + +- `--overwrite` - overwrite the content of the `output` file instead of just appending missing properties. Default: `false`. + +- `-c, --configDir` - define the directory of a [`svelte.config.js`](https://github.com/UnwrittenFun/svelte-vscode#generic-setup) in case your svelte components need to be preprocessed. diff --git a/docs/Dictionary.md b/docs/Dictionary.md new file mode 100644 index 0000000..a9eecd3 --- /dev/null +++ b/docs/Dictionary.md @@ -0,0 +1,31 @@ +`import { dictionary } from 'svelte-i18n'` + +### `$dictionary` + +The `$dictionary` store is responsible for holding all loaded message definitions for each locale. A dictionary of messages can be a shallow or deep object: + +###### `en-shallow.json` + +```json +{ + "title": "Sign up", + "field.name": "Name", + "field.birth": "Date of birth", + "field.genre": "Genre" +} +``` + +###### `en-deep.json` + +```json +{ + "title": "Sign up", + "field": { + "name": "Name", + "birth": "Date of birth", + "genre": "Genre" + } +} +``` + +It's recommended to use the [`addMessages()`](/docs/Methods.md#addmessages) and [`register()`](/docs/Methods.md#register) methods to add new message dictionaries to your app. diff --git a/docs/FAQ.md b/docs/FAQ.md new file mode 100644 index 0000000..5ddb479 --- /dev/null +++ b/docs/FAQ.md @@ -0,0 +1,34 @@ +##### `'this' keyword is equivalent to 'undefined'` + +When using `Rollup` as a bundler, you're possibly seeing this warning. It's related to the output of the typescript compiler used to transpile the `intl-messageformat` package. In this case, it's harmless and you can learn to live with it on your terminal or teach your rollup to ignore this kind of warning: + +```js +// modified version of onwarn provided by sapper projects +const onwarn = (warning, onwarn) => { + if ( + (warning.code === 'CIRCULAR_DEPENDENCY' && + /[/\\]@sapper[/\\]/.test(warning.message)) + ) { + return + } + + // ignores the annoying this is undefined warning + if(warning.code === 'THIS_IS_UNDEFINED') { + return + } + + onwarn(warning) +} + +export default { + client: { + ..., + onwarn, + }, + server: { + ..., + onwarn, + }, +} + +``` diff --git a/docs/Formatting.md b/docs/Formatting.md new file mode 100644 index 0000000..0e0f410 --- /dev/null +++ b/docs/Formatting.md @@ -0,0 +1,179 @@ +### Message syntax + +Under the hood, `formatjs` is used for localizing your messages. It allows `svelte-i18n` to support the ICU message syntax. It is strongly recommended to read their documentation about it. + +- [Basic Internationalization Principles](https://formatjs.io/guides/basic-i18n/) +- [Runtime Environments](https://formatjs.io/guides/runtime-environments/) +- [ICU Message Syntax](https://formatjs.io/guides/message-syntax/) + +### `$format` or `$_` or `$t` + +`import { _, t, format } from 'svelte-i18n'` + +The `$format` store is the actual formatter method. It's also aliased as `$_` and `$t` for convenience. To format a message is as simple as executing the `$format` method: + +```svelte + + +

{$_('page_title')}

+``` + +The formatter can be called with two different signatures: + +- `format(messageId: string, options?: MessageObject): string` +- `format(options: MessageObject): string` + +```ts +interface MessageObject { + id?: string + locale?: string + format?: string + default?: string + values?: Record +} +``` + +- `id`: represents the path to a specific message; +- `locale`: forces a specific locale; +- `default`: the default value in case of message not found in the current locale; +- `format`: the format to be used. See [#formats](#formats); +- `values`: properties that should be interpolated in the message; + +You can pass a `string` as the first parameter for a less verbose way of formatting a message. + +If the message id literal value is not in the root of the dicitonary, `.` (dots) are interpreted as a path: + +```jsonc +// en.json +{ + "shallow.prop": "Shallow property", + "deep": { + "property": "Deep property" + } +} +``` + +```svelte +
{$_('shallow.prop')}
+
{$_('deep.prop')}
+``` + +### Formatting utilities + +The formatter method also provides some casing methods: + +- `_.upper` - transforms a localized message into uppercase; +- `_.lower` - transforms a localized message into lowercase; +- `_.capital` - capitalize a localized message; +- `_.title` - transforms the message into title case; + +```html +
{$_.upper('greeting.ask')}
+ + +
{$_.lower('greeting.ask')}
+ + +
{$_.capital('greeting.ask')}
+ + +
{$_.title('greeting.ask')}
+ +``` + +#### `_.time(time: Date, options: MessageObject): string` + +Formats a date object into a time string with the specified format. Please refer to the [#formats](#formats) section to see available formats. + +```html +
{$_.time(new Date(2019, 3, 24, 23, 45))}
+ + +
{$_.time(new Date(2019, 3, 24, 23, 45), { format: 'medium' } )}
+ +``` + +#### `_.date(date: Date, options: MessageObject): string` + +Formats a date object into a string with the specified format. Please refer to the [#formats](#formats) section to see available formats. + +```html +
{$_.date(new Date(2019, 3, 24, 23, 45))}
+ + +
{$_.date(new Date(2019, 3, 24, 23, 45), { format: 'medium' } )}
+ +``` + +#### `_.number(number: number, options: MessageObject): string` + +Formats a number with the specified locale and format. Please refer to the [#formats](#formats) section to see available formats. + +```html +
{$_.number(100000000)}
+ + +
{$_.number(100000000, { locale: 'pt' })}
+ +``` + +### Formats + +`svelte-i18n` comes with a default set of `number`, `time` and `date` formats: + +**Number:** + +- `currency`: `{ style: 'currency' }` +- `percent`: `{ style: 'percent' }` +- `scientific`: `{ notation: 'scientific' }` +- `engineering`: `{ notation: 'engineering' }` +- `compactLong`: `{ notation: 'compact', compactDisplay: 'long' }` +- `compactShort`: `{ notation: 'compact', compactDisplay: 'short' }` + +**Date:** + +- `short`: `{ month: 'numeric', day: 'numeric', year: '2-digit' }` +- `medium`: `{ month: 'short', day: 'numeric', year: 'numeric' }` +- `long`: `{ month: 'long', day: 'numeric', year: 'numeric' }` +- `full`: `{ weekday: 'long', month: 'long', day: 'numeric', year: 'numeric' }` + +**Time:** + +- `short`: `{ hour: 'numeric', minute: 'numeric' }` +- `medium`: `{ hour: 'numeric', minute: 'numeric', second: 'numeric' }` +- `long`: `{ hour: 'numeric', minute: 'numeric', second: 'numeric', timeZoneName: 'short' }` +- `full`: `{ hour: 'numeric', minute: 'numeric', second: 'numeric', timeZoneName: 'short' }` + +### Accessing formatters directly + +`svelte-i18n` also provides a low-level API to access its formatter methods: + +```js +import { + getDateFormatter, + getNumberFormatter, + getTimeFormatter, + getMessageFormatter, +} from 'svelte-i18n' +``` + +By using these methods, it's possible to manipulate values in a more specific way that fits your needs. For example, it's possible to create a method which receives a `date` and returns its relevant date related parts: + +```js +import { getDateFormatter } from 'svelte-i18n' + +const getDateParts = date => + getDateFormatter() + .formatToParts(date) + .filter(({ type }) => type !== 'literal') + .reduce((acc, { type, value }) => { + acc[type] = value + return acc + }, {}) + +getDateParts(new Date(2020, 0, 1)) // { month: '1', day: '1', year: '2020' } +``` + +Check the [methods documentation](/docs/Methods.md#low-level-api) for more information. diff --git a/docs/Getting Started.md b/docs/Getting Started.md new file mode 100644 index 0000000..ac7252e --- /dev/null +++ b/docs/Getting Started.md @@ -0,0 +1,124 @@ +### Getting started + +#### 1. Locale dictionaries + +A locale dictionary is a regular JSON object which contains message definitions for a certain language. + +```jsonc +// en.json +{ + "page_title": "Page titlte", + "sign_in": "Sign in", + "sign_up": "Sign up", +} + +// pt.json +{ + "page_title": "Título da página", + "sign_in": "Entrar", + "sign_up": "Registrar", +} +``` + +#### 2. Adding locale dictionaries + +There are two different ways of adding a new dicitonary of messages to a certain locale: + +##### 2.1 Synchronous + +Just `import`/`require` your locale `.json` files and pass them to the [`addMessages(locale, dict)`](/docs/Methods.md#addmessages) method. + +```js +// src/i18n.js +import { addMessages } from 'svelte-i18n' + +import en from './en.json' +import enUS from './en-US.json' +import pt from './pt.json' + +addMessages('en', en) +addMessages('en-US', enUS) +addMessages('pt', pt) + +// en, en-US and pt are available +``` + +##### 2.2 Asynchronous + +A more performant way to load your dictionaries is to register `loader` methods. This way, only the files registered to the current locale will be loaded. A `loader` is a method which must return a `Promise` that resolves to a `JSON` object. A [`$locale`](/kaisermann/svelte-i18n/Locale) value change will automatically load the registered loaders for the new locale. + +```js +// src/i18n.js +import { register } from 'svelte-i18n' + +register('en', () => import('./en.json')) +register('en-US', () => import('./en-US.json')) +register('pt', () => import('./pt.json')) + +// en, en-US and pt are not available yet +``` + +#### 3. Initializing + +After populating your [`$dictionary`](/docs/Dictionary) with [`addMessages()`](/docs/Methods.md#addmessages) or registering loaders via [`register()`](/docs/Methods.md#register), you are ready to bootstrap the library. You can use [`init()`](/docs/Methods.md#init) to define the fallback locale, initial locale and other options of your app. + +```js +// src/i18n.js +import { register, init } from 'svelte-i18n' + +register('en', () => import('./en.json')) +register('en-US', () => import('./en-US.json')) +register('pt', () => import('./pt.json')) +// en, en-US and pt are not available yet + +init({ + fallbackLocale: 'en', + initialLocale: { + navigator: true, // i.e 'en-US' + }, +}) +// starts loading 'en-US' and 'en' +``` + +_**Note**: If you're using Sapper, remember to also call `init()` on your server side code (`server.js`)._ + +Since we're using `register`, and not `addMessages`, we need to wait for it's loaders to finish before rendering your app. + +In **Svelte**, the [`$isLoading`](/docs/Locale.md#loading) store can help to only show your app after the initial load as shown in [Locale](/docs/Locale.md#loading). + +In **Sapper**, you can use the `preload` static method together with `waitLocale`: + +```svelte + + +``` + +Please note that the `fallbackLocale` is always loaded, independent of the current locale, since only some messages can be missing. + +#### 4. Localizing your app + +After having the initial locale set, you're ready to start localizing your app. Import the [`$format`](/docs/Formatting) method, or any of its aliases, to any component that needs to be translated. Then, just call [`$format`](/docs/Formatting) passing the message `id` on your layout and voila! 🎉 + +```svelte + + + + {$_.upper('page_title')} + + + +``` + +See [Formatting](/docs/Formatting) to read about the supported message syntax. diff --git a/docs/Locale.md b/docs/Locale.md new file mode 100644 index 0000000..d5d6640 --- /dev/null +++ b/docs/Locale.md @@ -0,0 +1,60 @@ +`import { locale } from 'svelte-i18n'` + + + +### `$locale` + +The `locale` store defines what is the current locale. When its value is changed, before updating the actual stored value, `svelte-i18n` sees if there's any message loaders registered for the new locale: + +- If yes, changing the `locale` is an async operation. +- If no, the locale's dictionary is fully loaded and changing the locale is a sync operation. + +The `` attribute is automatically updated to the current locale. + +#### Usage on component + +To change the locale inside a component is as simple as assinging it a new value. + +```svelte + + + + +``` + +#### Usage on regular script + +```js +import { locale } from 'svelte-i18n' + +// Set the current locale to en-US +locale.set('en-US') + +// This is a store, so we can subscribe to its changes +locale.subscribe(() => console.log('locale change')) +``` + +### `$loading` + +While changing the `$locale`, the `$loading` store can be used to detect if the app is currently fetching any enqueued message definitions. + +```svelte + + +{#if loading} + Please wait... +{:else} +