---
title: "Translations"
url: https://develop.sentry.dev/backend/application-domains/translations/
---

# Translations

We use [**Transifex**](https://explore.transifex.com/getsentry/sentry/) to translate Sentry.

Other things that mean translating: localization, internationalization, i18n, l10n

If you're a sentry employee and need access to manage translations, translators, languages, or anything else, please open a ticket with IT for access to Transifex.

## [Approving Translators and Languages](https://develop.sentry.dev/backend/application-domains/translations.md#approving-translators-and-languages)

General rules to follow when doing approvals.

1. Don't approve new languages generally.
2. Don't approve new languages that are duplicates of existing languages.
3. Don't approve new team members unless they seem reliable (see security note below).

## [Backfilling a Language](https://develop.sentry.dev/backend/application-domains/translations.md#backfilling-a-language)

We have the ability to pay translators to come in and backfill a language. This has been done a number of times over the years, and is a good way to get an acceptable amount of coverage. There are caveats however:

* They often need "context" for a string, which we're usually missing in our code (or in the database). This means someone has to respond to their requests.
* The quality will be average - you given them a style to aim for, and they often do an ok-enough job.
* It's not free, though its cheap so it's not a big deal.

## [Translation Security](https://develop.sentry.dev/backend/application-domains/translations.md#translation-security)

It's possible for translators to inject advertisements (links) or other bad content into translations. For this reason we don't accept translations implicitly - you get approved first - but it means we also need to do at least a minor bit of research on the translator themselves. Generally this is left to your own judgement, but take a look at their profile and ask yourself if they seem like a real human, or if this is a one-off account intended to use for abuse.

## [Updating Translations (source code)](https://develop.sentry.dev/backend/application-domains/translations.md#updating-translations-source-code)

Translations have to be updated manually in Sentry.

To update untranslated strings in Transifex, open a terminal within the Sentry repo and run the following:

```bash
make update-transifex
```

This will extract strings from the frontend using a webpack loader, as well as from the backend using `django makemessages` -- which then gets merged together to create a `django.po` file for the default (English) locale. This then gets propagated to our other supported locales.

It then uploads these PO files to Transifex to be translated. Ideally, this process is automated so that it is run on a schedule to ensure that new strings are synced with Transifex.

**Note:** You may need to go to Transifex and approve some previously reviewed translations. You can select a language and query for `reviewed:no origin:TM` to find strings that have shifted around in the source code but have been previously translated. The `TM` stands for [Translation Memory](https://www.transifex.com/blog/2021/tm-management-update-all-you-need-to-know/).

### [Updating Sentry with New Translations](https://develop.sentry.dev/backend/application-domains/translations.md#updating-sentry-with-new-translations)

The process of updating Sentry should be separate from updating Transifex as there needs to be time for translations and reviews to occur. In order to update Sentry run the following command in the Sentry repo:

```bash
make update-local-locales
```

This will pull translations from Transifex and use `django compilemessages` to update the local translations. You should then commit the changes and submit a new Pull Request.

### [Troubleshooting](https://develop.sentry.dev/backend/application-domains/translations.md#troubleshooting)

You may encounter some errors when running `make update-local-locales`.

```bash
LC_MESSAGES/django.po:4790: number of format specifications in 'msgid_plural' and 'msgstr[0]' does not match
```

This means that we are using `tn()` with an unbalanced set of string placeholders. For example,

```bash
tn('one user', '%s users', userCount); // This is bad because the first argument needs to also have %s

// Instead do something like this
userCount === 1 ? t('one user') : tn('%s users', '%s users', userCount); // Not great as the first arg to `tn()` is always ignored, but at least it will compile
```

Another common error you may see is

```bash
LC_MESSAGES/django.po:10824: 'msgstr' is not a valid Python format string, unlike 'msgid'. Reason: The character that terminates the directive number 1 is not a valid conversion specifier.
```

This generally means there is a literal `%` that the parser is confusing for a string placeholder. For example,

```bash
#: static/app/views/dashboardsV2/manage/dashboardList.tsx:120
#, python-format
msgid "100% of releases"
```

This can be resolved by removing `#, python-format` (assuming you don't have any string formatting)
