django rest framework 多语言支持

在经历了半个月之后版权证书终于发下来了,但是现在即使拿到这个东西国内的多数应用商店也上不了。所以,实际意义并不大。并且在很长时间内这个问题可能无法解决。是时候转化下重心了,支持多语言在国外的市场上架。后续如果再做产品可能也是以国外用户为主了,国内的这个环境着实不善。

最开始的时候没有提前规划好,所以只能重新针对多语言进行处理。首先从后台服务开始,官方的文档简单的介绍了一下多语言的实现步骤:

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 an Accept-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 setting:

MIDDLEWARE = [
    ...
    '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 like processing 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 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.

https://www.django-rest-framework.org/topics/internationalization/

下面的这篇文章更详细的介绍了相关的操作流程:https://medium.com/ascentic-technology/how-to-add-localization-to-django-rest-framework-42eba321bfd1

具体的步骤就不想写了,按照上面的操作即可,所有的操作步骤完成之后,运行出现了下面的错误:

ERRORS:
?: (translation.E001) You have provided an invalid value for the LANGUAGE_CODE setting: 'zh_CN'.
?: (translation.E002) You have provided an invalid language code in the LANGUAGES setting: 'en_US'.
?: (translation.E002) You have provided an invalid language code in the LANGUAGES setting: 'zh_CN'.
?: (translation.E004) You have provided a value for the LANGUAGE_CODE setting that is not in the LANGUAGES setting.

System check identified 4 issues (0 silenced).

这是由于找到不到对应的语文编码导致的,在新版的 django 中必须严格使用global_settings.py中的语言编码,

# Languages we provide translations for, out of the box.
LANGUAGES = [
    ("af", gettext_noop("Afrikaans")),
    ("ar", gettext_noop("Arabic")),
    ("ar-dz", gettext_noop("Algerian Arabic")),
    ("ast", gettext_noop("Asturian")),
    ("az", gettext_noop("Azerbaijani")),
    ("bg", gettext_noop("Bulgarian")),
    ("be", gettext_noop("Belarusian")),
    ("bn", gettext_noop("Bengali")),
    ("br", gettext_noop("Breton")),
    ("bs", gettext_noop("Bosnian")),
    ("ca", gettext_noop("Catalan")),
    ("ckb", gettext_noop("Central Kurdish (Sorani)")),
    ("cs", gettext_noop("Czech")),
    ("cy", gettext_noop("Welsh")),
    ("da", gettext_noop("Danish")),
    ("de", gettext_noop("German")),
    ("dsb", gettext_noop("Lower Sorbian")),
    ("el", gettext_noop("Greek")),
    ("en", gettext_noop("English")),
    ("en-au", gettext_noop("Australian English")),
    ("en-gb", gettext_noop("British English")),
    ("eo", gettext_noop("Esperanto")),
    ("es", gettext_noop("Spanish")),
    ("es-ar", gettext_noop("Argentinian Spanish")),
    ("es-co", gettext_noop("Colombian Spanish")),
    ("es-mx", gettext_noop("Mexican Spanish")),
    ("es-ni", gettext_noop("Nicaraguan Spanish")),
    ("es-ve", gettext_noop("Venezuelan Spanish")),
    ("et", gettext_noop("Estonian")),
    ("eu", gettext_noop("Basque")),
    ("fa", gettext_noop("Persian")),
    ("fi", gettext_noop("Finnish")),
    ("fr", gettext_noop("French")),
    ("fy", gettext_noop("Frisian")),
    ("ga", gettext_noop("Irish")),
    ("gd", gettext_noop("Scottish Gaelic")),
    ("gl", gettext_noop("Galician")),
    ("he", gettext_noop("Hebrew")),
    ("hi", gettext_noop("Hindi")),
    ("hr", gettext_noop("Croatian")),
    ("hsb", gettext_noop("Upper Sorbian")),
    ("hu", gettext_noop("Hungarian")),
    ("hy", gettext_noop("Armenian")),
    ("ia", gettext_noop("Interlingua")),
    ("id", gettext_noop("Indonesian")),
    ("ig", gettext_noop("Igbo")),
    ("io", gettext_noop("Ido")),
    ("is", gettext_noop("Icelandic")),
    ("it", gettext_noop("Italian")),
    ("ja", gettext_noop("Japanese")),
    ("ka", gettext_noop("Georgian")),
    ("kab", gettext_noop("Kabyle")),
    ("kk", gettext_noop("Kazakh")),
    ("km", gettext_noop("Khmer")),
    ("kn", gettext_noop("Kannada")),
    ("ko", gettext_noop("Korean")),
    ("ky", gettext_noop("Kyrgyz")),
    ("lb", gettext_noop("Luxembourgish")),
    ("lt", gettext_noop("Lithuanian")),
    ("lv", gettext_noop("Latvian")),
    ("mk", gettext_noop("Macedonian")),
    ("ml", gettext_noop("Malayalam")),
    ("mn", gettext_noop("Mongolian")),
    ("mr", gettext_noop("Marathi")),
    ("ms", gettext_noop("Malay")),
    ("my", gettext_noop("Burmese")),
    ("nb", gettext_noop("Norwegian Bokmål")),
    ("ne", gettext_noop("Nepali")),
    ("nl", gettext_noop("Dutch")),
    ("nn", gettext_noop("Norwegian Nynorsk")),
    ("os", gettext_noop("Ossetic")),
    ("pa", gettext_noop("Punjabi")),
    ("pl", gettext_noop("Polish")),
    ("pt", gettext_noop("Portuguese")),
    ("pt-br", gettext_noop("Brazilian Portuguese")),
    ("ro", gettext_noop("Romanian")),
    ("ru", gettext_noop("Russian")),
    ("sk", gettext_noop("Slovak")),
    ("sl", gettext_noop("Slovenian")),
    ("sq", gettext_noop("Albanian")),
    ("sr", gettext_noop("Serbian")),
    ("sr-latn", gettext_noop("Serbian Latin")),
    ("sv", gettext_noop("Swedish")),
    ("sw", gettext_noop("Swahili")),
    ("ta", gettext_noop("Tamil")),
    ("te", gettext_noop("Telugu")),
    ("tg", gettext_noop("Tajik")),
    ("th", gettext_noop("Thai")),
    ("tk", gettext_noop("Turkmen")),
    ("tr", gettext_noop("Turkish")),
    ("tt", gettext_noop("Tatar")),
    ("udm", gettext_noop("Udmurt")),
    ("ug", gettext_noop("Uyghur")),
    ("uk", gettext_noop("Ukrainian")),
    ("ur", gettext_noop("Urdu")),
    ("uz", gettext_noop("Uzbek")),
    ("vi", gettext_noop("Vietnamese")),
    ("zh-hans", gettext_noop("Simplified Chinese")),
    ("zh-hant", gettext_noop("Traditional Chinese")),
]

修改语言编码为下面的配置:

LANGUAGES = [
    ('zh-hans', _('Chinese')),
    ('en', _('English')),
]
LANGUAGE_CODE = 'zh-hans'

切换语言可以通过 header 中的Accept-Language 来实现。

如果出现下面的错误:

ValueError: invalid token in plural form: EXPRESSION

可以讲 po 文件中的:

"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"

修改为:

"Plural-Forms: nplurals=2; plural=(n != 1);\n"

或者直接删除后重新生成mo 文件。

☆版权☆

* 网站名称:obaby@mars
* 网址:https://oba.by/
* 个性:https://oba.by/
* 本文标题: 《django rest framework 多语言支持》
* 本文链接:https://oba.by/2024/01/15185
* 短链接:https://oba.by/?p=15185
* 转载文章请标明文章来源,原文标题以及原文链接。请遵从 《署名-非商业性使用-相同方式共享 2.5 中国大陆 (CC BY-NC-SA 2.5 CN) 》许可协议。


You may also like

22 comments

  1. Level 3
    Google Chrome 104 Google Chrome 104 Android 13 Android 13 cn四川省成都市 联通

    膜拜中,希望数年之后能看懂这些代码。
    代码,无疑是最美的语言

    1. 公主 Queen 
      Google Chrome 120 Google Chrome 120 Android 10 Android 10 cnAsia/Shanghai

      都是雕虫小技,倒是也没什么高深的。如之前的木工瓦工无异耳,都是农民工

  2. Level 2
    Google Chrome 120 Google Chrome 120 Windows 10 Windows 10 cnGuangdong Shenzhen

    其实每次过来就是看美女的,这些东西对我来说象天书一样,但支持是必须的

  3.  Level 4
    Google Chrome 121 Google Chrome 121 Mac OS X 10.15 Mac OS X 10.15 cn江苏省无锡市 电信

    说真的 我确实好奇国外的人会不会记录大姨妈周期

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注