Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Django i18n and instructions #3321

Merged
merged 18 commits into from
Dec 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -195,3 +195,6 @@ core

# non tracked settings
config/settings/local.py

# Transifex binary
tx
18 changes: 18 additions & 0 deletions .tx/config
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[main]
host = https://app.transifex.com

[o:mathesar:p:mathesar:r:django]
file_filter = translations/<lang>/LC_MESSAGES/django.po
source_file = translations/en/LC_MESSAGES/django.po
source_lang = en
type = PO
resource_name = django
replace_edited_strings = false

[o:mathesar:p:mathesar:r:svelte]
file_filter = mathesar_ui/src/i18n/languages/<lang>/dict.json
source_file = mathesar_ui/src/i18n/languages/en/dict.json
source_lang = en
type = KEYVALUEJSON
resource_name = svelte
replace_edited_strings = false
14 changes: 14 additions & 0 deletions .tx/integration.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
git:
filters:
- filter_type: dir
file_format: PO
source_file_extension: po
source_language: en
source_file_dir: translations/en/LC_MESSAGES/
translation_files_expression: 'translations/<lang>/LC_MESSAGES/'
- filter_type: dir
file_format: KEYVALUEJSON
source_file_extension: json
source_language: en
source_file_dir: mathesar_ui/src/i18n/languages/en/
translation_files_expression: 'mathesar_ui/src/i18n/languages/<lang>/'
92 changes: 92 additions & 0 deletions DEVELOPER_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,98 @@ Sometimes you may need to rebuild your Docker images after pulling new code chan
docker compose -f docker-compose.yml -f docker-compose.dev.yml up dev-service --force-recreate --build dev-service
```

## Internationalization

Our repo contains two separate i18n flows: one for the server-rendered UI from **Django**, and another for the client-rendered UI handled by **Svelte**.

### Django i18n

We use the i18n features provided by Django. Refer the [Django docs](https://docs.djangoproject.com/en/4.2/topics/i18n/translation/#internationalization-in-template-code) on how to translate strings.

#### When modifying UI strings

If you make code changes to the UI strings in Django templates, follow these steps to ensure your changes are properly translated.

1. Regenerate the English-language [django.po](./translations/en/LC_MESSAGES/django.po) file:

```
docker exec mathesar_service_dev python manage.py makemessages -l en -i "mathesar_ui" -i "docs"
```

> **Note:**
>
> Only generate the `.po` file for _English_. Do not update other languages using `makemessages`. They will be pulled from our translation service provider when the translation process is complete.

1. Commit the changes to `django.po` along with your code changes.

#### When preparing a release

Django uses gettext, which require the `.po` files to be compiled into a more efficient form before using in production.

1. Compile the Django messages:

```
docker exec mathesar_service_dev python manage.py compilemessages
```

This will produce files with `.mo` extension for each of the `.po` files.

1. Test the app locally with different languages.

### Svelte i18n

- We use [svelte-i18n](https://github.com/kaisermann/svelte-i18n), which internally uses [format-js](https://formatjs.io/) for handling i18n.
- The source translation file is [en/dict.json](./mathesar_ui/src/i18n/languages/en/dict.json).
- To handle pluralization and other complexities, the source translation strings may utilize a special syntax called [JSON with ICU Plurals](https://help.transifex.com/en/articles/6220806-json-with-icu-plurals) (a subset of the [ICU format](https://unicode-org.github.io/icu/userguide/icu/i18n.html)).
- After making changes to your code, ensure that the source `/en/dict.json` file contains new translation strings, if any.
- Do not update other translation files. They will be pulled from our translation service provider when the translation process is complete.

## Translation process

- We use [Transifex](https://app.transifex.com/mathesar/mathesar/dashboard/) for managing our translation process.
- You'll need to be a member of the Mathesar organization in Transifex, inorder to work with translations. Please reach out to us for information on how to join.

### For Translators

_(We're currently working on a workflow for translators. This section will be updated once we have a clear set of instructions to follow.)_

### For Maintainers

#### Automation

- We have automated sync between Transifex and the `develop` branch, via the GitHub integration feature provided by Transifex.
- The configuration for it is specified in the `.tx/integration.yml` file, and within the Transifex admin panel.
- Refer [Transfiex documentation](https://help.transifex.com/en/articles/6265125-github-installation-and-configuration) for more information.

#### Manually pushing and pulling translations

If you'd like to manually push or pull translations, follow the instructions in this section.

> **Warning**
>
> Only push and pull translations on the `develop` branch. Do not do it for other branches since this will overwrite the existing resources within Transifex.

1. Install the Transifex cli tool, `tx`, if you haven't already.

```
curl -o- https://raw.githubusercontent.com/transifex/cli/master/install.sh | bash
```

It can be installed in your host machine or on the docker container.

1. **Push** the updated source translation files:

```
TX_TOKEN=<transifex_api_token> tx push -s
```

1. **Pull** the translations from Transifex:

```
TX_TOKEN=<transifex_api_token> tx pull -f
```

1. Commit and push the changes to our repo.

## Demo mode

Expand Down
3 changes: 3 additions & 0 deletions config/settings/common_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -264,5 +264,8 @@ def pipe_delim(pipe_string):
('en', gettext_lazy('English')),
('ja', gettext_lazy('Japanese')),
]
LOCALE_PATHS = [
'translations'
]
LANGUAGE_COOKIE_NAME = 'display_language'
SALT_KEY = SECRET_KEY
10 changes: 5 additions & 5 deletions mathesar/templates/mathesar/login_base.html
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{% extends 'mathesar/app_styled_base.html' %}
{% load i18n static %}

{% block title %}{% translate "login"|title %}{% endblock %}
{% block title %}{% translate "Login" %}{% endblock %}

{% block page_styles %}
<style type="text/css">
Expand Down Expand Up @@ -115,7 +115,7 @@
{% if live_demo_mode %}
<div class="unsupported-device">
<div class="warning-icon">⚠️</div>
<p class="title">{% translate "unsupported screen size"|title %}</p>
<p class="title">{% translate "Unsupported Screen Size" %}</p>
<p>
{% translate "Mathesar is a spreadsheet-like application with a rich UI that does not yet function well on screens this small. Improved support for mobile devices is on our" %}

Expand All @@ -129,16 +129,16 @@
</div>
<div class="tutorial align-center">
<div class="header">
<strong>{% translate "live demo mode"|title %}</strong>
<strong>{% translate "Live Demo Mode" %}</strong>
</div>
<div class="body">
{% translate "Mathesar's live demo is available to anyone to try out." %}

{% if live_demo_username and live_demo_password %}
{% translate "Use the following credentials to login" %}:
<ul>
<li>{% translate "username" %}: <strong>{{live_demo_username}}</strong></li>
<li>{% translate "password" %}: <strong>{{live_demo_password}}</strong></li>
<li>{% translate "Username" %}: <strong>{{live_demo_username}}</strong></li>
<li>{% translate "Password" %}: <strong>{{live_demo_password}}</strong></li>
</ul>
{% endif %}

Expand Down
6 changes: 3 additions & 3 deletions mathesar/templates/registration/login.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
<div class="labeled-input layout-stacked">
<label for="id_username" class="label-component">
<span class="label-content">
<span class="label">{% translate "username"|title %}</span>
<span class="label">{% translate "Username" %}</span>
<span class="input">
<input type="text" name="username"
class="input-element{% if form.username.errors %} has-error{% endif %}"
Expand All @@ -34,7 +34,7 @@
<div class="labeled-input layout-stacked">
<label for="id_password" class="label-component">
<span class="label-content">
<span class="label">{% translate "password"|title %}</span>
<span class="label">{% translate "Password" %}</span>
<span class="input">
<input type="password" name="password"
class="input-element{% if form.password.errors %} has-error{% endif %}"
Expand Down Expand Up @@ -62,7 +62,7 @@
{% endif %}
<div class="footer">
<button class="btn btn-primary submit-button" type="submit">
{% translate "log in"|title %}
{% translate "Log In" %}
</button>
</div>
</form>
Expand Down
6 changes: 3 additions & 3 deletions mathesar/templates/registration/superuser_create.html
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ <h2>{% translate "Create Admin User" %}</h2>
<div class="inputs-container">
<div class="left cell">
<label for="id_username" class="label-component">
{% translate "username"|title %}
{% translate "Username" %}
</label>
</div>
<div class="right cell">
Expand All @@ -141,7 +141,7 @@ <h2>{% translate "Create Admin User" %}</h2>
</div>
<div class="left cell">
<label for="id_password1" class="label-component">
{% translate "password"|title %}
{% translate "Password" %}
</label>
</div>
<div class="right cell">
Expand Down Expand Up @@ -170,7 +170,7 @@ <h2>{% translate "Create Admin User" %}</h2>
</div>
<div class="left cell">
<label for="id_password2" class="label-component">
{% translate "confirm password"|title %}
{% translate "Confirm Password" %}
</label>
</div>
<div class="right cell">
Expand Down
8 changes: 4 additions & 4 deletions mathesar/templates/users/password_reset_confirmation.html
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{% extends 'mathesar/login_base.html' %}
{% load i18n static %}

{% block h1 %}{% translate "update your password"|title %}{% endblock %}
{% block h1 %}{% translate "Update Your Password" %}{% endblock %}

{% block box_content %}
{% if validlink %}
Expand All @@ -11,7 +11,7 @@
<div class="labeled-input layout-stacked">
<label for="id_username" class="label-component">
<span class="label-content">
<span class="label">{% translate "new password"|title %}</span>
<span class="label">{% translate "New Password" %}</span>
<span class="input">
<input
type="password"
Expand All @@ -38,7 +38,7 @@
<div class="labeled-input layout-stacked">
<label for="id_username" class="label-component">
<span class="label-content">
<span class="label">{% translate "confirm"|title %}</span>
<span class="label">{% translate "Confirm" %}</span>
<span class="input">
<input
type="password"
Expand All @@ -64,7 +64,7 @@
</div>
<div class="footer">
<button class="btn btn-primary submit-button" type="submit">
{% translate "update password"|title %}
{% translate "Update Password" %}
</button>
<div class="warning-message">
<div class="icon">&#9432;</div>
Expand Down
Loading
Loading