Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

crosslink, cleanup and add some additional sections to the multilang …

…tutorial
  • Loading branch information...
commit f213b4371f4786641e14520615bbe9aa8a13dd3f 1 parent 1a4b4fb
@dbu dbu authored
View
10 bundles/blog.rst
@@ -76,8 +76,8 @@ in ``app/config/config.yml``:
Sonata Admin
~~~~~~~~~~~~
-The ``BlogBundle`` has admin services defined for Sonata Admin, to make the blog
-system visible on your dashboard, add the following to the
+The ``BlogBundle`` has admin services defined for Sonata Admin, to make the blog
+system visible on your dashboard, add the following to the
``sonata_admin`` section:
.. code-block:: yaml
@@ -97,7 +97,7 @@ Tree Browser Bundle
~~~~~~~~~~~~~~~~~~~
If you use the Symfony CMF Tree Browser bundle you can expose the blog routes
-to enable blog edition from the tree browser. Expose the routes in the
+to enable blog edition from the tree browser. Expose the routes in the
``fos_js_routing`` section of ``app/config/config.yml``:
.. code-block:: yaml
@@ -118,8 +118,8 @@ Templating
The default templates are marked up for `Twitter Bootstrap <http://twitter.github.com/bootstrap/>`_.
But it is easy to completely customize the templates by **overriding** them.
-The one template you will have to override is the default layout, you will need
- to change it and make it extend your applications layout. The easiest way to do
+The one template you will have to override is the default layout, you will need
+to change it and make it extend your applications layout. The easiest way to do
this is to create the following file:
.. code-block:: jinja
View
2  bundles/phpcr-odm.rst
@@ -470,7 +470,7 @@ correct.
constraints:
- Doctrine\Bundle\PHPCRBundle\Validator\Constraints\ValidPhpcrOdm
- .. code-block:: php-annotations
+ .. code-block:: php
// src/Acme/BlogBundle/Entity/Author.php
View
2  bundles/search.rst
@@ -10,7 +10,7 @@ to provide a site wide search.
Dependencies
------------
-* `LiipSearchBundle <https://github.com/liip/LiipSearchBundle#readme>`_
+* `LiipSearchBundle <https://github.com/liip/LiipSearchBundle>`_
Configuration
-------------
View
11 components/routing.rst
@@ -58,7 +58,7 @@ stack Symfony2 framework, this is identified by the ``_controller`` field
of the parameters.
The ``ChainRouter`` works by accepting a set of prioritized routing strategies,
-`RouterInterface <http://api.symfony.com/2.1/Symfony/Component/Routing/RouterInterface.html>`_
+`RouterInterface <http://api.symfony.com/master/Symfony/Component/Routing/RouterInterface.html>`_
implementations, commonly referred to as "Routers".
When handling an incoming request, the ChainRouter iterates over the configured Routers,
@@ -121,7 +121,7 @@ NestedMatcher
The provided ``RequestMatcherInterface`` implementation is ``NestedMatcher``.
It is suitable for use with ``DynamicRouter``, and it uses a multiple step
-matching process to determine the resulting routing parameters from a given
+matching process to determine the resulting routing parameters from a given
`Request <http://api.symfony.com/master/Symfony/Component/HttpFoundation/Request.html>`_.
It uses a ``RouteProviderInterface`` implementation, which is capable of
@@ -132,7 +132,7 @@ implemented on top of Doctrine PHPCR ODM or a relational database,
effectively allowing you to store and manage routes dynamically from database.
The ``NestedMatcher`` uses a 3-step matching process to determine which Route
-to use when handling the current Request:
+to use when handling the current Request:
* Ask the ``RouteProviderInterface`` for the collection of ``Route`` instances potentially matching the ``Request``
* Apply all ``RouteFilterInterface`` to filter down this collection
@@ -231,7 +231,7 @@ The included ``ProviderBasedGenerator`` extends Symfony2's default
`UrlGenerator <http://api.symfony.com/master/Symfony/Component/Routing/Generator/UrlGenerator.html>`_
(which, in turn, implements ``UrlGeneratorInterface``) and - if $name is
not already a ``Route`` object - loads the route from the ``RouteProviderInterface``.
-It then lets the core logic generate the URL from that Route.
+It then lets the core logic generate the URL from that Route.
The bundle also include the ``ContentAwareGenerator``, which extends the
``ProviderBasedGenerator`` to check if $name is an object implementing
@@ -244,6 +244,7 @@ three ways:
* Or provide an implementation of ``ContentRepositoryInterface`` and pass the id
of the content object as parameter ``content_id`` and ``null`` as $name.
+.. _route-generator-and-locales:
ContentAwareGenerator and locales
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -290,7 +291,7 @@ an integration bundle is also available. We strongly recommend that you take
a look at :doc:`../bundles/routing-extra`.
For a starter's guide to the Routing bundle and its integration with Symfony2,
-refer to :doc:`../getting-started/routing`
+refer to :doc:`../getting-started/routing`
We strongly recommend reading Symfony2's
`Routing <http://symfony.com/doc/current/components/routing/introduction.html>`__
View
6 getting-started/routing.rst
@@ -153,7 +153,7 @@ is carried out can be found in the :doc:`../components/routing`.
interface (see at the bottom) or with fixtures.
However, before we can explain how to do that, you need to understand how
- the DynamicRouter works. An example will come later in this document.
+ the DynamicRouter works. An example will come :ref:`later in this document <routing-document>`.
.. _routing-getting-controller-template:
@@ -264,6 +264,9 @@ urls, with a few added possibilities:
* Pass either an implementation of ``RouteObjectInterface`` or a ``RouteAwareInterface`` as ``name`` parameter
* Or supply an implementation of ``ContentRepositoryInterface`` and the id of the model instance as parameter ``content_id``
+The route generation handles locales as well, see :ref:`route-generator-and-locales`.
+
+.. _routing-document:
The PHPCR-ODM route document
----------------------------
@@ -351,3 +354,4 @@ For more information on the Routing component of Symfony CMF, please refer to:
- :doc:`../components/routing` for most of the actual functionality implementation
- :doc:`../bundles/routing-extra` for Symfony2 integration bundle for Routing Bundle
- Symfony2's `Routing <http://symfony.com/doc/current/components/routing/introduction.html>`_ component page
+- :doc:`../tutorials/handling-multilang-documents` for some notes on multilingual routing
View
5 index.rst
@@ -36,7 +36,7 @@ There are basically two main target audiences:
#. Developers that have built an existing custom application with Symfony2 and need a fast
way to add support for content management. Be it sophisticated CMS features like semantic
- content, inline editing, multi-channel delivery etc. or just a few content pages for things
+ content, inline editing, multi-channel delivery etc. or just a few content pages for things
like the about/contact pages.
#. Developers that need to build a highly customized authoring and content delivery
@@ -50,7 +50,7 @@ Just started learning about the CMF? Want to know if the CMF fits your project?
.. toctree::
:maxdepth: 1
-
+
getting-started/installing-symfony-cmf
getting-started/routing
getting-started/content
@@ -72,6 +72,7 @@ Want to know more about the CMF and how each part can be configured? There's a t
tutorials/installing-configuring-inline-editing
tutorials/creating-cms-using-cmf-and-sonata
tutorials/using-blockbundle-and-contentbundle
+ tutorials/handling-multilang-documents
Bundles
-------
View
6 tutorials/creating-cms-using-cmf-and-sonata.rst
@@ -212,3 +212,9 @@ If you have not yet added anything to the content repository, the tree view will
cannot find a root node. To fix this, load some data as fixtures by following this doc:
- :doc:`using-blockbundle-and-contentbundle`
+
+Further reading
+---------------
+
+* :doc:`../bundles/doctrine_phpcr_admin`
+* :doc:`handling-multilang-documents`
View
207 tutorials/handling-multilang-documents.rst
@@ -1,94 +1,189 @@
-Handling Multilang Documents
+Handling Multi-Language Documents
============================
The goal of the tutorial is to describe all the steps that are needed
-to be taken to use mulitlang documents as clearly as possible.
+to be taken to use multi-language documents as clearly as possible.
+
Please read this first
----------------------
-* :doc:`DoctrinePhpcrOdmBundle<../bundles/phpcr-odm>` - Documentation on the PHPCR-ODM Doctrine bundle
-* :doc:`Creating a CMS using the CMF and Sonata<creating-cms-using-cmf-and-sonata>`
+* You need to understand how to use PHPCR-ODM. You find an introduction in :doc:`Documentation on the PHPCR-ODM Doctrine bundle <../bundles/phpcr-odm>`
+
+
+Lunetics LocaleBundle
+---------------------
+
+The CMF recommends to rely on the `LuneticsLocaleBundle <https://github.com/lunetics/LocaleBundle/>`_
+to handle initial locale selection when a user first visits the site,
+and to provide a locale switcher.
+
+To install the bundle, require it in your project with ``./composer.phar require lunetics/locale-bundle``
+and then instantiate ``Lunetics\LocaleBundle\LuneticsLocaleBundle`` in your AppKernel.php.
+Then configure it in the main application configuration file. As
+there are several CMF bundles wanting the list of allowed locales,
+we recommend putting them into a parameter ``%locales%``, see the
+`cmf-sandbox config.yml file <https://github.com/symfony-cmf/cmf-sandbox/blob/master/app/config/config.yml>`_ for an example.
-PHPCR-ODM Multilanguage Documents
+
+PHPCR-ODM multi-language Documents
---------------------------------
-You can mark any properties as being translatable and have the document manager store and load the correct
-language for you. Note that translation always happens on a document level, not on the individual translatable fields.
-- `PHPCR-ODM documentation on Multilanguage <http://docs.doctrine-project.org/projects/doctrine-phpcr-odm/en/latest/reference/multilang.html>`_.
+You can mark any properties as being translatable and have the document manager
+store and load the correct language for you. Note that translation always happens
+on a document level, not on the individual translatable fields.
+
+.. code-block:: php
+
+ <?php
+ /**
+ * @PHPCRODM\Document(translator="attribute")
+ */
+ class MyPersistentClass
+ {
+ /**
+ * Translated property
+ * @String(translated=true)
+ */
+ private $topic;
+
+Read more about multi-language documents in the `PHPCR-ODM documentation on multi-language <http://docs.doctrine-project.org/projects/doctrine-phpcr-odm/en/latest/reference/multilang.html>`_
+and see :ref:`phpcr-odm-multilang-config` to configure PHPCR-ODM correctly.
+
+Most of the CMF bundles provide multi-language documents, for example MultilangStaticContent,
+MultilangMenuNode or MultilangSimpleBlock. The routing is different, as explained in the next
+section.
+
+
+Routing
+-------
+
+The concept of the DynamicRouter is to map the request URL onto a PHPCR id.
+Each document can have only one id, and therefore we need a separate route
+document for each locale. The cool thing with this is that you can localize
+the URL for each language. Simply create one route document per locale, and
+set a default value for _locale to point to the locale of that route.
+
+As all routes point to the same content, the route generator can handle picking
+the correct route for you when you generate the route from the content.
+See also :ref:`route-generator-and-locales`.
Sonata PHPCR-ODM Admin
----------------------
-The first step is to configure sonata admin. We are going to place the language switcher in the topnav bar.
+This section explains how to make Sonata Admin handle multi-language documents. You should
+already have set up Sonata PHPCR-ODM Admin and understand how it works, see
+:doc:`Creating a CMS using the CMF and Sonata <creating-cms-using-cmf-and-sonata>`.
+
+.. note::
+
+ The following assumes that you installed the LuneticsLocaleBundle as explained above.
+ If you want to use something else or write your own locale handling, first think if
+ it would not make sense to give the Lunetics bundle a try. If you are still convinced
+ you will need to adapt the following template examples to your way of building a
+ locale switcher.
+
+
+The first step is to configure sonata admin. We are going to place the LuneticsLocaleBundle
+language switcher in the ``topnav`` bar.
To do this we need to configure the template for the "user_block" as shown below:
-.. code-block:: yaml
+.. configuration-block::
- # app/main/config/config.yml
- sonata_admin:
- ...
- templates:
- user_block: LiipchCoreBundle:Admin:admin_topnav.html.twig
+ .. code-block:: yaml
+ # app/config/config.yml
+ sonata_admin:
+ ...
+ templates:
+ user_block: AcmeCoreBundle:Admin:admin_topnav.html.twig
+
+And the template looks like this
.. code-block:: jinja
- {# src/Liipch/CoreBundle/Resources/views/Admin/admin_topnav.html.twig #}
+ {# src/Acme/CoreBundle/Resources/views/Admin/admin_topnav.html.twig #}
{% extends 'SonataAdminBundle:Core:user_block.html.twig' %}
{% block user_block %}
- {{ locale_switcher(null, null, 'LiipchCoreBundle:Admin:switcher_links.html.twig') }}
+ {{ locale_switcher(null, null, 'AcmeCoreBundle:Admin:switcher_links.html.twig') }}
{{ parent() }}
{% endblock %}
+We tell the ``locale_switcher`` to use a custom template to display the links, which looks like this:
.. code-block:: jinja
- {# src/Liipch/CoreBundle/Resources/views/Admin/switcher_links.html.twig #}
+ {# src/Acme/CoreBundle/Resources/views/Admin/switcher_links.html.twig #}
Switch to :
{% for locale in locales %}
{% if loop.index > 1 %} | {% endif %}<a href="{{ locale.link }}" title="{{ locale.locale_target_language }}">{{ locale.locale_target_language }}</a>
{% endfor %}
-The next step is to update the routing.yml with the following content:
-
-.. code-block:: yaml
-
- # app/main/config/routing.yml
- admin_wo_locale:
- pattern: /admin
- defaults:
- _controller: FrameworkBundle:Redirect:redirect
- route: sonata_admin_dashboard
- permanent: true # this for 301
-
- admin_dashboard_wo_locale:
- pattern: /admin/dashboard
- defaults:
- _controller: FrameworkBundle:Redirect:redirect
- route: sonata_admin_dashboard
- permanent: true # this for 301
-
- admin_dashboard:
- pattern: /{_locale}/admin/
- defaults:
- _controller: FrameworkBundle:Redirect:redirect
- route: sonata_admin_dashboard
- permanent: true # this for 301
-
- admin:
- resource: '@SonataAdminBundle/Resources/config/routing/sonata_admin.xml'
- prefix: /{_locale}/admin
-
- sonata_admin:
- resource: .
- type: sonata_admin
- prefix: /{_locale}/admin
-
-If you now open up the admin dashboard again, the url should be prefixed with your default locale,
-for example ``/de/admin/...``. When clicking on the language switcher the page reloads and displays
-the correct content for the requested language. Happy editing.
+Now what is left to do is to update the sonata routes to become locale aware:
+
+.. configuration-block::
+
+ .. code-block:: yaml
+
+ # app/config/routing.yml
+
+ admin_dashboard:
+ pattern: /{_locale}/admin/
+ defaults:
+ _controller: FrameworkBundle:Redirect:redirect
+ route: sonata_admin_dashboard
+ permanent: true # this for 301
+
+ admin:
+ resource: '@SonataAdminBundle/Resources/config/routing/sonata_admin.xml'
+ prefix: /{_locale}/admin
+
+ sonata_admin:
+ resource: .
+ type: sonata_admin
+ prefix: /{_locale}/admin
+
+ # redirect routes for the non-locale routes
+ admin_without_locale:
+ pattern: /admin
+ defaults:
+ _controller: FrameworkBundle:Redirect:redirect
+ route: sonata_admin_dashboard
+ permanent: true # this for 301
+
+ admin_dashboard_without_locale:
+ pattern: /admin/dashboard
+ defaults:
+ _controller: FrameworkBundle:Redirect:redirect
+ route: sonata_admin_dashboard
+ permanent: true # this for 301
+
+When we now reload the admin dashboard, the url should be prefixed with our
+default locale, for example ``/de/admin/dashboard``. When clicking on the
+language switcher the page reloads and displays the correct content for the
+requested language.
+
+Happy editing.
+
+
+Frontend editing and multi-language
+-----------------------------------
+
+When using the CreateBundle, you do not need to do anything at all to get
+multi-language support. PHPCR-ODM will deliver the document in the requested
+language, and the callback URL is generated in the request locale,
+leading to save the edited document in the same language as it was loaded.
+
+
+.. note::
+
+ If a translation is missing, language fallback kicks in, both when viewing the
+ page but also when saving the changes, so you always update the current locale.
+
+ It would make sense to offer the user the choice whether he wants to create
+ a new translation or update the existing one. There is this `issue <https://github.com/symfony-cmf/CreateBundle/issues/39>`_
+ in the CreateBundle issue tracker.
View
4 tutorials/using-blockbundle-and-contentbundle.rst
@@ -339,8 +339,8 @@ Using the CMF ContentBundle
Follow this example to use both the CMF Block and Content components together.
-The ContentBundle also requires RoutingExtraBundle, so to save time you can install both together.
-Add the following to ``composer.json``:
+The ContentBundle is best used together with the RoutingExtraBundle. Add the
+following to ``composer.json``:
.. code-block:: javascript
Please sign in to comment.
Something went wrong with that request. Please try again.