Merge branch 'locale' into 'master'

Centralized translations

See merge request JustScreaMy/facturio!3
This commit is contained in:
Jakub Kropáček 2024-01-29 20:52:57 +00:00
commit 12d30552b3
15 changed files with 227 additions and 46 deletions

21
TODO.md Normal file
View file

@ -0,0 +1,21 @@
# TODO
## Localisation
- [ ] It would be nice to centralize the translations to some well-chosen singular directory
- [ ] Integrate it with some public translation project?
## DevOps Functionality
- [ ] I need to dockerize it
- [ ] It should be easily buildable and publishable using some kind of CI/CD
## Application Functionality
- [ ] I should be able to connect one (or many) subjects to a user, so they can start generating as the one
- This is meant so that the user is being the "connected subject"
- [ ] I need to be able to create the invoices as the connected subject to any subject in current database
- Automatically creating non-existing subjects might be nice to have
- [ ] I should be able to keep the invoices even if the subject is deleted (or changed) with the data in the day of the
creation
- [ ] Generating QR Payments is nice to have
- [ ] It would be great to automatically check `ares` for data changes from time to time

View file

@ -1,5 +1,6 @@
from crispy_forms import helper, layout from crispy_forms import helper, layout
from django.contrib.auth.forms import AuthenticationForm, UserCreationForm from django.contrib.auth.forms import AuthenticationForm, UserCreationForm
from django.utils.translation import gettext_lazy as _
from .models import User from .models import User
@ -13,7 +14,7 @@ class LoginForm(AuthenticationForm):
self.helper = helper.FormHelper() self.helper = helper.FormHelper()
self.helper.form_action = "accounts:login" self.helper.form_action = "accounts:login"
self.helper.form_method = "post" self.helper.form_method = "post"
self.helper.add_input(layout.Submit('submit', 'Login')) self.helper.add_input(layout.Submit('submit', _('Login')))
class RegisterForm(UserCreationForm): class RegisterForm(UserCreationForm):
@ -26,4 +27,4 @@ class RegisterForm(UserCreationForm):
self.helper = helper.FormHelper() self.helper = helper.FormHelper()
self.helper.form_action = "accounts:register" self.helper.form_action = "accounts:register"
self.helper.form_method = "post" self.helper.form_method = "post"
self.helper.add_input(layout.Submit('submit', 'Register')) self.helper.add_input(layout.Submit('submit', _('Register')))

View file

@ -1,8 +1,9 @@
{% extends "facturio/base.html" %} {% extends "facturio/base.html" %}
{% load i18n %}
{% load crispy_forms_tags %} {% load crispy_forms_tags %}
{% block title %}Login{% endblock %} {% block title %}{% trans "Login" %}{% endblock %}
{% block content %} {% block content %}
{% crispy form form.helper %} {% crispy form form.helper %}

View file

@ -1,14 +1,22 @@
{% extends "facturio/base.html" %} {% extends "facturio/base.html" %}
{% load i18n %}
{% block title %}About Me{% endblock %} {% block title %}{% trans "About Me" %}{% endblock %}
{% block content %} {% block content %}
<h2 class="mb-4">About Me</h2> <h2 class="mb-4">{% trans "About Me" %}</h2>
<div class="card"> <div class="card">
<h5 class="card-header">Welcome, {{ request.user.first_name }} {{ request.user.last_name }}!</h5> <h5 class="card-header">
{% blocktrans trimmed with firstname=request.user.first_name lastname=request.user.last_name %}Welcome,
{{ firstname }} {{ lastname }}!{% endblocktrans %}
</h5>
<ul class="list-group list-group-flush"> <ul class="list-group list-group-flush">
<li class="list-group-item">Username: {{ request.user.username }}</li> <li class="list-group-item">
<li class="list-group-item">Email: {{ request.user.email }}</li> {% blocktrans with username=request.user.username %}Username: {{ username }}{% endblocktrans %}
</li>
<li class="list-group-item">
{% blocktrans with email=request.user.email %}Email: {{ email }}{% endblocktrans %}
</li>
</ul> </ul>
</div> </div>
{% endblock %} {% endblock %}

