# External QA Check

The External QA Check tool allows you to validate translations before they are delivered to the end-users. This tool is useful when you need to check translations for specific requirements, such as placeholders, forbidden words, or any other custom rules.

## Sample

```js ins="externalQaCheck" title="index.js"
    import crowdinModule from '@crowdin/app-project-module';

    const configuration = {
      baseUrl: 'https://123.ngrok.io',
      clientId: 'clientId',
      clientSecret: 'clientSecret',
      name: 'Sample App',
      identifier: 'sample-app',
      description: 'Sample App description',
      dbFolder: import.meta.dirname,
      imagePath: import.meta.dirname + '/logo.png',
      externalQaCheck: [
        {
          batchSize: 500,
          validate: async ({
            client,
            file,
            project,
            sourceLanguage,
            strings,
            targetLanguage,
            translations,
            context
          }) => {
            const validations = translations.map((translation) => {
              const string = strings.find(string => string.id === translation.stringId);
              if (string && String(string.text).includes('bk')) {
                const checkRegexp = new RegExp(`\\W${targetLanguage.id}\\W${string.text}`, 'g');
                return {
                  translationId: translation.id,
                  passed: checkRegexp.test(translation.text),
                  error: {
                    message: 'String contains "bk"'
                  }
                };
              }
              return {
                translationId: translation.id,
                passed: true
              };
            });

            return { validations };
          }
        }
      ]
    };

    crowdinModule.createApp(configuration);
    ```
  ```ts ins="externalQaCheck" title="index.ts"
    import crowdinModule from '@crowdin/app-project-module';
    import type { ClientConfig } from '@crowdin/app-project-module';

    const configuration: ClientConfig = {
      baseUrl: 'https://123.ngrok.io',
      clientId: 'clientId',
      clientSecret: 'clientSecret',
      name: 'Sample App',
      identifier: 'sample-app',
      description: 'Sample App description',
      dbFolder: import.meta.dirname,
      imagePath: import.meta.dirname + '/logo.png',
      externalQaCheck: [
        {
          batchSize: 500,
          validate: async ({
            client,
            file,
            project,
            sourceLanguage,
            strings,
            targetLanguage,
            translations,
            context
          }) => {
            const validations = translations.map((translation) => {
              const string = strings.find(string => string.id === translation.stringId);
              if (string && String(string.text).includes('bk')) {
                const checkRegexp = new RegExp(`\\W${targetLanguage.id}\\W${string.text}`, 'g');
                return {
                  translationId: translation.id,
                  passed: checkRegexp.test(translation.text),
                  error: {
                    message: 'String contains "bk"'
                  }
                };
              }
              return {
                translationId: translation.id,
                passed: true
              };
            });

            return { validations };
          }
        }
      ]
    };

    crowdinModule.createApp(configuration);
    ```
  ## Configuration

| Parameter   | Description                                    | Allowed values | Default value |
|-------------|------------------------------------------------|----------------|---------------|
| `batchSize` | The number of translations to process at once. | Integer        | -             |

### `validate` Function

This function is called for each batch of translations to check them against the specified rules.

#### Parameters

- `client` - Crowdin API client.
- `file` - File object.
- `project` - Project object.
- `sourceLanguage` - Source language object.
- `strings` - Array of strings.
- `targetLanguage` - Target language object.
- `translations` - Array of translations.
- `context` - [Context object](/app-project-module/reference/context/).

#### Return Value

The function should return an object with the following structure:

```yml
{
  validations: [
    {
      translationId: number,
      passed: boolean,
      error?: {
        message: string
      }
    }
  ]
}
```

A successful validation should have the `passed` property set to `true`. If the validation fails, set the `passed` property to `false` and provide an error message.

### Multiple QA Checks

You can register multiple external QA checks in a single app by providing an array:

```js title="index.js"
const configuration = {
  // ... other configuration
  externalQaCheck: [
    {
      name: 'Placeholder Check',
      validate: async ({ strings, translations }) => ({
        validations: translations.map((t) => ({ translationId: t.id, passed: true }))
      })
    },
    {
      name: 'Forbidden Words Check',
      batchSize: 200,
      validate: async ({ strings, translations }) => ({
        validations: translations.map((t) => ({ translationId: t.id, passed: true }))
      })
    }
  ]
};
```