duplicate_tree.rst 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. ===========================================================
  2. Creating a multilingual site (by duplicating the page tree)
  3. ===========================================================
  4. This tutorial will show you a method of creating multilingual sites in Wagtail by duplicating the page tree.
  5. For example::
  6. /
  7. en/
  8. about/
  9. contact/
  10. fr/
  11. about/
  12. contact/
  13. The root page
  14. =============
  15. The root page (``/``) should detect the browsers language and forward them to the correct language homepage (``/en/``, ``/fr/``). This page should sit at the site root (where the homepage would normally be).
  16. We must set Django's ``LANGUAGES`` setting so we don't redirect non English/French users to pages that don't exist.
  17. .. code-block:: python
  18. # settings.py
  19. LANGUAGES = (
  20. ('en', _("English")),
  21. ('fr', _("French")),
  22. )
  23. # models.py
  24. from django.utils import translation
  25. from django.http import HttpResponseRedirect
  26. from wagtail.wagtailcore.models import Page
  27. class LanguageRedirectionPage(Page):
  28. def serve(self, request):
  29. # This will only return a language that is in the LANGUAGES Django setting
  30. language = translation.get_language_from_request(request)
  31. return HttpResponseRedirect(self.url + language + '/')
  32. Linking pages together
  33. ======================
  34. It may be useful to link different versions of the same page together to allow the user to easily switch between languages. But we don't want to increase the burden on the editor too much so ideally, editors should only need to link one of the pages to the other versions and the links between the other versions should be created implicitly.
  35. As this behaviour needs to be added to all page types that would be translated, its best to put this behaviour in a mixin.
  36. Here's an example of how this could be implemented (with English as the main language and French/Spanish as alternative languages):
  37. .. code-block:: python
  38. from wagtail.wagtailcore.models import Page
  39. from wagtail.wagtailadmin.edit_handlers import MultiFieldPanel, PageChooserPanel
  40. class TranslatablePageMixin(models.Model):
  41. # One link for each alternative language
  42. # These should only be used on the main language page (english)
  43. french_link = models.ForeignKey(Page, null=True, on_delete=models.SET_NULL, blank=True, related_name='+')
  44. spanish_link = models.ForeignKey(Page, null=True, on_delete=models.SET_NULL, blank=True, related_name='+')
  45. panels = [
  46. PageChooserPanel('french_link'),
  47. PageChooserPanel('spanish_link'),
  48. ]
  49. def get_language(self):
  50. """
  51. This returns the language code for this page.
  52. """
  53. # Look through ancestors of this page for its language homepage
  54. # The language homepage is located at depth 3
  55. language_homepage = self.get_ancestors(inclusive=True).get(depth=3)
  56. # The slug of language homepages should always be set to the language code
  57. return language_homepage.slug
  58. # Method to find the main language version of this page
  59. # This works by reversing the above links
  60. def english_page(self):
  61. """
  62. This finds the english version of this page
  63. """
  64. language = self.get_language()
  65. if language == 'en':
  66. return self
  67. elif language == 'fr':
  68. return type(self).objects.filter(french_link=self).first().specific
  69. elif language == 'es':
  70. return type(self).objects.filter(spanish_link=self).first().specific
  71. # We need a method to find a version of this page for each alternative language.
  72. # These all work the same way. They firstly find the main version of the page
  73. # (english), then from there they can just follow the link to the correct page.
  74. def french_page(self):
  75. """
  76. This finds the french version of this page
  77. """
  78. english_page = self.english_page()
  79. if english_page and english_page.french_link:
  80. return english_page.french_link.specific
  81. def spanish_page(self):
  82. """
  83. This finds the spanish version of this page
  84. """
  85. english_page = self.english_page()
  86. if english_page and english_page.spanish_link:
  87. return english_page.spanish_link.specific
  88. class Meta:
  89. abstract = True
  90. class AboutPage(Page, TranslatablePageMixin):
  91. ...
  92. content_panels = [
  93. ...
  94. MultiFieldPanel(TranslatablePageMixin.panels, 'Language links')
  95. ]
  96. class ContactPage(Page, TranslatablePageMixin):
  97. ...
  98. content_panels = [
  99. ...
  100. MultiFieldPanel(TranslatablePageMixin.panels, 'Language links')
  101. ]
  102. You can make use of these methods in your template by doing:
  103. .. code-block:: html+django
  104. {% if page.english_page and page.get_language != 'en' %}
  105. <a href="{{ page.english_page.url }}">{% trans "View in English" %}</a>
  106. {% endif %}
  107. {% if page.french_page and page.get_language != 'fr' %}
  108. <a href="{{ page.french_page.url }}">{% trans "View in French" %}</a>
  109. {% endif %}
  110. {% if page.spanish_page and page.get_language != 'es' %}
  111. <a href="{{ page.spanish_page.url }}">{% trans "View in Spanish" %}</a>
  112. {% endif %}