Skip to content

Translations

We use Weblate to manage PyPI translations across several languages. Visit the Warehouse project on Weblate to contribute.

If you are experiencing issues as a translator, please let us know by opening a translation issue on the Warehouse issue tracker.

Adding a newly completed translation

Weblate will automatically add commits to a pull request as translations are updated.

When a translation reaches 100%, it should be added as a known locale and have it's MO file (Machine Object file) compiled.

To add a new known locale:

  1. Check for outstanding Weblate pull requests and merge them if so.
  2. In a new branch for pypi/warehouse, add the new language identifier to KNOWN_LOCALES in warehouse/i18n/__init__.py and webpack.plugin.localize.js. The value is the locale code, and corresponds to a directory in warehouse/locale.
  3. Commit these changes and make a new pull request to pypi/warehouse.
  4. In a new branch for pypi/infra, add the new identifier to the accept.language_lookup call in PyPI's VCL configuration. The value is the IANA language subtag string for the locale.

    Note

    This value may differ from the identifier used for KNOWN_LOCALES, e.g. pt-BR vs pt_BR.

  5. Commit these change and make a new pull request to pypi/infra referencing your pull request to pypi/warehouse.

Marking new strings for translation

In an HTML template, use the {% trans %} and {% endtrans %} tags to mark a string for translation.

In Python, given a request context, call request._(message) to mark message for translation. Without a request context, you can do the following:

from warehouse.i18n import localize as _
message = _("Your message here.")

In javascript, use gettext("singular", ...placeholder_values) and ngettext("singular", "plural", count, ...placeholder_values). The function names are important because they need to be recognised by pybabel.

import { gettext, ngettext } from "../utils/messages-access";
gettext("Get some fruit");
// -> (en) "Get some fruit"
ngettext("Yesterday", "In the past", numDays);
// -> (en) numDays is 1: "Yesterday"; numDays is 3: "In the past"

Passing non-translatable values to translated strings

In html, to pass values you don't want to be translated into translated strings, define them inside the {% trans %} tag. For example, to pass a non-translatable link request.route_path('classifiers') into a string, instead of placing it directly in the string like so:

{% trans %}
Filter by <a href="request.route_path('classifiers')">classifier</a>
{% endtrans %}

Instead, define it inside the {% trans %} tag:

{% trans href=request.route_path('classifiers') %}
Filter by <a href="{{ href }}">classifier</a>
{% endtrans %}

In javascript, use %1, %2, etc as placeholders and provide the placeholder values:

import { ngettext } from "../utils/messages-access";
ngettext("Yesterday", "About %1 days ago", numDays, numDays);
// -> (en) numDays is 1: "Yesterday"; numDays is 3: "About 3 days ago"

Marking new strings for pluralization

To pluralize a translated string in an HTML template, use the {% pluralize %} tag to separate the singular and plural variants of a string, for example:

{% trans n_hours=n_hours %}
This link will expire in {{ n_hours }} hour.
{% pluralize %}
This link will expire in {{ n_hours }} hours.
{% endtrans %}

This is not yet directly possible in Python for Warehouse.

In javascript, use ngettext() as described above.

Marking views as translatable

If a view's renderer uses translations, you should mark the view as translatable by setting the has_translations option in the view's configuration:

@viewconfig(
   route_name="sample.route",
   renderer="translatable_sample.html",
   has_translations=True,
)
class SampleViews:

You may have to rebuild the translation files.