0.0.5 • Published 4 years ago

@nicholasperetti/rollup-plugin-i18n v0.0.5

Weekly downloads
-
License
MIT
Repository
github
Last release
4 years ago

rollup-plugin-i18n

Use i18n in your app with rollup!

Install

yarn add -D @nicholasperetti/rollup-plugin-i18n

or

npm i -D @nicholasperetti/rollup-plugin-i18n

Usage

In your rollup.config.js file:

import i18n from '@nicholasperetti/rollup-plugin-i18n'

export default {
  plugins: [
    i18n({
      /* options */
    }),
  ],
}

Your translations.js file

export const languages = {
  EN: 'en'
  IT: 'it'
  FR: 'fr'
}

export default {
  "appName": {
    [languages.EN]: 'My App',
    [languages.FR]: 'Mon appli',
    [languages.IT]: 'La mia App',
  }
}

In your code

console.log(__('appName'), availableLanguages)

Globals

It's very likely that you'll need to know which languages are available, which of them is active and more.

In order to provide to you this runtime info, this plugin will allow you to import this informations via the following modules:

i18n:languages

Returns an array of strings. Every element of the array represent one of the languages that you've set in the translations.js file. You can use these values to redirect the user to the bundle you want.

This is useful if you want to show a dropdown with the available languages.

i18n:active-language

Returns a string that represent the active language that has been rendered in the running code.

This is useful if you want to show to the user which language is active

i18n:is-root-bundle

Returns a boolean. This flag will be true if the user is running the root bundle instead of the translated one.

For example, the user is surfing on yoursite.com/ instead of yoursite.com/en/.

How it works

After rollup wrote the files, the plugin reads them, analyzes all the chunks and replace all the __() occurences with the respecitve value.

Where does the translated code will be put?

The plugin creates a directory for each language that you specify in the translations.js file. The whole build is being kind of copy-pasted in the language directory and then transformed

So, are my assets beign duplicated for every language?

Nope!

This plugins copies only the chunks to be sure everything has been translated. All the assets and other static files will be symlinked.

This means that you'll have your assets directory in the root of your output.dir, and every build will have a symlink to that.

This solution saves a lot of space on disk when you build your code.

What happens to the original files?

The original files will be translated to your default language. If you don't specify one, the plugin will get the first language available and use it as default language.

You can set your default langauge with the defaultLanguage option

Dynamic translation keys

The plugin will try to replace every __() occurency with the right translation. Anyhow, there are cases where you don't know what the translation will be. Maybe, the translation key is given to you by an API base on a user action.

For those cases the plugin defines the __() globally and inject in your code the dictionary of the translations for a specific language.

Note: If you're sure you won't need the dynamic translations feature, make sure to use the disableDynamicTranslations option.

The translations.js file

You can store all your translations in the translations.js file (you can override this with the translationsPath option). This file behaves in a different way compared to similar i18n plugins.

The common approach (and its problems)

It's a common practice to group the translations under a certain languange, like this:

{
  "en": {
    "Title": "Title"
  },
  "it": {
    "Title": "Titolo"
  },
  "fr": {
    "Title": "Titre"
  }
}

Anyhow, this approach make it easy to miss information along the way. Since we need to repeat every key in the config object, we might mispell that key for some language and generate a bug.

We might even forget to translate some keys for some languages and no tool will aler us of the bug.

The solution adopted

In order to solve those issue and ensure consistency within your translations, this plugins organises data by content instead of language, like this:

{
  "Title": {
    "en": "Title",
    "it": "Titolo",
    "fr": "Titre"
  }
}

Why?

It's more common to change the content of the app instead of add/remove languages. This approach make the maintance of translations way more easy.

Also, since the keys are being written only once, it's impossible to mistype a certain key in your configuration.

This is really easy to use because the human brain oraganise the information by content, not by language. So this schema reflects way more the way humans thinks about translations.

Structure of the file

This file must exports the following things:

languages

This must be an object containing all the languages supported by your app. If you forget to translate some key in yor config, this plugin will make the build fail, warning you about what translation is missing

The keys of the object will be used by you in order to reference the language in your translations object, like this:

export const languages = { EN: 'en' }

//  Optional
export const defaultLanguage = languages.EN

export default {
  Title: {
    [languages.EN]: 'Title',
  },
}

default

You must export as default your translations object, like this:

export default {
  Title: {
    [languages.EN]: 'Title',
  },
}

defaultLanguage

Specify wich language will be the default language.

This is useful to set a default langauge when your users visit yourapp.domain/ instead of yourapp.domain/en/.

Options

translationsPath

Tell the plugin where it can find your translations file. By default, it will look for translations.js.

import i18n from '@nicholasperetti/rollup-plugin-i18n'

export default {
  plugins: [
    i18n({
      translationsPath: './i18n/translations.js',
    }),
  ],
}

disableDynamicTranslations

By default the plugin injects the translations of a specific language in your code in order to be able to dynamically translate all the keys you want to.

The downside of this approach is that, as your translations grows, your bundle grows too.

So, if you're sure you don't need to dynamically resolve your translations, you can set this option to true and the plugin won't inject neither the translations dictionary nor the fallback function.

Typescript support

In order to use this within your Typescript codebase you need to add the definition of the __() function. If you already have a global .d.ts file add it in there. Otherwise, create a global.d.ts and include it in your tsconfig.json.

Copy paste this definition in there:

declare function __(translationKey: string): string;

declare module 'i18n:languages' {
  const content: Array<string>
  export default content
}
declare module 'i18n:active-language' {
  const content: string
  export default content
}
declare module 'i18n:is-root-bundle' {
  const content: boolean
  export default content
}

More information about typescript global declarations can be found here

0.0.3

4 years ago

0.0.2

4 years ago

0.0.5

4 years ago

0.0.4

4 years ago

0.0.1

4 years ago