2016-04-29 06:55:09 +02:00
|
|
|
# Translating Zulip
|
|
|
|
|
|
|
|
Zulip has full support for unicode, so you can already use your
|
|
|
|
preferred language everywhere in Zulip.
|
|
|
|
|
|
|
|
To make Zulip even better for users around the world, the Zulip UI is
|
|
|
|
being translated into a number of major languages, including Spanish,
|
|
|
|
German, French, Chinese, Russian, and Japanese, with varying levels of
|
|
|
|
progress. If you speak a language other than English, your help with
|
|
|
|
translating Zulip would be greatly appreciated!
|
|
|
|
|
|
|
|
If you're interested in contributing translations to Zulip, join the
|
|
|
|
[Zulip project on Transifex](https://www.transifex.com/zulip/zulip/)
|
|
|
|
and ask to join any languages you'd like to contribute to (or add new
|
|
|
|
ones). Transifex's notification system sometimes fails to notify the
|
|
|
|
maintainers when you ask to join a project, so please send a quick
|
|
|
|
email to zulip-core@googlegroups.com when you request to join the
|
|
|
|
project or add a language so that we can be sure to accept your
|
|
|
|
request to contribute.
|
2016-05-06 13:22:37 +02:00
|
|
|
|
|
|
|
## Translation Tags
|
|
|
|
|
|
|
|
All user-facing text in the Zulip UI should be generated by a HTML
|
|
|
|
template so that it can be translated.
|
|
|
|
|
|
|
|
Zulip uses two types of templates: backend templates (powered by the
|
|
|
|
[Jinja2][] template engine, though the original [Django][] template
|
|
|
|
engine is still supported) and frontend templates (powered by
|
|
|
|
[Handlebars][]). At present, the frontend templates don't support
|
|
|
|
translation (though we're working on fixing this!), so the rest of
|
|
|
|
this discussion will be about the backend templates.
|
|
|
|
|
|
|
|
To mark a string for translation in the Jinja2 and Django template
|
|
|
|
engines, you can use the `_()` function in the templates like this:
|
|
|
|
|
|
|
|
```
|
|
|
|
{{ _("English text") }}
|
|
|
|
```
|
|
|
|
|
|
|
|
If a string contains both a literal string component and variables,
|
|
|
|
you can use a block translation, which makes use of placeholders to
|
|
|
|
help translators to translated an entire sentence. To translate a
|
|
|
|
block, Jinja2 uses the [trans][] tag while Django uses the
|
|
|
|
[blocktrans][] tag. So rather than writing something ugly and
|
|
|
|
confusing for translators like this:
|
|
|
|
|
|
|
|
```
|
|
|
|
# Don't do this!
|
|
|
|
{{ _("This string will have") }} {{ value }} {{ _("inside") }}
|
|
|
|
```
|
|
|
|
|
|
|
|
You can instead use:
|
|
|
|
|
|
|
|
```
|
|
|
|
# Jinja2 style
|
|
|
|
{% trans %}This string will have {{ value }} inside.{% endtrans %}
|
|
|
|
# Django style
|
|
|
|
{% blocktrans %}This string will have {{ value }} inside.{% endblocktrans %}
|
|
|
|
```
|
|
|
|
|
2016-06-01 13:20:45 +02:00
|
|
|
Zulip expects all the error messages to be translatable. To ensure
|
|
|
|
this, the error message passed to `json_error` and `JsonableError`
|
|
|
|
should always be a literal string enclosed by `_()` function, e.g:
|
|
|
|
|
|
|
|
```
|
|
|
|
json_error(_('English Text'))
|
|
|
|
JsonableError(_('English Text'))
|
|
|
|
```
|
|
|
|
|
|
|
|
To ensure we always internationalize our JSON errors messages, the
|
|
|
|
Zulip linter (`tools/lint-all`) checks for correct usage.
|
|
|
|
|
2016-05-13 12:44:03 +02:00
|
|
|
## Frontend Translations
|
|
|
|
The first step in translating the frontend is to create the translation
|
|
|
|
files using `python manage makemessages`. This command will create
|
|
|
|
translation files under `static/locale`, the location can be changed by
|
|
|
|
passing an argument to the command, however make sure that the location is
|
2016-06-02 19:16:56 +02:00
|
|
|
publicly accessible since these files are loaded through XHR in the
|
|
|
|
frontend which will only work with publicly accessible resources.
|
2016-05-13 12:44:03 +02:00
|
|
|
|
|
|
|
The second step is to upload the translatable strings to Transifex using
|
|
|
|
`tx push -s -a`.
|
|
|
|
|
|
|
|
The final step is to get the translated files from Transifex using
|
|
|
|
`tx pull -a`.
|
|
|
|
|
|
|
|
|
2016-05-06 13:22:37 +02:00
|
|
|
[Django]: https://docs.djangoproject.com/en/1.9/topics/templates/#the-django-template-language
|
|
|
|
[Jinja2]: http://jinja.pocoo.org/
|
|
|
|
[Handlebars]: http://handlebarsjs.com/
|
|
|
|
[trans]: http://jinja.pocoo.org/docs/dev/templates/#i18n
|
|
|
|
[blocktrans]: https://docs.djangoproject.com/en/1.8/topics/i18n/translation/#std:templatetag-blocktrans
|
2016-05-19 17:33:30 +02:00
|
|
|
|
|
|
|
## Testing Translations
|
|
|
|
|
|
|
|
First of all make sure that you have compiled the translation strings
|
|
|
|
using `python manage.py compilemessages`.
|
|
|
|
|
|
|
|
Django figures out the effective language by going through the
|
|
|
|
following steps:
|
|
|
|
|
|
|
|
1. It looks for the language code in the url.
|
|
|
|
2. It loooks for the LANGUGE_SESSION_KEY key in the current user's
|
|
|
|
session.
|
|
|
|
3. It looks for the cookie named 'django_language'. You can set a
|
|
|
|
different name through LANGUAGE_COOKIE_NAME setting.
|
|
|
|
4. It looks for the `Accept-Language` HTTP header in the HTTP request.
|
|
|
|
Normally your browser will take care of this.
|
|
|
|
|
|
|
|
The easiest way to test translations is through the i18n urls e.g. if
|
|
|
|
you have German translations available you can access the German
|
|
|
|
version of a page by going to `/de/path_to_page`.
|
|
|
|
|
|
|
|
To test translations using other methods you will need an HTTP client
|
|
|
|
library like `requests`, `cURL` or `urllib`. Here is a sample code to
|
|
|
|
test `Accept-Language` header using requests:
|
|
|
|
|
|
|
|
```
|
|
|
|
import requests
|
|
|
|
headers = {"Accept-Language": "de"}
|
|
|
|
response = requests.get("http://localhost:9991/login/", headers=headers)
|
|
|
|
print(response.content)
|
|
|
|
```
|