Skip to content

Commit

Permalink
Merge pull request #42 from CentreForDigitalHumanities/feature/i18n
Browse files Browse the repository at this point in the history
Added localization and language switch
  • Loading branch information
oktaal authored Jun 26, 2024
2 parents a916e42 + af0d453 commit 1a30452
Show file tree
Hide file tree
Showing 41 changed files with 543 additions and 186 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ jobs:
strategy:
matrix:
python-version: ['3.8', '3.9']
node-version: ['14.x', '16.x']
node-version: ['18.x', '20.x']
steps:
- uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# cookiecutter-webapp-deluxe

[![Actions Status](https://github.com/UUDigitalHumanitiesLab/cookiecutter-webapp-deluxe/workflows/Tests/badge.svg)](https://github.com/UUDigitalHumanitiesLab/cookiecutter-webapp-deluxe/actions)
[![Actions Status](https://github.com/CentreForDigitalHumanities/cookiecutter-webapp-deluxe/workflows/Tests/badge.svg)](https://github.com/CentreForDigitalHumanities/cookiecutter-webapp-deluxe/actions)

A boilerplate for full-fledged web applications with [Django][1] backend, [Angular][2] frontend and [Selenium][3] functional tests.

Expand Down Expand Up @@ -47,7 +47,7 @@ These are all the external dependencies you'll need during or after project gene

```console
$ cd to/parent/directory/that/contains/all/your/projects/
$ cookiecutter gh:UUDigitalHumanitieslab/cookiecutter-webapp-deluxe --checkout develop
$ cookiecutter gh:CentreForDigitalHumanities/cookiecutter-webapp-deluxe --checkout develop
# (the plan is to change the latter command into `dh init`)
```

Expand Down
7 changes: 4 additions & 3 deletions cookiecutter.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,19 @@
"description": "{{cookiecutter.project_title}} will humanize all your digits!",
"author": "Research Software Lab, Centre for Digital Humanities, Utrecht University",
"author_url": "https://cdh.uu.nl/centre-for-digital-humanities/research-software-lab/",
"origin": "github:UUDigitalHumanitieslab/{{cookiecutter.slug}}",
"origin": "github:CentreForDigitalHumanities/{{cookiecutter.slug}}",
"database_name": "{{cookiecutter.slug}}",
"database_user": "{{cookiecutter.slug}}",
"database_password": "{{cookiecutter.slug}}",
"database_port": "5432",
"localizations": "en:english,nl:dutch",
"localizations": "en:English,nl:Nederlands",
"default_localization": "en",
"frontend": ["angular", "backbone"],
"frontend_port": "4200",
"backend_port": "8000",
"psql_command": "psql",
"virtualenv": ".env",
"virtualenv_command": "virtualenv {{cookiecutter.virtualenv}} -p %PYTHON% --prompt=\"({{cookiecutter.slug}}) \"",
"virtualenv_command": "virtualenv {{cookiecutter.virtualenv}} -p %PYTHON% --prompt=\"{{cookiecutter.slug}}\"",
"_copy_without_render": [
"frontend.backbone/src/core",
"frontend.backbone/gulpfile.ts",
Expand Down
7 changes: 6 additions & 1 deletion hooks/post_gen_project.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ def main(argv):
commit = initial_commit()
remote = add_remote()
db = create_db()
if db:
db = grant_db()
migrate = superuser = False
if db and backpack:
migrate = run_migrations()
Expand All @@ -91,7 +93,9 @@ def main(argv):
if not stage: print(git_add)
if not commit: print(initial_commit)
if not remote: print(add_remote)
if not db: print(create_db)
if not db:
print(create_db)
print(grant_db)
if not migrate: print(run_migrations)
if not superuser: print(create_superuser)
print(git_push)
Expand Down Expand Up @@ -176,6 +180,7 @@ def generate_backbone_translations():
# psql does not properly indicate failure; it always exits with 0.
# Fortunately, it is one of the last commands.
create_db = make_create_db_command(PSQL_COMMAND)
grant_db = make_access_db_command(PSQL_COMMAND)

git_push = Command('', ['git', 'push', '-u', 'origin', 'main', 'develop'])

Expand Down
2 changes: 1 addition & 1 deletion {{cookiecutter.slug}}/.github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ jobs:
strategy:
matrix:
python-version: ['3.8']
node-version: ['14.x', '16.x']
node-version: ['18.x', '20.x']
steps:
- uses: actions/checkout@v2
- name: Set up Python {{ "${{ matrix.python-version }}" }}
Expand Down
2 changes: 1 addition & 1 deletion {{cookiecutter.slug}}/.nvmrc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
v14.21.2
v18.20.3
1 change: 1 addition & 0 deletions {{cookiecutter.slug}}/backend/access_db.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
GRANT ALL ON SCHEMA public to {{cookiecutter.database_user}};
1 change: 1 addition & 0 deletions {{cookiecutter.slug}}/backend/create_db.sql
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
create user {{cookiecutter.database_user}} with createdb password '{{cookiecutter.database_password}}';
create database {{cookiecutter.database_name}};
grant all on database {{cookiecutter.database_name}} to {{cookiecutter.database_user}};
GRANT ALL ON SCHEMA public to {{cookiecutter.database_user}};
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'livereload',
'django.contrib.staticfiles',
'rest_framework',
'revproxy',
'example'
]

MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.locale.LocaleMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
{% if cookiecutter.frontend == "backend" %}
'livereload.middleware.LiveReloadScript',
{% endif %}
]

# Internationalization
# https://docs.djangoproject.com/en/3.0/topics/i18n/
LANGUAGES = [
{% set localizations = cookiecutter.localizations.split(',') %}
{%- for loc in localizations %}
{%- set code, name = loc.split(':') %}
('{{code}}', '{{name}}'),
{%- endfor %}
]
LANGUAGE_CODE = '{{cookiecutter.default_localization}}'

TIME_ZONE = 'Europe/Amsterdam'

USE_I18N = True

USE_TZ = True
19 changes: 19 additions & 0 deletions {{cookiecutter.slug}}/backend/{{cookiecutter.slug}}/i18n.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
from rest_framework.decorators import api_view
from rest_framework.request import Request
from rest_framework.response import Response
from django.conf import settings
from django.utils import translation


@api_view(["GET", "POST"])
def i18n(request: Request):
response = Response()
if request.method == "POST":
language = request.data["language"]
translation.activate(language)
response.set_cookie(settings.LANGUAGE_COOKIE_NAME, language)
else:
language = request.LANGUAGE_CODE

response.data = {"current": language, "supported": settings.LANGUAGES}
return response
18 changes: 13 additions & 5 deletions {{cookiecutter.slug}}/backend/{{cookiecutter.slug}}/index.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
from django.http import Http404, HttpResponse
from os import path
from django.http import HttpRequest, HttpResponse
from django.contrib.staticfiles import finders
from django.views.decorators.csrf import ensure_csrf_cookie
import mimetypes


@ensure_csrf_cookie
def index(request):
""" Thin wrapper for the static index.html that adds the CSRF cookie."""
return HttpResponse(content=open(finders.find('index.html')))
def index(request: HttpRequest):
"""Thin wrapper for the static index.html that adds the CSRF cookie."""
language = request.LANGUAGE_CODE
page = request.path[1:].split("/", 1)[0]
# pre-rendered version available?
location = finders.find(path.join(language, page, "index.html"))
if not location:
location = finders.find(path.join(language, "index.html"))

return HttpResponse(content=open(location))
41 changes: 1 addition & 40 deletions {{cookiecutter.slug}}/backend/{{cookiecutter.slug}}/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"""

import os
from {{cookiecutter.slug}}.common_settings import *

# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
Expand All @@ -28,32 +29,6 @@

# Application definition

INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'livereload',
'django.contrib.staticfiles',
'rest_framework',
'revproxy',
'example'
]

MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
{% if cookiecutter.frontend == "backend" %}
'livereload.middleware.LiveReloadScript',
{% endif %}
]

ROOT_URLCONF = '{{cookiecutter.slug}}.urls'

TEMPLATES = [
Expand Down Expand Up @@ -109,20 +84,6 @@
]


# Internationalization
# https://docs.djangoproject.com/en/3.0/topics/i18n/

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'Europe/Amsterdam'

USE_I18N = True

USE_L10N = True

USE_TZ = True


# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.0/howto/static-files/

Expand Down
2 changes: 2 additions & 0 deletions {{cookiecutter.slug}}/backend/{{cookiecutter.slug}}/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

from .index import index
from .proxy_frontend import proxy_frontend
from .i18n import i18n

from example.views import hooray as ExampleView # DELETEME, see below

Expand All @@ -44,5 +45,6 @@
'rest_framework.urls',
namespace='rest_framework',
)),
path('api/i18n/', i18n),
spa_url, # catch-all; unknown paths to be handled by a SPA
]
Loading

0 comments on commit 1a30452

Please sign in to comment.