cypresslab / translation-bundle
Translation bundle for Symfony2 and Doctrine 2
Installs: 112
Dependents: 0
Suggesters: 0
Security: 0
Stars: 5
Watchers: 2
Forks: 3
Open Issues: 1
Type:symfony-bundle
Requires
- php: >=5.3.3
- doctrine/doctrine-bundle: 1.*
- doctrine/orm: >=2.2,<=2.4
Requires (Dev)
- twig/twig: 1.9.*
This package is auto-updated.
Last update: 2024-10-29 08:06:49 UTC
README
A Symfony2 bundle for translating Doctrine2 entities
WYSIWYG
<?php $book = new Cypress\MyBundle\Entity\Book(); // setters $book->setTitle('the lord of the rings'); $book->setTitleEs('el señor de los anillos'); $book->setTitleIt('il signore degli anelli'); // getters $book->getTitle(); $book->getTitleEs(); // etc...
In your twig templates
<h1>{{ book|translate('title') }}</h1> <h1>{{ book|translate('title', 'es') }}</h1>
Configuration
Let's assume you have a Book entity with a title property
<?php namespace Cypress\MyBundle\Entity; use Doctrine\ORM\Mapping as ORM; /** * Books * * @ORM\Entity * @ORM\Table(name="book") */ class Book { /** * @var integer * * @ORM\Id * @ORM\Column(type="integer") * @ORM\GeneratedValue(strategy="AUTO") */ private $id; /** * @var string * * @ORM\Column */ private $title; // constructor, getter, setter and others amenities... }
In order to translate it:
- create the BookTranslations class (pick the name you want), and make it extends the TranslationEntity superclass. You have to define the $object property, which has a ManyToOne relation with your main book class
<?php namespace Cypress\MyBundle\Entity; use Cypress\TranslationBundle\Entity\Base\TranslationEntity; use Doctrine\ORM\Mapping as ORM; /** * @ORM\Entity * @ORM\Table(name="book_translations", * uniqueConstraints={@ORM\UniqueConstraint(name="lookup_unique_idx", columns={ * "locale", "object_id", "field" * })} * ) */ class BookTranslations extends TranslationEntity { /** * @var Book * * @ORM\ManyToOne(targetEntity="Cypress\MyBundle\Entity\Book", inversedBy="translations") * @ORM\JoinColumn(onDelete="CASCADE") */ protected $object; }
the sensible parts that you'll probably want to change is: the namespace, the table name, the index name and the target entity.
Do not change the inversedBy attribute! And, yes, this is your class, but do not add properties here, do it in the main class!
- add the TranslatableEntity superclass to your Book entity, define a translations property with a OneToMany relation with the translations entity, and implement the three abstract methods:
<?php namespace Cypress\MyBundle\Entity; use Doctrine\ORM\Mapping as ORM; use Cypress\TranslationBundle\Entity\Base\TranslatableEntity; /** * Books * * @ORM\Entity * @ORM\Table(name="book") */ class Book extends TranslatableEntity { /** * @var integer * * @ORM\Id * @ORM\Column(type="integer") * @ORM\GeneratedValue(strategy="AUTO") */ private $id; /** * @var string * * @ORM\Column */ protected $title; /** * @var string * * @ORM\OneToMany(targetEntity="Cypress\MyBundle\Entity\BookTranslations", mappedBy="object", cascade={"all"}) */ protected $translations; // constructor, getter, setter and others amenities... /** * get the name of the TranslationEntity * * @return mixed */ public function getTranslationEntity() { return 'Cypress\MyBundle\Entity\BookTranslations'; } /** * get the default language * * @return string */ public function getDefaultLanguage() { return 'en'; } /** * get an array of supported languages * * @return array */ public function getOtherLanguages() { return array('it', 'es'); } }
getTranslationEntity: return a string with the fully qualified name of the translation entity
getDefaultLanguage: return a string with the two digit code of the main language
getOtherLanguages: return an array with the two digit codes of the other languages
CAREFUL!!: you need to set the properties that has a translation as protected and not private, or no party.
- Rebuild you model
$ ./app/console doctrine:schema:update --force
Important
If your translatable entity contains a constructor remember to call the parent constructor or set the translations property to an empty ArrayCollection. For example:
<?php class Book extends TranslatableEntity { // properties public function __contruct() { // call the parent constructor parent::__construct(); // or alternatively, set the translations property $this->translations = new ArrayCollection(); // your logic ... } }
You're done!
MongoDB
read the docs about MongoDB odm here
Usage
<?php $book = new Cypress\MyBundle\Entity\Book(); $book->setTitle('the lord of the rings'); // default language defined in getDefaultLanguage() $book->setTitleEn('the lord of the rings'); // same as before $book->setTitleEs('el señor de los anillos'); // set the title in spanish $book->setTitleIt('il signore degli anelli'); // guess? $book->setTitleRu('some weird letters here'); // throws an exception! $em->persist($book); // $em is a doctrine entity manager $em->flush(); // if you WTF on this go read the doctrine docs... :) // now retrieve echo $book->getTitle(); // the lord of the rings echo $book->getTitleEn(); // the lord of the rings echo $book->getTitleIt(); // il signore degli anelli... // and so on...
You can use any naming convention for your properties, underscore and camelCase, as long as you define a getter/setter for the property
Twig
In your twig templates you can use a nice filter
{% for book in books %} <h1>{{ book|translate('title') }}</h1> <p>{{ book|translate('description') }}</p> {% endfor %}
Remember to apply the filter directly to the TranslatableEntity instance, and to set the property name as the filter argument
By default, twig gets the language from the actual environment (from the session in sf 2.0 and from the request in sf 2.1), but you can also force the language with twig, just pass the two digit code as the second argument of the filter
<h1>{{ book|translate('title') }}</h1> <h2>spanish translation: {{ book|translate('title', 'es') }}</h2> <h2>italian translation: {{ book|translate('title', 'it') }}</h2>
In some case, you don't know what is the method to call on the object. For example a menu where the voices are different kind of objects with "title" and "name" as the main translated property. In this cases you could also pass an array as the property name. The first that match wins.
<ul> {% for menu_voice in menu_voices %} <li>{{ menu_voice|translate(['title', 'name'], 'es') }}</li> {% endfor %} </ul>
If you don't use twig add this to your configuration file:
cypress_translation: twig: false
Sonata
this bundle works great with sonata admin bundle Just name the properties in your admin class
<?php namespace Sonata\NewsBundle\Admin; use Sonata\AdminBundle\Admin\Admin; class TagAdmin extends Admin { protected function configureFormFields(FormMapper $formMapper) { $formMapper ->add('title') ->add('title_it', 'text') ->add('title_es', 'text') ->add('myAwesomeDescription_es', 'text') ; } }
You only need to define the field type, as sonata is not able to guess the type on a non-existent property
Careful
Use a 2 digit code for your languages. Like "en", "it" or "es".
"en_US" DO NOT WORK!
Testing
This bundle is unit tested with phpunit. Here is the travis build page