Skip to content

Commit

Permalink
updated translation docs, fixed #4057
Browse files Browse the repository at this point in the history
  • Loading branch information
Guite committed Jan 25, 2020
1 parent a742402 commit 3b0a0e8
Show file tree
Hide file tree
Showing 11 changed files with 288 additions and 284 deletions.
234 changes: 1 addition & 233 deletions Refactoring for 3.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,239 +52,7 @@ information and examples.
## Translations
All custom Zikula translation mechanisms have been removed in favour of Symfony's native translation system.

### PHP files
Some examples for how to convert translations in PHP files:

```php
// import
use Zikula\Common\Translator\TranslatorInterface; // old
use Symfony\Contracts\Translation\TranslatorInterface; // new

// 1. Simple:
$this->__('Hello') // old
$this->trans('Hello') // new

// 2. With simple substitution parameters
$this->__f('Hello %userName%', ['%userName%' => 'Mark Smith']) // old
$this->trans('Hello %userName%', ['%userName%' => 'Mark Smith']) // new

// 3. With explicit domain
$this->__('Hello', 'acmefoomodule') // old
$this->trans('Hello', [], 'acmefoomodule') // new

// 4. With plural forms and advanced substitution (see note below)
$this->_fn('User deleted!', '%n users deleted!', count($deletedUsers), ['%n' => count($deletedUsers)]);
/** @Desc("{count, plural,\n one {User deleted!}\n other {# users deleted!}\n}") */
$this->getTranslator()->trans('plural_n.users.deleted', ['%count%' => count($deletedUsers)]);
```

You can still use `Zikula\Bundle\CoreBundle\Translation\TranslatorTrait`, but it has only one method left now:
```php
public function trans(string $id, array $parameters = [], string $domain = null, string $locale = null): string
```
You can/should remove the `setTranslator` method from your class which uses the trait. It is not needed anymore.

#### Automatic translations
You should remove all translation calls from the following elements:

- Strings inside form type classes:
- Form field labels
- Choice labels
- Placeholders
- String values for `empty_value` attribute
- Invalid messages
- Single help messages
- Input group addons
- Alert messages
- Flash messages (`$this->addFlash()` as well as `getFlashBag()->add()`); except when substitution parameters are used.
- Knp menu entries:
- Labels (`$menu->addChild('foo')` as well as `$menu['foo']->setLabel('bar')`)
- Link titles (`setLinkAttribute('title', 'my.title')`)

They will be picked up by the extractor nevertheless.

More information about how translation of form messages work can be found [here](https://symfony.com/blog/new-in-symfony-4-3-improved-form-translation).

For a help array with multiple strings an example follows below.

#### Using the extractor

To extract translations use the console command `translation:extract`. To see all of it's option, do this:
```
php bin/console translation:extract -h
# or
php bin/console translation:extract --help
```

Example for Zikula core:
```
# extract for all configured locales
php bin/console translation:extract zikula
# extract only for English
php bin/console translation:extract zikula en
```

Note `zikula` is the name of our configuration.

Examples for a module or a theme:
```
php bin/console translation:extract -b AcmeFooModule extension
php bin/console translation:extract --bundle AcmeFooModule extension en
php bin/console translation:extract -b AcmeFooModule acmefoomodule
php bin/console translation:extract --bundle AcmeFooModule acmefoomodule en
# or with more memory:
php -dmemory_limit=2G bin/console translation:extract --bundle AcmeFooModule extension
php -dmemory_limit=2G bin/console translation:extract --bundle AcmeFooModule acmefoomodule en
```

You can always check the status of your translation using the `translation:status` command.
Check the available options using `-h` or `--help` like shown above.

#### Translation annotations

To influence the extraction behaviour you can utilise some annotations from the `Translation\Extractor\Annotation` namespace.
Import them like any other php class:
```php
use Translation\Extractor\Annotation\Desc;
use Translation\Extractor\Annotation\Ignore;
use Translation\Extractor\Annotation\Translate;
```

##### `@Desc`
The `@Desc` annotation allows specifying a default translation for a key.

Examples:

```php
$builder->add('title', 'text', [
/** @Desc("Title:") */
'label' => 'post.form.title',
]);

/** @Desc("We have changed the permalink because the post '%slug%' already exists.") */
$errors[] = $this->translator->trans(
'post.form.permalink.error.exists', ['%slug%' => $slug]
);
```

##### `@Ignore`
The `@Ignore` annotation allows ignoring extracting translation subjects which are not a string, but a variable.
You can use it for example for `trans()` calls, form labels and form choices.

Examples:

```php
echo $this->translator->trans(/** @Ignore */$description);

$builder->add('modulecategory' . $module['name'], ChoiceType::class, [
/** @Ignore */
'label' => $module['displayname'],
'empty_data' => null,
'choices' => /** @Ignore */$options['categories']
]);
```

##### `@Translate`
With the `/** @Translate */` you can explicitly add phrases to the dictionary. This helps to extract strings
which would have been skipped otherwise.

Examples:

```php
$placeholder = /** @Translate */'delivery.user.not_chosen';
```

It can be also used to force specific domain:

```php
$errorMessage = /** @Translate(domain="validators") */'error.user_email.not_unique';
```

##### Combined example

If you have a form class which uses a help array with multiple help messages strings you need to prepare it like this:

```php
$builder->add('myField', [
// ...
/** @Ignore */
'help' => [
/** @Translate */'This is the first help message.',
/** @Translate */'This is the second help message.'
]
]);
```

### JavaScript files
Follows basically the same rules as translations in PHP files shown above. See [BazingaJsTranslation docs](https://github.com/willdurand/BazingaJsTranslationBundle/blob/master/Resources/doc/index.md#the-js-translator) for further details and examples.

### Twig template files
Some examples for how to convert translations in templates:

```twig
1. Simple:
Old: {{ __('Hello') }}
New: {% trans %}Hello{% endtrans %} or {{ 'Hello'|trans }}
2. With simple substitution parameters
Old: {{ __f('Hello %userName%', {'%userName%': 'Mark Smith'}) }}
New: {% trans with {'%userName%': 'Mark Smith'} %}Hello %userName%{% endtrans %}
3. With explicit domain and locale
Old: {{ __('Hello', 'acmefoomodule', 'fr') }}
New: {% trans with {} from 'acmefoomodule' into 'fr' %}Hello{% endtrans %} or {{ 'Hello'|trans({}, 'acmefoomodule', 'fr' }}
```

See [Symfony docs](https://symfony.com/doc/current/translation/templates.html) for further details and examples of simple translation.

There is also a `desc` filter for specifying a default translation for a key (same as the `@Desc` annotation shown above). Use it like this:

```twig
{{ 'post.form.title'|trans|desc('Title:') }}
{{ 'welcome.message'|trans({'%userName%': 'John Smith'})|desc('Welcome %userName%!') }}
```

### Translation domains
Earlier we used the bundle name as translation domain. The new translation system uses different configurations for different bundles though. You are encouraged to use multiple translation domains now. They should cover different semantical topics and act as a context for translators, like for example `mail`, `messages`, `navigation`, `validators` and `admin`).

### About plural forms
Here is an example using plural forms, advanced substitution and the `desc` filter:
```twig
Old: {% set amountOfUsers = _fn('%amount% registered user', '%amount% registered users', users|length, {'%amount%': users|length}) %}
New: {% set amountOfUsers = 'plural_n.registered.user'|trans({count: users|length})|desc('{count, plural,\n one {one registered user}\n other {# registered users}\n}') %}
```

The `plural_n` portion of the translation key is simply a convention established to note that this key requires plural translation.

The translation of this would look something like:
```yaml
#messages+intl-icu.en.yaml
plural_n.registered.user: "{count, plural,\n one {one registered user}\n other {# registered users}\n}"
```
More advanced translation like plurals and other substitutions require using the Symfony ICU MessageFormatter. See [How to Translate Messages using the ICU MessageFormat](https://symfony.com/doc/current/translation/message_format.html). This requires a specific name format on the translation file and other adjustments.
### UI-based translations
Zikula 3 introduces two new abilities for creating and changing translations.
Both can be accessed in the Settings module at the localisation settings if the environment is set to `dev`.

**Edit in place functionality**
Allows to edit translations directly in the context of a page ([demo](https://php-translation.readthedocs.io/en/latest/_images/edit-in-place-demo.gif)).

Edit in place has some limitations you should be aware of:

- It always works for the current locale only; so in order to update translation for multiple languages you need to switch your site's language.
- It can only work with one single configuration. By default this is set to `zikula`, so it works for the core. If you want to use it for a module or a theme, you need to lookup the corresponding configuration name (e.g. `zikulabootstraptheme`) in `/app/config/dynamic/generated.yml` and use this in `/app/config/packages/dev/php_translation.yaml` at `translation.edit_in_place.config_name`.

You can utilise HTML formatting options when your translation keys end with the `.html` suffix ([screenshot](https://php-translation.readthedocs.io/en/latest/_images/demo-html-editor.png)).

**Web UI: provides a web interface to add, edit and remove translations.**

It features a dashboard page ([screenshot](https://php-translation.readthedocs.io/en/latest/_images/webui-dashboard.png)) for the overall progress. When you dive into a translation domain you can use a form to change the translation messages ([screenshot](https://php-translation.readthedocs.io/en/latest/_images/webui-page.png)).

The web UI is able to handle multiple configurations and target languages.
For more information please refer to the documents in `docs/TranslationAndLanguage/`.

## Twig

Expand Down
11 changes: 7 additions & 4 deletions src/docs/TranslationAndLanguage/Debugging.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
# Debugging translations

Symfony comes with `bin/console debug:translation` command line tool to debug translations.
**This tool work only with Symfony and Zikula Core-2.0 translation paths.**

Example output for more information please check https://symfony.com/doc/current/translation.html#debugging-translations
Example output:

%> php bin/console debug:translation pl KaikmediaPagesModule
%> php bin/console debug:translation pl --domain=mydomain
+----------+-------------+----------------------+
| State(s) | Id | Message Preview (pl) |
+----------+-------------+----------------------+
Expand All @@ -23,7 +22,11 @@ Example output for more information please check https://symfony.com/doc/current
o Unused message
= Same as the fallback message

For more information please check https://symfony.com/doc/current/translation.html#debugging-translations

## Important notes
From Symfony translator documentation

From Symfony translator documentation:

> Each time you create a new translation resource (or install a bundle that includes a translation resource), be sure to
clear your cache so that Symfony can discover the new translation resources.
118 changes: 113 additions & 5 deletions src/docs/TranslationAndLanguage/Extraction.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,119 @@
# Translation extraction
To extract translations use the console command `translation:extract`.

Extract all the core translations
To see all of it's option, do this:
```
php bin/console translation:extract -h
# or
php bin/console translation:extract --help
```

php bin/console translation:extract zikula en
Example for Zikula core:
```
# extract for all configured locales
php bin/console translation:extract zikula
# extract only for English
php bin/console translation:extract zikula en
```

The files will automatically be extracted to the `/translations` directory.
Note `zikula` is the name of our configuration.

See the help file for more information:
Examples for a module or a theme:
```
php bin/console translation:extract -b AcmeFooModule extension
php bin/console translation:extract --bundle AcmeFooModule extension en
php bin/console translation:extract -b AcmeFooModule acmefoomodule
php bin/console translation:extract --bundle AcmeFooModule acmefoomodule en
php bin/console translation:extract -h
# or with more memory:
php -dmemory_limit=2G bin/console translation:extract --bundle AcmeFooModule extension
php -dmemory_limit=2G bin/console translation:extract --bundle AcmeFooModule acmefoomodule en
```

You can always check the status of your translation using the `translation:status` command.
Check the available options using `-h` or `--help` like shown above.

## Translation annotations

To influence the extraction behaviour you can utilise some annotations from the `Translation\Extractor\Annotation` namespace.
Import them like any other php class:
```php
use Translation\Extractor\Annotation\Desc;
use Translation\Extractor\Annotation\Ignore;
use Translation\Extractor\Annotation\Translate;
```

### `@Desc`
The `@Desc` annotation allows specifying a default translation for a key.

Examples:

```php
$builder->add('title', 'text', [
/** @Desc("Title:") */
'label' => 'post.form.title',
]);

/** @Desc("We have changed the permalink because the post '%slug%' already exists.") */
$errors[] = $this->translator->trans(
'post.form.permalink.error.exists', ['%slug%' => $slug]
);
```

### desc filter in Twig
There is also a `desc` filter for specifying a default translation for a key in Twig.

Use it like this:

```twig
{{ 'post.form.title'|trans|desc('Title:') }}
{{ 'welcome.message'|trans({'%userName%': 'John Smith'})|desc('Welcome %userName%!') }}
```

### `@Ignore`
The `@Ignore` annotation allows ignoring extracting translation subjects which are not a string, but a variable.
You can use it for example for `trans()` calls, form labels and form choices.

Examples:

```php
echo $this->translator->trans(/** @Ignore */$description);

$builder->add('modulecategory' . $module['name'], ChoiceType::class, [
/** @Ignore */
'label' => $module['displayname'],
'empty_data' => null,
'choices' => /** @Ignore */$options['categories']
]);
```

### `@Translate`
With the `/** @Translate */` you can explicitly add phrases to the dictionary. This helps to extract strings
which would have been skipped otherwise.

Examples:

```php
$placeholder = /** @Translate */'delivery.user.not_chosen';
```

It can be also used to force specific domain:

```php
$errorMessage = /** @Translate(domain="validators") */'error.user_email.not_unique';
```

### Combined example

If you have a form class which uses a help array with multiple help messages strings you need to prepare it like this:

```php
$builder->add('myField', [
// ...
/** @Ignore */
'help' => [
/** @Translate */'This is the first help message.',
/** @Translate */'This is the second help message.'
]
]);
```
Loading

0 comments on commit 3b0a0e8

Please sign in to comment.