Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 0 additions & 7 deletions .storybook/preview.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,6 @@ import React, { useEffect } from 'react';
import 'react-app-polyfill/ie11';

addParameters({
options: {
storySort: (a, b) => {
return a[1].kind === b[1].kind
? 0
: a[1].id.localeCompare(b[1].id, undefined, { numeric: true, caseFirst: 'upper' });
}
},
passArgsFirst: true,
viewMode: 'docs',
docs: { forceExtractedArgTypes: true },
Expand Down
123 changes: 123 additions & 0 deletions docs/5-Internationalization.stories.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import { Meta } from '@storybook/addon-docs/blocks';

<Meta title="Internationalization" />

# Setup Internationalization (i18n)

UI5 Web Components (for React) aim to be feature rich and with a minimal code footprint at the same time.
In order to achieve this, most UI5 Web Components packages ship their assets as `.json` files while also providing a public module import for them.

**Prerequisite: your `@ui5/webcomponents-react` dependency has to be at least at `0.10.0-rc.2` or newer.**

In order to make your app translatable into various languages, you need to import the following assets:

```js
import '@ui5/webcomponents/dist/Assets.js';
import '@ui5/webcomponents-fiori/dist/Assets.js';
import '@ui5/webcomponents-react/dist/Assets';
```

That's it! You can now test whether the translations work correctly by adding e.g. `?sap-ui-language=de` to your URL for German translations.

<br />
<br />

## How to add custom translations

_Please also read the [UI5 Web Components i18n documentation](https://github.com/SAP/ui5-webcomponents/blob/master/docs/i18n.md)._
_This chapter requires `@ui5/webcomponents@>1.0.0-rc.8`._

**1. Start by creating some `i18n` resources in a directory that can be served, for example:**

| File | Content |
| ------------------------------------ | -------------------------- |
| `assets/messagebundle_de.properties` | `PLEASE_WAIT=Bitte warten` |
| `assets/messagebundle_fr.properties` | `PLEASE_WAIT=Patientez.` |
| `assets/messagebundle_es.properties` | `PLEASE_WAIT=Espere` |
| `assets/messagebundle_en.properties` | `PLEASE_WAIT=Please wait` |

**2. Import the following `i18n`-related modules to your app:**

```js
import '@ui5/webcomponents-base/dist/features/PropertiesFormatSupport.js';
import { registerI18nBundle, fetchI18nBundle, getI18nBundle } from '@ui5/webcomponents-base/dist/i18nBundle.js';
```

The first one provides support for `.properties` files, as used in the example and the second one contains the functions
that will allow you to take advantage of the `i18n` functionality.

**3. Register your message bundles:**

```js
registerI18nBundle('myApp', {
de: './assets/messagebundle_de.properties',
es: './assets/messagebundle_es.properties',
fr: './assets/messagebundle_fr.properties',
en: './assets/messagebundle_en.properties'
});
```

The first argument is an ID that will be used to reference this message bundle and the second, an object,
providing the URLs where the `i18n` assets can be found.

_Note:_ This is just asset registration, no data will be fetched at that point.

**4. Use your translated texts in your components**

Add the following import statement to the component where you want to use translated texts:

```js
import { useI18nText } from '@ui5/webcomponents-react-base/lib/hooks';
```

Now, you can use the `useI18nText` hook in your functional components in order to get your translated texts.

The hook has the following signature:

```js
const translatedTextsArray = useI18nText((messageBundleId: string), (...textsToTranslate: (string | string[])[]));
```

In case you have texts without placeholder values you can use the simple `string` arguments, but if you have parameters
in your message bundle you will have to use the `array` notation (_please see step 6_).
You can mix `string` and `array` arguments in the same call.

Each parameter will be translated one by one and returned in an array in the same order.

**Example:**

```jsx
const MyTranslatedTextComponent = () => {
const [pleaseWaitText, anotherText] = useI18nText('myApp', 'PLEASE_WAIT', 'ANOTHER_TEXT_TO_TRANSLATE');

return (
<div>
<span>{pleaseWaitText}</span>
<p>{anotherText}</p>
</div>
);
};
```

**5. Use texts with placeholder values**

In case you have texts with placeholders in your message bundle, you can pass an array as text parameter to receive
translated text with parameters. In this case, the first entry in the array is the translation key, followed by an
arbitrary number of parameters which should be inserted into the translation.

**Example:**

You have this text in your message bundle:

```properties
CAROUSEL_DOT_TEXT=Item {0} of {1} displayed
```

Your hook call would now look like this:

```js
const [carouselText, pleaseWaitText] = useI18nText('myApp', ['CAROUSEL_DOT_TEXT', 5, 20], 'PLEASE_WAIT');
```

This would resolve this text:<br />
`Item 5 of 20 displayed`
122 changes: 122 additions & 0 deletions docs/6-Efficient-Bundling.stories.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import { Meta } from '@storybook/addon-docs/blocks';

<Meta title="Efficient Bundling" />

# Efficient Bundling

This section describes some options on how to optimize your bundle size.

**Following these steps require you to modify the default `create-react-app` setup. This might result in broken applications!**<br />
**We can't provide any support for custom build setups.**

UI5 Web Components (for React) aim to be feature rich and with a minimal code footprint at the same time, so we are
providing several assets as `.json` files which can be optionally imported (like `themes`, `i18n translations`).
As `create-react-app` is inlining all `.json` files by default, this could result in a very large bundle size.

Here are two options how to improve your bundle size:

## Option 1: Using `react-app-rewired`

[react-app-rewired](https://github.com/timarney/react-app-rewired) is tweaking the `create-react-app` config without
the need to use `eject` or to fork `react-scripts`. <br />
Please read through the projects' [`README`](https://github.com/timarney/react-app-rewired/blob/master/README.md) before continuing.

**Step by Step Guide**

1. Follow the setup instructions of [react-app-rewired](https://github.com/timarney/react-app-rewired#how-to-rewire-your-create-react-app-project)
2. Add the following content to the `config-overrides.js` file:

```js
module.exports = function override(config, env) {
config.module.rules.push({
test: /assets\/.*\.json$/,
use: 'file-loader',
type: 'javascript/auto'
});
return config;
};
```

## Option 2: Ejecting your `create-react-app`

Another option to take full control of configs in your app is to eject your `create-react-app` by running `npm run eject`
in your project. Please read the `create-react-app` notes about the [eject command](https://github.com/facebook/create-react-app/blob/master/packages/cra-template/template/README.md#npm-run-eject) carefully:

> ### `npm run eject`
>
> **Note: this is a one-way operation. Once you `eject`, you can’t go back!**
>
> If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.
>
> Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own.
>
> You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it.
>
> _Quote from https://github.com/facebook/create-react-app/blob/master/packages/cra-template/template/README.md#npm-run-eject_

**Step by Step Guide**

1. Run `npm run eject` in your project
2. Open `config/webpack.config.js` and look for the `oneOf` array inside of `module.rules`. Add the following `file-loader`
anywhere in this array but **before the existing `file-loader`**:

```js
{
test: /assets\/.*\.json$/,
use: 'file-loader',
type: 'javascript/auto'
}
```

Your `config/webpack.config.js` should now look similar to:

```js
...
return {
...
module: {
strictExportPresence: true,
rules: [
...,
{
// "oneOf" will traverse all following loaders until one will
// match the requirements. When no loader matches it will fall
// back to the "file" loader at the end of the loader list.
oneOf: [
...,
{
test: /assets\/.*\.json$/,
use: 'file-loader',
type: 'javascript/auto'
},
// "file" loader makes sure those assets get served by WebpackDevServer.
// When you `import` an asset, you get its (virtual) filename.
// In production, they would get copied to the `build` folder.
// This loader doesn't use a "test" so it will catch all modules
// that fall through the other loaders.
{
loader: require.resolve('file-loader'),
// Exclude `js` files to keep "css" loader working as it injects
// its runtime that would otherwise be processed through "file" loader.
// Also exclude `html` and `json` extensions so they get processed
// by webpacks internal loaders.
exclude: [/\.(js|mjs|jsx|ts|tsx)$/, /\.html$/, /\.json$/],
options: {
name: 'static/media/[name].[hash:8].[ext]',
},
},
// ** STOP ** Are you adding a new loader?
// Make sure to add the new loader(s) before the "file" loader.
],
},
],
},
...
};
};

```

<br />

_In case you also have other alternatives for improving the bundle size, please feel free to submit a pull request!_
18 changes: 9 additions & 9 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,15 @@
"lerna:version-dryrun": "lerna version --conventional-graduate --no-git-tag-version --no-push"
},
"dependencies": {
"@storybook/addon-actions": "6.0.0-rc.5",
"@storybook/addon-controls": "6.0.0-rc.5",
"@storybook/addon-docs": "6.0.0-rc.5",
"@storybook/addon-knobs": "6.0.0-rc.5",
"@storybook/addon-toolbars": "6.0.0-rc.5",
"@storybook/addons": "6.0.0-rc.5",
"@storybook/cli": "6.0.0-rc.5",
"@storybook/react": "6.0.0-rc.5",
"@storybook/theming": "6.0.0-rc.5",
"@storybook/addon-actions": "6.0.0-rc.8",
"@storybook/addon-controls": "6.0.0-rc.8",
"@storybook/addon-docs": "6.0.0-rc.8",
"@storybook/addon-knobs": "6.0.0-rc.8",
"@storybook/addon-toolbars": "6.0.0-rc.8",
"@storybook/addons": "6.0.0-rc.8",
"@storybook/cli": "6.0.0-rc.8",
"@storybook/react": "6.0.0-rc.8",
"@storybook/theming": "6.0.0-rc.8",
"@ui5/webcomponents": "1.0.0-rc.7",
"@ui5/webcomponents-fiori": "1.0.0-rc.7",
"@ui5/webcomponents-icons": "1.0.0-rc.7",
Expand Down
Loading