npm package: @ringcentral-integration/locale-loader
Description: Locale Loader for webpack
Author: RingCentral Integrations
Latest version: 2.3.3

# Locale Loader

<!-- TODO: Make this work in monorepo
[![Build Status](https://travis-ci.org/u9520107/locale-loader.svg?branch=master)](https://travis-ci.org/u9520107/locale-loader)
[![Coverage Status](https://coveralls.io/repos/github/u9520107/locale-loader/badge.svg?branch=master)](https://coveralls.io/github/u9520107/locale-loader?branch=master) -->

Simple locale loader for webpack.

## Sample File Structure:

```
    --/src
        |--/i18n
             |--en-US.js
             |--fr-FR.js
             |--localeLoader.js
```

## Locale files

1. Must be ES6 module.
2. No nested structures.
3. Do not support variables in template strings

```javascript
import constants from './constants';

export default {
    title: 'Hello World',
    [constants.fetchError]: 'Fetch Error',
    icuCompliant: 'Greetings, {name}!',
    handleEscapedBraces: "Escape braces with single quote: '{foo}'",
    'complex-keys': 'Support using quoted property names',
    concat: 'support' + 'string' + 'concatenation',
    template: `support
    templateStrings`,
    123: 'numeric key supported',
    templateVariable: `this is ${not} supported`,
};
```

## Loader File

Loader files should be a js file starting with the following comment.

```javascript
/* loadLocale */
```

The webpack loader will generate necessary code (in es6) in compiling process.
Each locale will be placed into separate bundles.

If there is a need to not separate the bundles, the following comment can be used instead.

```javascript
/* loadLocale noChunk */
```

There must be a space after '/\*' and '\*/'.

## locale-loader

locale-loader is a webpack loader, this must be placed before babel-loader.

Example webpack config

```javascript
module.exports = {
    module: {
      rules: [
        {
            test: /\.js$/,
            use: [
                {
                    loader: 'babel-loader',
                },
                {
                    loader: '@ringcentral-integration/locale-loader',
                    options: {
                        supportedLocales: ['en-US','en-GB']// the locales you want to support in the project, when null, undefined or [] , it will pack all locales.
                    }
                },
            ],
            exclude: /node_modules/,
        },
    }
}
```

## transformLocaleLoader

For building libraries and releasing, often we only compile the source to es2015 with babel transform and not webpack. The transformLocaleLoader is a gulp transform that can transform the loader files with generated code so the final result is ready to use.

gulpfile.js

```javascript
gulp.src('./src')
    .pipe(transformLocaleLoader({ supportedLocales: ['en-US', 'en-GB'] }))
    .pipe(babel(...babelConfig))
    .pipe(gulp.dest('./build'));
```

## supportedLocales order

The generated loadLocale file will try to respect the order of locales defined in supportedLocales. This is useful for language wide defaults. For example, `['en-US', 'en-GB', 'en-AU', 'zh-CN', 'zh-TW']` will result in 'en' = 'en-US' and 'zh' = 'zh-TW'. But `['en-GB', 'en-US', 'en-AU', 'zh-TW', 'zh-CN']` will result in 'en' = 'en-GB' and 'zh' = 'zh-TW'. If supportedLocales is not specified, then the order will be alphabetical.

## Export to Xlf

The exportLocale function can be used to generate xlf files.

```javascript
import exportLocale from '@ringcentral-integration/locale-loader/lib/exportLocale';
// or import { exportLocale } from '@ringcentral-integration/locale-laoder';

const config = {
    sourceLocale: 'en-US', // the default locale with original strings
    supportedLocales: ['en-US', 'fr-FR', 'ja-JP'], // the array of locales to support
    sourceFolder: 'src', // export locale will use 'src/**/*.js' glob to search for loaders
    localizationFolder: 'localization', // exported files will be saved to here
    exportType: 'diff', // determines what is exported
    fillEmptyWithSource: true, // default to fill in translated field with source string
};

exportLocale(config);
console.log('.xlf generated to `cwd()/localization/`');
```

**Export Types**

1. 'diff': Diff will only export entries that have not been translated, or have been modified since last translation. This is the default mode.
2. 'full': This will export everything.
3. 'translated': This will only export translated entries.

## Import from Xlf

Place the translated Xlf files in to localization folder.

```javascript
import importLocale from '@ringcentral-integration/locale-loader/lib/importLocale';
// or import { importLocale } from '@ringcentral-integration/locale-laoder';

const config = {
    sourceLocale: 'en-US', // the default locale with original strings
    supportedLocales: ['en-US', 'fr-FR', 'ja-JP'], // the array of locales to support
    sourceFolder: 'src', // export locale will use 'src/**/*.js' glob to search for loaders
    localizationFolder: 'localization', // exported files will be saved to here,
    interactive: true, // will prompt for confirmation on deleting/skipping changed keys
    silent: false, // will not output deletion/skip to console
};

importLocale(config).then(() => {
    console.log('.xlf imported');
});
```

## Single File APIs

The package also supports exporting, importing, and checking one locale file at a time.

```javascript
import {
    exportLocaleFile,
    importLocaleFile,
    isLocaleFile,
} from '@ringcentral-integration/locale-loader';

const sourceRelativePath = 'src/components/Foo/i18n/en-US.ts';

isLocaleFile(sourceRelativePath); // true
isLocaleFile(sourceRelativePath, 'en-US'); // true
isLocaleFile(sourceRelativePath, 'fr-FR'); // false

const sourceData = exportLocaleFile({
    sourceFolder: process.cwd(), // optional, default to cwd()
    sourceRelativePath,
    sourceLocale: 'en-US',
});

await importLocaleFile({
    sourceFolder: process.cwd(), // optional, default to cwd()
    targetLocale: 'fr-FR',
    targetRelativePath: sourceRelativePath,
    rawData: {
        title: 'Bonjour',
        '[constants.fetchError]': 'Erreur de chargement',
    },
});
```

### `exportLocaleFile`

- `sourceRelativePath`: locale file path relative to `sourceFolder`
- `sourceFolder`: optional base folder, defaults to `process.cwd()`
- `sourceLocale`: expected source locale for that file, such as `en-US`

Returns a flat object of source strings:

```javascript
{
    title: 'Hello World',
    '[constants.fetchError]': 'Fetch Error',
}
```

### `importLocaleFile`

- `targetRelativePath`: locale file path relative to `sourceFolder`
- `targetLocale`: locale to write, such as `fr-FR`
- `sourceFolder`: optional base folder, defaults to `process.cwd()`
- `sourceLocale`: optional source locale, defaults to `en-US` when `targetRelativePath` already points to the target file
- `rawData`: translated key-value payload

`targetRelativePath` may point to either the source file or the target file:

- `src/components/Foo/i18n/en-US.ts` + `targetLocale: 'fr-FR'` will write `fr-FR.ts`
- `src/components/Foo/i18n/fr-FR.ts` + `targetLocale: 'fr-FR'` will update `fr-FR.ts` and infer the source file

`rawData` supports both formats:

```javascript
{
    title: 'Bonjour',
}
```

```javascript
{
    title: {
        source: 'Hello World',
        value: 'Bonjour',
    },
}
```

When `rawData` includes `source`, the import will skip that key if the current source text no longer matches.

## Consolidate Locale Data

Consolidate locale will do the following:

1. Delete values from translations if the source value has been modified, or if the source no longer contain that key.
2. Re-generate the annotations.

```javascript
import consolidateLocale from '@ringcentral-integration/locale-loader/lib/consolidateLocale';
// or import { consolidateLocale } from '@ringcentral-integration/locale-laoder';

const config = {
    sourceLocale: 'en-US', // the default locale with original strings
    supportedLocales: ['en-US', 'fr-FR', 'ja-JP'], // the array of locales to support
    sourceFolder: 'src', // export locale will use 'src/**/*.js' glob to search for loaders
    localizationFolder: 'localization', // exported files will be saved to here
    interactive: true, // will prompt for confirmation on deleting/skipping changed keys
    silent: false, // will not output deletion/skip to console
};

consolidateLocale(config).then(() => {
    console.log('consolidate done');
});
```