View file

@ -1,10 +1,10 @@
{% extends "facturio/base.html" %} {% extends "facturio/base.html" %}
{% load i18n %}
{% load crispy_forms_tags %} {% load crispy_forms_tags %}
{% block title %}Register{% endblock %} {% block title %}{% trans "Register" %}{% endblock %}
{% block content %} {% block content %}
{# TODO: neukazovat všechny pičoviny hned najedou#}
{% crispy form form.helper %} {% crispy form form.helper %}
{% endblock %} {% endblock %}

View file

@ -55,4 +55,5 @@ def auth_register(req: HttpRequest) -> HttpResponse:
@login_required @login_required
def me(req: HttpRequest) -> HttpResponse: def me(req: HttpRequest) -> HttpResponse:
print(req.user.username)
return render(req, "account/me.html") return render(req, "account/me.html")

View file

@ -11,6 +11,7 @@ https://docs.djangoproject.com/en/5.0/ref/settings/
""" """
from pathlib import Path from pathlib import Path
from django.utils.translation import gettext_lazy as _
# Build paths inside the project like this: BASE_DIR / 'subdir'. # Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent BASE_DIR = Path(__file__).resolve().parent.parent
@ -44,6 +45,7 @@ INSTALLED_APPS = [
MIDDLEWARE = [ MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware", "django.middleware.security.SecurityMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware", "django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.locale.LocaleMiddleware",
"django.middleware.common.CommonMiddleware", "django.middleware.common.CommonMiddleware",
"django.middleware.csrf.CsrfViewMiddleware", "django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware", "django.contrib.auth.middleware.AuthenticationMiddleware",
@ -102,7 +104,15 @@ AUTH_PASSWORD_VALIDATORS = [
# Internationalization # Internationalization
# https://docs.djangoproject.com/en/5.0/topics/i18n/ # https://docs.djangoproject.com/en/5.0/topics/i18n/
LANGUAGE_CODE = "en-us" LANGUAGE_CODE = "cs"
LANGUAGES = [
("en", _("English")),
("cs", _("Czech"))
]
LOCALE_PATHS = [
BASE_DIR / "locale"
]
TIME_ZONE = "UTC" TIME_ZONE = "UTC"

View file

@ -1,32 +1,18 @@
"""
URL configuration for facturio project.
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/5.0/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin from django.contrib import admin
from django.http import HttpRequest, HttpResponse from django.http import HttpRequest, HttpResponse
from django.shortcuts import render from django.shortcuts import render
from django.urls import path, include from django.urls import path, include
from django.conf.urls.i18n import i18n_patterns
def landing_page(req: HttpRequest) -> HttpResponse: def landing_page(req: HttpRequest) -> HttpResponse:
return render(req, "facturio/index.html") return render(req, "facturio/index.html")
urlpatterns = [ urlpatterns = i18n_patterns(
path("", landing_page, name="main-page"), path("", landing_page, name="main-page"),
path("accounts/", include("accounts.urls")), path("accounts/", include("accounts.urls")),
path("subjects/", include("subjects.urls")), path("subjects/", include("subjects.urls")),
path("admin/", admin.site.urls), path("admin/", admin.site.urls),
] prefix_default_language=False
)

View file

@ -0,0 +1,142 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-01-29 20:46+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=4; plural=(n == 1 && n % 1 == 0) ? 0 : (n >= 2 && n "
"<= 4 && n % 1 == 0) ? 1: (n % 1 != 0 ) ? 2 : 3;\n"
#: accounts/forms.py:17 accounts/templates/account/login.html:6
#: templates/facturio/base.html:39
msgid "Login"
msgstr "Přihlásit se"
#: accounts/forms.py:30 accounts/templates/account/register.html:6
#: templates/facturio/base.html:42
msgid "Register"
msgstr "Registrovat se"
#: accounts/models.py:9
msgid "first name"
msgstr "křestní jméno"
#: accounts/models.py:10
msgid "last name"
msgstr "přijmení"
#: accounts/models.py:11
msgid "email address"
msgstr "emailová adresa"
#: accounts/templates/account/me.html:4 accounts/templates/account/me.html:7
msgid "About Me"
msgstr "O mně"
#: accounts/templates/account/me.html:10
#, python-format
msgid "Welcome, %(firstname)s %(lastname)s!"
msgstr "Vítej, %(firstname)s %(lastname)s!"
#: accounts/templates/account/me.html:15
#, python-format
msgid "Username: %(username)s"
msgstr "Uživatelské jméno: %(username)s"
#: accounts/templates/account/me.html:18
#, python-format
msgid "Email: %(email)s"
msgstr "Email: %(email)s"
#: facturio/settings.py:109
msgid "English"
msgstr "Angličtina"
#: facturio/settings.py:110
msgid "Czech"
msgstr "Čeština"
#: subjects/forms.py:14
msgid "Your provided CIN is not correct."
msgstr "Vaše poskytnuté IČO není správné."
#: subjects/forms.py:15
msgid "Subject with provided CIN already exists."
msgstr "Subjekt s poskytnutým IČO již existuje."
#: subjects/forms.py:18 subjects/models.py:12
#: subjects/templates/subjects/index.html:11
msgid "CIN"
msgstr "IČO"
#: subjects/forms.py:20
msgid "Enter the subject CIN, rest will be generated automatically"
msgstr "Zadejte IČO subjektu, zbytek bude generován automaticky"
#: subjects/forms.py:28
msgid "Add"
msgstr "Vytvořit"
#: subjects/models.py:8
msgid "Subject"
msgstr "Subjekt"
#: subjects/models.py:9 subjects/templates/subjects/index.html:4
#: templates/facturio/base.html:19
msgid "Subjects"
msgstr "Subjekty"
#: subjects/models.py:18 subjects/templates/subjects/index.html:12
msgid "Name"
msgstr "Jméno"
#: subjects/models.py:23 subjects/templates/subjects/index.html:13
msgid "VAT ID"
msgstr "IČO"
#: subjects/models.py:30 subjects/templates/subjects/index.html:14
msgid "Street"
msgstr "Ulice"
#: subjects/models.py:35 subjects/templates/subjects/index.html:15
msgid "Zip Code"
msgstr "PSČ"
#: subjects/models.py:40 subjects/templates/subjects/index.html:16
msgid "City"
msgstr "Město"
#: subjects/models.py:45 subjects/templates/subjects/index.html:17
msgid "City part"
msgstr "Část města"
#: subjects/templates/subjects/create.html:6
msgid "Create Subjects"
msgstr "Vytvořit Subjekty"
#: subjects/templates/subjects/index.html:7
msgid "Add new"
msgstr "Přidat nový"
#: templates/facturio/base.html:8 templates/facturio/index.html:4
msgid "App"
msgstr "Aplikace"
#: templates/facturio/base.html:31
msgid "Profile"
msgstr "Profil"
#: templates/facturio/base.html:34
msgid "Logout"
msgstr "Odhlásit se"

View file

@ -25,7 +25,7 @@ class CreateSubjectForm(forms.Form):
self.helper = helper.FormHelper() self.helper = helper.FormHelper()
self.helper.form_action = "subjects:create" self.helper.form_action = "subjects:create"
self.helper.form_method = "post" self.helper.form_method = "post"
self.helper.add_input(layout.Submit('submit', 'Add')) self.helper.add_input(layout.Submit('submit', _('Add')))
def clean_cin(self): def clean_cin(self):
cin = self.cleaned_data.get("cin") cin = self.cleaned_data.get("cin")

View file

@ -4,6 +4,10 @@ from django.utils.translation import gettext_lazy as _
class Subject(models.Model): class Subject(models.Model):
class Meta:
verbose_name = _("Subject")
verbose_name_plural = _("Subjects")
id = models.CharField( id = models.CharField(
_("CIN"), _("CIN"),
max_length=8, max_length=8,

View file

@ -1,8 +1,9 @@
{% extends "facturio/base.html" %} {% extends "facturio/base.html" %}
{% load i18n %}
{% load crispy_forms_tags %} {% load crispy_forms_tags %}
{% block title %}Create Subjects{% endblock %} {% block title %}{% trans "Create Subjects" %}{% endblock %}
{% block content %} {% block content %}
{% crispy form form.helper %} {% crispy form form.helper %}

View file

@ -1,19 +1,20 @@
{% extends "facturio/base.html" %} {% extends "facturio/base.html" %}
{% load i18n %}
{% block title %}Subjects{% endblock %} {% block title %}{% trans "Subjects" %}{% endblock %}
{% block content %} {% block content %}
<a href="{% url "subjects:create" %}" class="btn btn-primary" role="button">Add new</a> <a href="{% url "subjects:create" %}" class="btn btn-primary" role="button">{% trans "Add new" %}</a>
<table class="table"> <table class="table">
<thead> <thead>
<tr> <tr>
<th>CIN</th> <th>{% trans "CIN" %}</th>
<th>Name</th> <th>{% trans "Name" %}</th>
<th>VAT ID</th> <th>{% trans "VAT ID" %}</th>
<th>Street</th> <th>{% trans "Street" %}</th>
<th>Zip Code</th> <th>{% trans "Zip Code" %}</th>
<th>City</th> <th>{% trans "City" %}</th>
<th>City part</th> <th>{% trans "City part" %}</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>

View file

@ -1,9 +1,11 @@
{% load i18n %}
<!DOCTYPE html> <!DOCTYPE html>
<html lang="cs"> <html lang="cs">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"/> <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>Facturio - {% block title %}App{% endblock %}</title> {# FIXME: this is not translating correctly!! #}
<title>Facturio - {% block title %}{% trans "App" %}{% endblock %}</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet" <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" crossorigin="anonymous"> integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" crossorigin="anonymous">
</head> </head>
@ -14,7 +16,7 @@
<div class="collapse navbar-collapse"> <div class="collapse navbar-collapse">
<ul class="navbar-nav"> <ul class="navbar-nav">
<li class="nav-item"> <li class="nav-item">
<a class="nav-link" href="{% url "subjects:list" %}">Subjects</a> <a class="nav-link" href="{% url "subjects:list" %}">{% trans "Subjects" %}</a>
</li> </li>
{#<li class="nav-item">#} {#<li class="nav-item">#}
{# <a class="nav-link" href="#">Item 2</a>#} {# <a class="nav-link" href="#">Item 2</a>#}
@ -26,17 +28,18 @@
<ul class="navbar-nav"> <ul class="navbar-nav">
{% if request.user.is_authenticated %} {% if request.user.is_authenticated %}
<li class="nav-item"> <li class="nav-item">
<a class="nav-link" href="{% url 'accounts:me' %}">Profile</a> <a class="nav-link" href="{% url 'accounts:me' %}">{% trans "Profile" %}</a>
</li> </li>
<li class="nav-item"> <li class="nav-item">
<a class="nav-link" href="{% url 'accounts:logout' %}">Logout</a> <a class="nav-link" href="{% url 'accounts:logout' %}">{% trans "Logout" %}</a>
</li> </li>
{% else %} {% else %}
{# FIXME: this is not translating correctly!! #}
<li class="nav-item"> <li class="nav-item">
<a class="nav-link" href="{% url 'accounts:login' %}">Login</a> <a class="nav-link" href="{% url 'accounts:login' %}">{% trans "Login" %}</a>
</li> </li>
<li class="nav-item"> <li class="nav-item">
<a class="nav-link" href="{% url 'accounts:register' %}">Register</a> <a class="nav-link" href="{% url 'accounts:register' %}">{% trans "Register" %}</a>
</li> </li>
{% endif %} {% endif %}
</ul> </ul>

View file

@ -1,2 +1,4 @@
{% extends "facturio/base.html" %} {% extends "facturio/base.html" %}
{% load i18n %}
{% block title %}{% trans "App" %}{% endblock %}