diff --git a/one.org b/one.org index 6d99093..748788f 100644 --- a/one.org +++ b/one.org @@ -111,56 +111,58 @@ Actions are where business logic is stored. The place where you write the functi In every app you can create a folder called ~actions~ and inside it a file for each page. For example, ~home.py~ for the home page. The file will have the following structure: #+BEGIN_SRC python -# my_app/actions/home.py -from liveview.context_processors import get_global_context -from core import settings -from liveview.utils import ( - get_html, - update_active_nav, - enable_lang, - loading, -) -from django.templatetags.static import static + # my_app/actions/home.py + from liveview.context_processors import get_global_context + from core import settings + from liveview.utils import ( + get_html, + update_active_nav, + enable_lang, + loading, + ) + from django.utils.translation import gettext as _ + from django.templatetags.static import static + from django.urls import reverse -template = "pages/home.html" + template = "pages/home.html" -# Database + # Database -# Functions + # Functions -async def get_context(consumer=None): - context = get_global_context(consumer=consumer) - # Update context - context.update( - { - "url": settings.DOMAIN_URL + reverse("home"), - "title": _("Home") + " | Home", - "meta": { - "description": _("Home page of the website"), - "image": f"{settings.DOMAIN_URL}{static('img/seo/og-image.jpg')}", - }, - "active_nav": "home", - "page": template, - } - ) - return context + async def get_context(consumer=None): + context = get_global_context(consumer=consumer) + # Update context + context.update( + { + "url": settings.DOMAIN_URL + reverse("home"), + "title": _("Home") + " | Home", + "meta": { + "description": _("Home page of the website"), + "image": f"{settings.DOMAIN_URL}{static('img/seo/og-image.jpg')}", + }, + "active_nav": "home", + "page": template, + } + ) + return context -@enable_lang -@loading -async def send_page(consumer, client_data, lang=None): - # Nav - await update_active_nav(consumer, "home") - # Main - my_context = await get_context(consumer=consumer) - html = await get_html(template, my_context) - data = { - "action": client_data["action"], - "selector": "#main", - "html": html, - } - data.update(my_context) - await consumer.send_html(data) + @enable_lang + @loading + async def send_page(consumer, client_data, lang=None): + # Nav + await update_active_nav(consumer, "home") + # Main + my_context = await get_context(consumer=consumer) + html = await get_html(template, my_context) + data = { + "action": client_data["action"], + "selector": "#main", + "html": html, + } + data.update(my_context) + await consumer.send_html(data) #+END_SRC Let's explain each part. @@ -863,7 +865,7 @@ urlpatterns = [ Run the server. #+BEGIN_SRC sh -python manage.py runserver + python3 manage.py runserver #+END_SRC And open the browser at ~http://localhost:8000/~. You should see the home page with a button that generates a random number when clicked. @@ -883,23 +885,217 @@ The next step is to create a more complex application. You can read other [[#/tu :DESCRIPTION: Create a multilingual website with subdomains. :END: -Here you will learn how to create a multilingual website using Django LiveView. We recommend using subdomains to define the language (~en.example.com~, ~es.example.com~...), instead of using prefixes in addresses (~example.com/en/blog/~, ~example.com/es/blog/~). They simplify SEO, maintain consistency in the Sitemap and are easy to test. +Here you will learn how to create a multilingual website using Django LiveView. + +We using subdomains to define the language (~en.example.com~, ~es.example.com~...), instead of using prefixes in addresses (~example.com/en/blog/~, ~example.com/es/blog/~). They simplify SEO, maintain consistency in the Sitemap and are easy to test. + +We will use the following structure: + +- ~example.com~ and ~en.example.com~ for English. +- ~es.example.com~ for Spanish. ** 1. Configure the subdomains -** 2. Create the subdomains +In your ~settings.py~ file, add all domains that will be used. -** 3. Configure the languages +#+BEGIN_SRC python +ALLOWED_HOSTS = ["example.com", "en.example.com", "es.example.com"] +#+END_SRC -** 4. Redirection with Middleware +** 2. Configure the languages -** 5. First text +And add or modify the following settings in the same file (~settings.py~). -** 6. Make messages +#+BEGIN_SRC python + # Languages -** 7. Compile messages + # Enable internationalization + USE_I18N = True -** 8. Selector of languages + # Default language + LANGUAGE_CODE = "en" + + # Available languages + LANGUAGES = [ + ("en", _("English")), + ("es", _("Spanish")), + ] + + # Locale paths + LOCALE_PATHS = (BASE_DIR / "locale/",) +#+END_SRC + +** 3. Redirection with Middleware + +Create a middleware that redirects the user to the correct subdomain and sets the language. If the user enters ~en.example.com~ or ~example.com~, English language will be activated. If the user enters ~es.example.com~, Spanish language will be activated. And if the user enters ~en.example.com~, it will be redirected to ~example.com~. + +Create a file called ~middlewares.py~ in your project folder and add the following code. + +#+BEGIN_SRC python + from django.utils import translation + from django.conf import settings + from django.utils.translation import get_language + from django.http import HttpResponseRedirect + + def language_middleware(get_response): + # One-time configuration and initialization. + + def middleware(request): + # Code to be executed for each request before + # the view (and later middleware) are called. + + # Set the language based on the domain + # Example: + # "example.com" and "en.example.com" -> en + # "es.example.com" -> es + + # Get the domain from the request + domain = request.META["HTTP_HOST"] + # Get the subdomain + domain_list = domain.split(".") + subdomain = domain_list[0] if len(domain_list) == 3 else None + # Set the language + if get_language() != subdomain: + translation.activate(subdomain) + + # Redirect default language to main domain + # Example: "en.example.com" -> "example.com" + if subdomain == settings.LANGUAGE_CODE: + return HttpResponseRedirect("http://example.com") + + response = get_response(request) + + # Code to be executed for each request/response after + # the view is called. + + return response + + return middleware +#+END_SRC + +Now, add the middleware to the ~MIDDLEWARE~ list in ~settings.py~. + +#+BEGIN_SRC python + MIDDLEWARE = [ + ... + "middlewares.language_middleware", + ] +#+END_SRC + +** 4. Set multilingual texts + +In any of your HTML templates, you can use translation tags to display multilingual texts. + +#+BEGIN_SRC + {% load i18n %} + +
{% blocktrans %}This is a multilingual website.{% endblocktrans %}
+ +#+END_SRC + +For titles and descriptions, you can use the ~meta~ dictionary in the action with ~_("text")~ to translate the texts. + +#+BEGIN_SRC python + from liveview.context_processors import get_global_context + from core import settings + from liveview.utils import ( + get_html, + update_active_nav, + enable_lang, + loading, + ) + from django.utils.translation import gettext as _ + from django.templatetags.static import static + from django.urls import reverse + + ... + context.update( + { + "url": settings.DOMAIN_URL + reverse("home"), + "title": _("Home") + " | Home", + "meta": { + "description": _("Home page of the website"), + }, + } + ) + ... +#+END_SRC + +For the url of the page, you can edit the ~urls.py~ file to include the language. + +#+BEGIN_SRC python + from django.urls import path + from django.utils.translation import gettext as _ + from .views import home + + urlpatterns = [ + path(_("home") + "/", home, name="home"), + path(_("about") + "/", about, name="about"), + ] +#+END_SRC + +** 5. Make messages + +Create the ~locale~ folder in the root of your project and run the following commands. + +#+BEGIN_SRC sh + ./manage.py makemessages -l en + ./manage.py makemessages -l es +#+END_SRC + +The files ~locale/en/LC_MESSAGES/django.po~ and ~locale/es/LC_MESSAGES/django.po~ will be created. You can edit them with a text editor or use a translation tool like [[https://poedit.net/][Poedit]]. + +** 6. Compile messages + +After translating the texts, compile the messages. + +#+BEGIN_SRC sh +./manage.py compilemessages +#+END_SRC + +Your multilingual website is ready. You can test it by entering ~example.com~, ~en.example.com~ and ~es.example.com~. + +** 7. Selector of languages + +You can create a selector of languages in the header of your website. + +#+BEGIN_SRC html + {% load i18n %} + {% get_current_language as CURRENT_LANGUAGE %} + {% get_available_languages as AVAILABLE_LANGUAGES %} +