Skip to content

Commit

Permalink
more docs
Browse files Browse the repository at this point in the history
  • Loading branch information
orsinium committed May 5, 2022
1 parent 9891567 commit 13864fb
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 13 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ locales = Locales()

def say_hello(lang='en'):
loc = locales[lang]
msg = loc.get("Hello, world!")
msg = loc.get('Hello, world!')
print(msg)
```

Expand Down
76 changes: 67 additions & 9 deletions docs/advanced.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,68 @@

## If translation is missed

...
If there is no translation for the message in the mo file, `Locale.get` will return the message itself. This is how `gettext` and all its ports work. The motivation is that translations aren't so important as the actual business logic of the application, so it's better to show one message on English rather than fail. Either way, such situations should be avoided, and there are a few tips on how:

## Plural form
+ Run `l10n extract` each time you touch anything related to translated strings.
+ Run `l10n compile` each time you update the translation files.
+ Add commands above into your [pre-commit hooks](https://pre-commit.com/) and on CI.
+ If your target audience doesn't know a word of English, run `l10n translate` to temporarily populate new messages by bad translations.

...
## Format strings

## Fuzzy entries
Use `str.format` to format strings:

...
```python
loc = locales[lang]
msg = loc.get('Hello, {user_name}!').format(user_name=user.name)
```

## Keeping translations up-to-date
Such entries will have `python-brace-format`, so the other tools you may use should correctly detect it as a format tool. In particular, `l10n translate` will not translate the placeholders. So, the message above will be correctly translated on Russian as "Привет, {user_name}!" instead of "Привет, {имя_пользователя}!".

...
Do not use f-strings. Otherwise, the message will be formatted before it gets translated, so l10n will not be able to find the correct translation for it.

## Plural forms

First you should understand that many languages have multiple plural forms (and some have only one form) meaing that different words should be used depending on the number. For example, in English you have 2 forms:

1. 1 message.
2. 2 messages, 3 messages...

And the same in Russian has 3 forms:

1. 1 сообщение, 21 сообщение...
2. 2 сообщения, 3 сообщения...
3. 5 сообщений, 6 сообщений, 11 сообщений, 12 сообщений...

And Arabic even has 6 forms! The good news is that if you use l10n, things aren't so complex for you. All you need to do is to pass the argument `n` into `Locale.get` which will be used to pick the right plural form for thetranslation:

```python
n_msgs = 13
locale = Locales()['ru']
msg = locale.get('{n} message(s)', n=n_msgs).format(n=n_msgs)
```

Additionally, you can specify the argument `plural` which is the default message to be used if no translation is found and `n!=1` (we assume that you use English or another germanic language for your messages):

```python
msg = locale.get('{n} message', n=n_msgs, plural='{n} messages').format(n=n_msgs)
```

The best thing you can do, though, is to avoid plurals (or even translations) altogether. For example:

+ Use an icon of an envelope (✉️) instead of the word "message".
+ Write it as "messages: 1", so you only need to translate the word "messages".
+ At last, don't use a number, just say "You have a new message".

When you run `l10n extract`, the generated po file will contain a special header `Plural-Forms` which indicates how many plural forms the language has in total and contains a C-expression used to pick the right form based on the number. l10n will fill the field with the correct expression for all languages it knows (or just assume the germanic form). Also, for each entry where you specified the `plural` argument, it will use it as `msgid_plural` which is an indication for the translator that the message is supposed to have a plural form.

## Fuzzy and obsolete entries

Th po file format allows to add different flags to entries. One of such flags is "fuzzy" which means that the entry might have a wrong translation and so it needs to be checked by the translator. When you run `l10n translate`, all auto-translated entries will be marked as fuzzy.

When you run `l10n compile`, it will include fuzzy translations in the mo file, which is a different behavior from all other po to mo compilation tools. We think that imperfect translation is better than no translation at all. Also, that would be confusing for user if they translate a message using `l10n translate`, compile it but still don't see the translation in their app. If you want to be strict and don't want to have fuzzy entries in your app, add `--no-fuzzy` flag when running `l10n compile`.

Another interesting flag is "obsolete". When you run `l10n extract`, it will mark as "obsolete" all translations that have a translation but aren't in the source code anymore. Usually, you can just safely remove these entries. The tool doesn't do it for you because often the message is still there, you just change its ID. In such cases, you can take the obsolete translation, add it to the new ID, and mark it as "fuzzy", so the translator later can adjust the translation according to what you changed in the message.

## Including additional strings

Expand Down Expand Up @@ -48,6 +97,15 @@ The `Locale` object provides the following translation functions:
+ `translate_currency`
+ `translate_language`

## Translating HTML
## Translating HTML and JS

...
If you need to translate messages outside of Python code, you'll need other tools in addition to l10n. The main focus of l10n is only Python: "Do one thing and do it well". There are some of our favorites for JS:

+ [i18next](https://github.com/i18next/i18next) for translating messages
+ [Format.js](https://formatjs.io/) for numbers, date, and time.
+ [Angular](https://angular.io/guide/i18n-overview) has some solutions out-of-the-box.

Often, however, it can be a good idea to keep all translations in one place, inside of your Python code. For example:

+ If you use a template language like [Jinja2](https://palletsprojects.com/p/jinja/) or [Genshi](https://genshi.edgewall.org/), you can extract translations on the Python side and pass inside the template already translated strings.
+ If you have some dynamic content to be rendered on the client side, you can have a thin client and provide for JS code an API that will return already translated messages.
8 changes: 6 additions & 2 deletions docs/more.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,12 @@

## Other tools

...
+ [babel](https://babel.pocoo.org/en/latest/) is a tool similar to l10n. It's more low-level but supports HTML and JS files.
+ [weblate](https://github.com/WeblateOrg/weblate) is a WebUI for continious translation.
+ [translate](https://github.com/translate/translate) is a CLI tool for different operations on po and mo files, like converting in different formats or showing statistics.
+ [polib](https://github.com/izimobil/polib) is a pure Python tool to work with po files. In case you want to collect some information that isn't covered by tools provided by `translate`.

## Further reading

+ [The Format of PO Files](https://www.gnu.org/software/gettext/manual/html_node/PO-Files.html)
+ [GNU gettext utilities](https://www.gnu.org/software/gettext/manual/html_node/index.html) is where it all started. They have alot of guides on the format of PO files and the tools you can use to work with them.
+ [linguistics.stackexchange.com](https://linguistics.stackexchange.com/) is like StackOverflow but for questions about natural languages.
2 changes: 1 addition & 1 deletion l10n/_locale.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ def get(

if translation is not None:
return translation
if n is not None and n > 1:
if n is not None and n != 1:
return plural or message
return message

Expand Down

0 comments on commit 13864fb

Please sign in to comment.