Co-authored-by: Karol Onyśko <karol.onysko@cic.com>
6.0 KiB
Internationalization
Supporting internationalization is not optional. It must be a core feature.
REST framework ships with translatable error messages. You can make these appear in your language enabling Django's standard translation mechanisms.
Doing so will allow you to:
- Select a language other than English as the default, using the standard
LANGUAGE_CODE
Django setting. - Allow clients to choose a language themselves, using the
LocaleMiddleware
included with Django. A typical usage for API clients would be to include anAccept-Language
request header.
Enabling internationalized APIs
You can change the default language by using the standard Django LANGUAGE_CODE
setting:
LANGUAGE_CODE = "es-es"
You can turn on per-request language requests by adding LocalMiddleware
to your MIDDLEWARE_CLASSES
setting:
MIDDLEWARE_CLASSES = [
...
'django.middleware.locale.LocaleMiddleware'
]
When per-request internationalization is enabled, client requests will respect the Accept-Language
header where possible. For example, let's make a request for an unsupported media type:
Request
GET /api/users HTTP/1.1
Accept: application/xml
Accept-Language: es-es
Host: example.org
Response
HTTP/1.0 406 NOT ACCEPTABLE
{"detail": "No se ha podido satisfacer la solicitud de cabecera de Accept."}
REST framework includes these built-in translations both for standard exception cases, and for serializer validation errors.
Note that the translations only apply to the error strings themselves. The format of error messages, and the keys of field names will remain the same. An example 400 Bad Request
response body might look like this:
{"detail": {"username": ["Esse campo deve ser único."]}}
If you want to use different string for parts of the response such as detail
and non_field_errors
then you can modify this behavior by using a custom exception handler.
Specifying the set of supported languages.
By default all available languages will be supported.
If you only wish to support a subset of the available languages, use Django's standard LANGUAGES
setting:
LANGUAGES = [
('de', _('German')),
('en', _('English')),
]
Adding new translations
REST framework translations are managed online using Transifex. You can use the Transifex service to add new translation languages. The maintenance team will then ensure that these translation strings are included in the REST framework package.
Sometimes you may need to add translation strings to your project locally. You may need to do this if:
- You want to use REST Framework in a language which has not been translated yet on Transifex.
- Your project includes custom error messages, which are not part of REST framework's default translation strings.
Translating a new language locally
This guide assumes you are already familiar with how to translate a Django app. If you're not, start by reading Django's translation docs.
If you're translating a new language you'll need to translate the existing REST framework error messages:
-
Make a new folder where you want to store the internationalization resources. Add this path to your
LOCALE_PATHS
setting. -
Now create a subfolder for the language you want to translate. The folder should be named using locale name notation. For example:
de
,pt_BR
,es_AR
. -
Now copy the base translations file from the REST framework source code into your translations folder.
-
Edit the
django.po
file you've just copied, translating all the error messages. -
Run
manage.py compilemessages -l pt_BR
to make the translations available for Django to use. You should see a message likeprocessing file django.po in <...>/locale/pt_BR/LC_MESSAGES
. -
Restart your development server to see the changes take effect.
If you're only translating custom error messages that exist inside your project codebase you don't need to copy the REST framework source django.po
file into a LOCALE_PATHS
folder, and can instead simply run Django's standard makemessages
process.
How the language is determined
If you want to allow per-request language preferences you'll need to include django.middleware.locale.LocaleMiddleware
in your MIDDLEWARE_CLASSES
setting.
You can find more information on how the language preference is determined in the Django documentation. For reference, the method is:
- First, it looks for the language prefix in the requested URL.
- Failing that, it looks for the
LANGUAGE_SESSION_KEY
key in the current user’s session. - Failing that, it looks for a cookie.
- Failing that, it looks at the
Accept-Language
HTTP header. - Failing that, it uses the global
LANGUAGE_CODE
setting.
For API clients the most appropriate of these will typically be to use the Accept-Language
header; Sessions and cookies will not be available unless using session authentication, and generally better practice to prefer an Accept-Language
header for API clients rather than using language URL prefixes.