Fekide / strapi-plugin-translate

Strapi plugin for automated translations using different Translate Providers
https://market.strapi.io/plugins/strapi-plugin-translate
MIT License
55 stars 21 forks source link
deepl i18n strapi strapi-plugin translation

Strapi-Translate

Strapi v4 - Translate plugin

Manage and automate the translation of content fields.

GitHub package.json version Monthly download on NPM Build Commitizen friendly

plugin showcase

πŸ“­ Requirements

This plugin requires the following, in order to work correctly:

Unless you have the previous set up, the field on the right where you can translate will not show up. Also it will not show up when editing the currently only available translation of an entry.

⏳ Installation

# with npm
$ npm install strapi-plugin-translate
# or with yarn
$ yarn add strapi-plugin-translate

After successful installation you have to build a fresh package that includes plugin UI:

# with npm
$ npm run build && npm run develop
# or with yarn
$ yarn build && yarn develop

βš™ Configuration

Overall plugin configuration

The overall plugin configuration is done through config[/env]/plugins.js or environment variables

module.exports = {
  // ...
  translate: {
    enabled: true,
    config: {
      // Add the name of your provider here (for example 'deepl' for strapi-provider-translate-deepl or the full package name)
      provider: '[name]',
      providerOptions: {
        // Your provider might define some custom options like an apiKey
      },
      // Which field types are translated (default string, text, richtext, components and dynamiczones)
      // Either string or object with type and format
      // Possible formats: plain, markdown, html (default plain)
      translatedFieldTypes: [
        'string',
        { type: 'text', format: 'plain' },
        { type: 'richtext', format: 'markdown' },
        'component',
        'dynamiczone',
      ],
      // If relations should be translated (default true)
      translateRelations: true,
    },
  },
  // ...
}

Available providers

Configure translation of individual fields/attributes

There are two options to configure translation of individual fields. Both are configured either in the Content-Type Builder in the admin interface in development mode, or in the pluginOptions property in the schema file.

Disable localization completely

This is part of the i18n-plugin and available in all field types except relation, uid under the name Enable localization for this field.

Set this value to false, and the field will not be translated. However it will be copied and have the same value for all localizations.

Configure behavior of automated translation

For the field types component, dynamiczone, media, relation, richtext, string, text, you can additionally configure the behavior when translating automatically under the name Configure automated translation for this field?. There are three options:

Relations are again little bit different. The translate option works as described below, the copy option only works when the related content type is not localized and is one way or if bothWays is either manyToOne or manyToMany

If you have other fields (e.g. custom fields) for which you want to configure the translation, this cannot be done through the Content-Type Builder, but only in the schema file:

{
  //...
  "attributes": {
    //...
    "customField": {
      "type": "customField",
      "pluginOptions": {
        "translate": {
          "translate": "copy"
        },
        "i18n": {
          "localized": true
        }
      }
    }
    //...
  }
  //...
}

πŸš€ Features

This plugin allows you to automatically translate content types. This can be done either on a single entity, or for all entities of a content type.

The following features are included:

Translate a single entity

Translate all entities of a content type

Batch translation showcase

Additional remarks:

Schema for translating relations

The related objects are not translated directly, only the relation itself is translated

the related content type is localized

the related content type is not localized

πŸ” Permissions

Since RBAC was moved to the community edition in Strapi v4.8.0, permissions for endpoints of direct translation, batch translation and api usage can now be granted to other roles than super admins:

Permissions for Translate plugin

πŸ§‘β€πŸ’» Creating your own translation provider

A translation provider should have the following:

module.exports = {
  provider: 'google',
  name: 'Google',
  /**
   * @param {object} providerOptions all config values in the providerOptions property
   * @param {object} pluginOptions all config values from the plugin
   */
  init(providerOptions = {}, pluginConfig = {}) {
    // Do some setup here

    return {
      /**
       * @param {{
       *  text:string|string[],
       *  sourceLocale: string,
       *  targetLocale: string,
       *  priority: number,
       *  format?: 'plain'|'markdown'|'html'
       * }} options all translate options
       * @returns {string[]} the input text(s) translated
       */
      async translate(options) {
        // Implement translation
      },
      /**
       * @returns {{count: number, limit: number}} count for the number of characters used, limit for how many can be used in the current period
       */
      async usage() {
        // Implement usage
      },
    }
  },
}

If your provider has some limits on how many texts or how many bytes can be submitted at once, you can use the chunks service to split it:

const { chunks, reduceFunction } = strapi
  .service('plugin::translate.chunks')
  .split(textArray, {
    // max length of arrays
    maxLength: 100,
    // maximum byte size the request should have, if a single text is larger it is split on new lines
    maxByteSize: 1024 * 1000 * 1000,
  })
// The reduceFunction combines the split text array and possibly split texts back together in the right order
return reduceFunction(
  await Promise.all(
    chunks.map(async (texts) => {
      // Execute the translation here
      return providerClient.translateTexts(texts)
    })
  )
)

The translate function receives the format of the text as plain, markdown or html. If your translation provider supports only html, but no markdown, you can use the format service to change the format before translating to html and afterwards back to markdown:

const { markdownToHtml, htmlToMarkdown } = strapi.service(
  'plugin::translate.format'
)

if (format === 'markdown') {
  return htmlToMarkdown(providerClient.translateTexts(markdownToHtml(text)))
}
return providerClient.translateTexts(texts)

⚠ Limitations: