Skip to content

Latest commit

 

History

History
298 lines (196 loc) · 8.19 KB

File metadata and controls

298 lines (196 loc) · 8.19 KB

ExposeTranslationBundle

A pretty nice way to expose your translated messages to your JavaScript.

Installation

Install the bundle:

composer require "willdurand/js-translation-bundle:@stable"

Protip: you should browse the willdurand/js-translation-bundle page to choose a stable version to use, avoid the @stable meta constraint.

Register the bundle in app/AppKernel.php:

<?php
// app/AppKernel.php
public function registerBundles()
{
    return array(
        // ...
        new Bazinga\ExposeTranslationBundle\BazingaExposeTranslationBundle(),
    );
}

Register the routing in app/config/routing.yml:

# app/config/routing.yml
_bazinga_exposetranslation:
    resource: "@BazingaExposeTranslationBundle/Resources/config/routing/routing.yml"

Publish assets:

php app/console assets:install --symlink web

Usage

Add this line in your layout:

<script type="text/javascript" src="{{ asset('bundles/bazingaexposetranslation/js/translator.min.js') }}"></script>

Now, you have to specify which translation files to load.

Load Translation Domains

By adding a line as below:

<script type="text/javascript" src="{{ url('bazinga_exposetranslation_js') }}"></script>

This will use the current locale and will provide translated messages found in each messages.CURRENT_LOCALE.* files of your project.

Domain

<script type="text/javascript" src="{{ url('bazinga_exposetranslation_js', { 'domain_name': 'DOMAIN_NAME' }) }}"></script>

This will use the current locale and will provide translated messages found in each DOMAIN_NAME.CURRENT_LOCALE.* files of your project.

Locale

You can specify a locale to use for translation if you want, just add the _locale parameter:

<script type="text/javascript" src="{{ url('bazinga_exposetranslation_js', { 'domain_name': 'DOMAIN_NAME', '_locale' : 'MY_LOCALE' }) }}"></script>

This will provide translated messages found in each DOMAIN_NAME.MY_LOCALE.* files of your project.

Loading via JSON

Alternatively, you can load your translated messages via JSON (e.g. using jQuery's ajax() or RequireJS's text plugin). Just amend the above mentioned URLs to also contain the '_format': 'json' parameter like so:

{{ url('bazinga_exposetranslation_js', { '_format': 'json' }) }}

Then, feed the translator via Translator.fromJSON(myRetrievedJSONString).

Load Translations Via Dumped JavaScript Files

Dump JavaScript Translation Files

Dump the translation files to the web/js folder:

php app/console bazinga:expose-translation:dump web/js

You can use the optional --symlink option. The target (web/js in the example above) argument is also optionally, web is the default target.

Use With Assetic

{% javascripts
    'bundles/bazingaexposetranslation/js/translator.js'
    'js/i18n/*/*.js' %}
    <script type="text/javascript" src="{{ asset_url }}"></script>
{% endjavascripts %}

With 'js/i18n/*/*.js', you load all the translation files from all of the translation domains. Of couse, you can load domains one by one 'js/i18n/admin/*.js'.

The JavaScript Side

Translator.has('DOMAIN_NAME:key');
// true or false

Translator.get('DOMAIN_NAME:key');
// the translated message or undefined

Note: The JavaScript is AMD ready.

Guesser

If you don't specify any domain, a guesser is provided to find the best translated message for the given key. To configure the guesser, you have to set the defaultDomains attribute. By default, the configured default domain is messages.

Translator.get('key');
// will try to find a translated message in default domains.

Note: this will only work if default domains are previously loaded (see the Load translation domains first section).

Message Placeholders

Read the official documentation about Symfony2 message placeholders.

The get() method accepts a second argument that takes placeholders without % delimiters:

Translator.get('DOMAIN_NAME:key', { "foo" : "bar" });
// will replace each "%foo%" in the message by "bar".

You can override the placeholder delimiters by setting the placeHolderSuffix and placeHolderPrefix attributes.

Pluralization

Probably the best feature provided in this bundle ! It allows you to use pluralization exactly like you can do in Symfony2.

Read the official doc about pluralization.

A third parameter can be added to the get() method, it's the number of objects being described. Here is an example:

# app/Resources/messages.en.yml
apples: "{0} There is no apples|{1} There is one apple|]1,19] There are %count% apples|[20,Inf] There are many apples"
Translator.locale = 'en';

Translator.get('apples', {"count" : 0}, 0);
// will return "There is no apples"

Translator.get('apples', {"count" : 1}, 1);
// will return "There is one apple"

Translator.get('apples', {"count" : 2}, 2);
// will return "There are 2 apples"

Translator.get('apples', {"count" : 10}, 10);
// will return "There are 10 apples"

Translator.get('apples', {"count" : 19}, 19);
// will return "There are 19 apples"

Translator.get('apples', {"count" : 20}, 20);
// will return "There are many apples"

Translator.get('apples', {"count" : 100}, 100);
// will return "There are many apples"

Note: This is not tested at the moment. It works fine for english/french translations.

Get The Locale

You can get the current locale by accessing the locale attribute:

Translator.locale;
// will return the current locale.

Example

Consider the following translation files:

# app/Resources/translations/Hello.fr.yml
foo: "Bar"
ba:
    bar: "Hello world"

placeholder: "Hello %username% !"
# app/Resources/translations/messages.fr.yml
placeholder: "Hello %username%, how are you ?"

You can do:

Translator.get('Hello:foo');
// will return 'Bar' if the current locale is set to 'fr', undefined otherwise.

Translator.get('Hello:ba.bar');
// will return 'Hello world' if the current locale is set to 'fr', undefined otherwise.

Translator.get('Hello:placeholder');
// will return 'Hello %username% !' if the current locale is set to 'fr', undefined otherwise.

Translator.get('Hello:placeholder', { "username" : "will" });
// will return 'Hello will !' if the current locale is set to 'fr', undefined otherwise.

Translator.get('placeholder', { "username" : "will" });
// will return 'Hello will, how are you ?' if the current locale is set to 'fr', undefined otherwise.

Translator.get('placeholder');
// will return 'Hello %username%, how are you ?' if the current locale is set to 'fr', undefined otherwise.

More configuration

Custom Default Domains

You can easily add your own default domains by adding these lines in your app/config/config*.yml files:

bazinga_expose_translation:
    default_domains: [ messages ]

Note: You still have to include a <script> tag to expose messages but you avoid writing domain names before each of your keys.

Locale Fallback

In a similar way, if some of your translations are not complete you can enable a fallback for untranslated messages:

bazinga_expose_translation:
    locale_fallback: "en" # put here locale code of some complete translation, I recommend the value used for translator fallback

Reference Configuration

# app/config/config*.yml
bazinga_expose_translation:
    locale_fallback:      ''
    default_domains:      []

Testing

PHP

Setup the test suite using Composer:

$ composer install --dev

Run it using PHPUnit:

$ phpunit

JavaScript

You can run the JavaScript test suite using PhantomJS:

$ phantomjs Resources/js/run-qunit.js file://`pwd`/Resources/js/index.html