i18n: german ui, readme overhaul
compose: unless-stopped add source code, license, author notice at the bottom of index page
This commit is contained in:
parent
1100abf141
commit
08e2060245
4 changed files with 148 additions and 127 deletions
33
README.md
33
README.md
|
|
@ -2,40 +2,35 @@
|
||||||
|
|
||||||
## Required
|
## Required
|
||||||
|
|
||||||
The [db-prawo-jazdy](https://git.mandarynki.eu/netman/db-prawo-jazdy) project is designed for this one in mind, so use it in conjunction with this - visit it for more details
|
### db
|
||||||
|
|
||||||
^^ Above is kind of outdated, project moved from PostgreSQL to SQLite - I included a `database.db` file in the `db/` folder, although it has older dataset of questions from the Ministry - foreshadowing...
|
A python script at [db-prawo-jazdy](https://git.mandarynki.eu/netman/db-prawo-jazdy) is designed to convert the CSV(s) to a SQLite database for use here. When you acquire your database via that script, insert it at your desired path (default `./db/database.db`) and change the `DATABASE_URL` environment value in `.env`. Visit [db-prawo-jazdy](https://git.mandarynki.eu/netman/db-prawo-jazdy) for more details.
|
||||||
|
|
||||||
You also need the exam media files from the (Ministry of Infrasture)[https://www.gov.pl/web/infrastruktura/prawo-jazdy] - the latest files should be there
|
The database from November 2025 is included here at `./db/database.db`
|
||||||
|
|
||||||
The newest at the moment of me writing this (December 16th 2025) are the (visualisations for questions from November 2025)[https://www.gov.pl/pliki/mi/pytania_egzaminacyjne_na_prawo_jazdy_11_2025.zip]
|
### media
|
||||||
|
|
||||||
# To-do:
|
A shell script at [media-prawo-jazdy](https://git.mandarynki.eu/netman/media-prawo-jazdy) for media files ([available on the website of the Ministry of Infrastructure](https://www.gov.pl/web/infrastruktura/prawo-jazdy) under the link title `Pytania egzaminacyjne na prawo jazdy`) will convert (copy) all `.wmv` files to `.mp4` and copy all `.jpeg` files to `.jpg`. When you have all media and the script completed successfully, host these files on a webserver of your choice (e.g. apache, nginx), and change the `CDN_URL` environment value in `.env` to your webserver URL including the folder path to the media files. Visit [media-prawo-jazdy](https://git.mandarynki.eu/netman/media-prawo-jazdy) for more details.
|
||||||
|
|
||||||
|
## To-do:
|
||||||
|
|
||||||
- [x] re-forge database structure (good for now)
|
- [x] re-forge database structure (good for now)
|
||||||
- [x] choose category (good for now)
|
|
||||||
- [x] come up with how to show results appropriately
|
- [x] come up with how to show results appropriately
|
||||||
- [x] better answer click recognition
|
- [x] better answer click recognition
|
||||||
- [x] beautify website (good for now)
|
- [x] beautify website (good for now)
|
||||||
- [x] <b>Fixed?</b> Needs testing, but should be fine question-mark? - fix pinia middleware between pages, MAJOR ISSUE - finishing exam sometimes redirects to homepage instead of results
|
- [x] <b>Fixed?</b> Needs more testing, but should be fine. (question-mark?) - middleware between pages; finishing exam sometimes redirects to homepage instead of results, major issue
|
||||||
- [x] question timers
|
- [x] question timers
|
||||||
- [x] exam (& results?) warning leave message on exit and timer end (and definitely on refresh)
|
- [x] exam (& results?) warning leave message on exit and timer end (and definitely on refresh)
|
||||||
- [x] add keybinds:
|
- [x] add keybinds:
|
||||||
- S - start
|
- S - start, D - next question, X - exam end, T/Y - yes, N - no, A - A, B - B, C - C
|
||||||
- D - nast.pyt
|
|
||||||
- X - koniec egzaminu (na pewno chcesz zakonczyc egzamin?)
|
|
||||||
- T - Tak
|
|
||||||
- N - Nie
|
|
||||||
- A - A
|
|
||||||
- B - B
|
|
||||||
- C - C
|
|
||||||
- [ ] i18n - pl, en, de, ua (not all questions are available in ua, api handle)
|
- [ ] i18n - pl, en, de, ua (not all questions are available in ua, api handle)
|
||||||
- [ ] UI i18n
|
- [ ] UI i18n
|
||||||
- [x] pl
|
- [x] pl
|
||||||
- [x] en
|
- [x] en
|
||||||
- [ ] de
|
- [x] de
|
||||||
- [ ] ua
|
- [ ] ua
|
||||||
- [x] db: examstore add language field, api handle languages (questions lang)
|
- [x] db: examstore add language field, api handle languages (questions lang)
|
||||||
|
- [ ] nuxt3 -> nuxt4
|
||||||
- [ ] clean up js code in exam.vue and result.vue (currently a little bit of a mess)
|
- [ ] clean up js code in exam.vue and result.vue (currently a little bit of a mess)
|
||||||
|
|
||||||
## Some information about the project
|
## Some information about the project
|
||||||
|
|
@ -50,16 +45,14 @@ This project is a website mimicking an official driver's license theoritical exa
|
||||||
|
|
||||||
## Setup
|
## Setup
|
||||||
|
|
||||||
|
Copy `.env.example` to `.env` and modify it to values specified in the `Required#db` and `Required#media` sections according to your case.
|
||||||
|
|
||||||
This project utilizes `pnpm`, thus it is recommended
|
This project utilizes `pnpm`, thus it is recommended
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pnpm install
|
pnpm install
|
||||||
```
|
```
|
||||||
|
|
||||||
Check out `.env.example`, mainly CDN_URL for media http url
|
|
||||||
|
|
||||||
As of Dec. 16 2025 a test database is included at `./db/database.db`
|
|
||||||
|
|
||||||
### Development Server
|
### Development Server
|
||||||
|
|
||||||
Start the development server on `http://localhost:3000`:
|
Start the development server on `http://localhost:3000`:
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
services:
|
services:
|
||||||
prawojazdy:
|
prawojazdy:
|
||||||
|
restart: unless-stopped
|
||||||
container_name: prawojazdy
|
container_name: prawojazdy
|
||||||
build: .
|
build: .
|
||||||
ports:
|
ports:
|
||||||
|
|
|
||||||
|
|
@ -1,79 +1,79 @@
|
||||||
{
|
{
|
||||||
"mainTitle": "Test na prawo jazdy",
|
"mainTitle": "Führerscheinprüfung",
|
||||||
"loading": "Ładowanie",
|
"loading": "Laden",
|
||||||
"keybinds": "Skróty klawiszowe",
|
"keybinds": "Tastenkürzel",
|
||||||
"bindedKeys": {
|
"bindedKeys": {
|
||||||
"S": "niebieski przycisk start",
|
"S": "blauer „Start“-Button",
|
||||||
"D": "następne pytanie",
|
"D": "nächste Frage",
|
||||||
"X": "zakończ egzamin",
|
"X": "Prüfung beenden",
|
||||||
"T / Y": "Tak",
|
"T / Y": "Ja",
|
||||||
"N": "Nie",
|
"N": "Nein",
|
||||||
"A": "A",
|
"A": "A",
|
||||||
"B": "B",
|
"B": "B",
|
||||||
"C": "C"
|
"C": "C"
|
||||||
},
|
},
|
||||||
"yes": "Tak",
|
"yes": "Ja",
|
||||||
"no": "Nie",
|
"no": "Nein",
|
||||||
"theme": "Motyw",
|
"theme": "Design",
|
||||||
"light": "Jasny",
|
"light": "Hell",
|
||||||
"dark": "Ciemny",
|
"dark": "Dunkel",
|
||||||
"auto": "Automatyczny",
|
"auto": "Automatisch",
|
||||||
"endExam": "Zakończ egzamin",
|
"endExam": "Prüfung beenden",
|
||||||
"examEnd": "Koniec egzaminu",
|
"examEnd": "Prüfung beendet",
|
||||||
"basicQuestions": "Pytania podstawowe",
|
"basicQuestions": "Grundfragen",
|
||||||
"advancedQuestions": "Pytania specjalistyczne",
|
"advancedQuestions": "Spezialfragen",
|
||||||
"timeToGetAcquaintedWithTheQuestion": "Czas na zapoznanie się z pytaniem",
|
"timeToGetAcquaintedWithTheQuestion": "Zeit zum Lesen der Frage",
|
||||||
"timeForAnswer": "Czas na udzielenie odpowiedzi",
|
"timeForAnswer": "Antwortzeit",
|
||||||
"startBtn": "START",
|
"startBtn": "START",
|
||||||
"second": "s",
|
"second": "s",
|
||||||
"nextQuestion": "Następne pytanie",
|
"nextQuestion": "Nächste Frage",
|
||||||
"goBackToHomePage": "Wróć na stronę główną",
|
"goBackToHomePage": "Zur Startseite",
|
||||||
"points": "Punkty",
|
"points": "Punkte",
|
||||||
"pointValue": "Wartość punktowa",
|
"pointValue": "Punktwert",
|
||||||
"currentCategory": "Aktualna kategoria",
|
"currentCategory": "Aktuelle Kategorie",
|
||||||
"timeToExamEnd": "Czas do końca egzaminu",
|
"timeToExamEnd": "Verbleibende Prüfungszeit",
|
||||||
"result": "Wynik",
|
"result": "Ergebnis",
|
||||||
"startAgain": "Rozpocznij jeszcze raz",
|
"startAgain": "Erneut starten",
|
||||||
"viewAnswers": "Przejrzyj odpowiedzi",
|
"viewAnswers": "Antworten anzeigen",
|
||||||
"doYouReallyWantToEndExam": "Czy na pewno chcesz zakończyć egzamin?",
|
"doYouReallyWantToEndExam": "Möchten Sie die Prüfung wirklich beenden?",
|
||||||
"questionWithoutVisual": "Pytanie bez wizualizacji",
|
"questionWithoutVisual": "Frage ohne Visualisierung",
|
||||||
"categoryWord": "Kategoria",
|
"categoryWord": "Kategorie",
|
||||||
"anAnomalyHasOccured": "Nastąpiła anomalia",
|
"anAnomalyHasOccured": "Ein unerwarteter Fehler ist aufgetreten",
|
||||||
"redirectFrom": "Przekierowanie z",
|
"redirectFrom": "Weiterleitung von",
|
||||||
"end": "Koniec",
|
"end": "Ende",
|
||||||
"question": "Pytanie",
|
"question": "Frage",
|
||||||
"anAPIErrorOccured": "Wystąpił błąd z API",
|
"anAPIErrorOccured": "API-Fehler ist aufgetreten",
|
||||||
"positive": "pozytywny",
|
"positive": "Positiv",
|
||||||
"negative": "negatywny",
|
"negative": "Negativ",
|
||||||
"theoreticalExam": "Egzamin teorytyczny",
|
"theoreticalExam": "Theoretische Prüfung",
|
||||||
"category": {
|
"category": {
|
||||||
"description": {
|
"description": {
|
||||||
"A": "motocykle bez ograniczeń mocy",
|
"A": "Motorräder ohne Leistungsbegrenzung",
|
||||||
"B": "⭐ samochody osobowe do 3,5 t",
|
"B": "⭐ Personenkraftwagen bis 3,5 t",
|
||||||
"C": "pojazdy ciężarowe powyżej 3,5 t",
|
"C": "Lastkraftwagen über 3,5 t",
|
||||||
"D": "autobusy",
|
"D": "Busse",
|
||||||
"T": "ciągniki rolnicze i pojazdy wolnobieżne",
|
"T": "Landwirtschaftliche Traktoren und langsam fahrende Fahrzeuge",
|
||||||
"AM": "motorowery i lekkie czterokołowce",
|
"AM": "Mopeds und leichte Quadricycles",
|
||||||
"A1": "motocykle do 125 cm³ i 11 kW",
|
"A1": "Motorräder bis 125 cm³ und 11 kW",
|
||||||
"A2": "motocykle do 35 kW",
|
"A2": "Motorräder bis 35 kW",
|
||||||
"B1": "czterokołowce (np. quady)",
|
"B1": "Quadricycles (z. B. Quads)",
|
||||||
"C1": "pojazdy od 3,5 t do 7,5 t",
|
"C1": "Fahrzeuge von 3,5 t bis 7,5 t",
|
||||||
"D1": "autobusy do 16 pasażerów",
|
"D1": "Busse mit bis zu 16 Fahrgastplätzen",
|
||||||
"PT": "tramwaje"
|
"PT": "Straßenbahnen"
|
||||||
},
|
},
|
||||||
"age": {
|
"age": {
|
||||||
"A": "(24 lata; lub 20 lat jeśli masz kat. A2 min. 2 lata)",
|
"A": "(24 Jahre alt; oder 20 Jahre bei mindestens 2 Jahren Besitz der Klasse A2)",
|
||||||
"B": "(18 lat)",
|
"B": "(18 Jahre alt)",
|
||||||
"C": "(21 lat; lub 18 lat z kwalifikacją wstępną)",
|
"C": "(21 Jahre alt; oder 18 Jahre mit Grundqualifikation)",
|
||||||
"D": "(24 lata; lub 21 lat z kwalifikacją wstępną)",
|
"D": "(24 Jahre alt; oder 21 Jahre mit Grundqualifikation)",
|
||||||
"T": "(16 lat)",
|
"T": "(16 Jahre alt)",
|
||||||
"AM": "(14 lat)",
|
"AM": "(14 Jahre alt)",
|
||||||
"A1": "(16 lat)",
|
"A1": "(16 Jahre alt)",
|
||||||
"A2": "(18 lat)",
|
"A2": "(18 Jahre alt)",
|
||||||
"B1": "(16 lat)",
|
"B1": "(16 Jahre alt)",
|
||||||
"C1": "(18 lat)",
|
"C1": "(18 Jahre alt)",
|
||||||
"D1": "(21 lat; lub 18 lat z kwalifikacją wstępną)",
|
"D1": "(21 Jahre alt; oder 18 Jahre alt mit Grundqualifikation)",
|
||||||
"PT": "(21 lat)"
|
"PT": "(21 Jahre alt)"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
113
pages/index.vue
113
pages/index.vue
|
|
@ -63,53 +63,80 @@ function themeAuto() {
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div v-if="!loading" class="text-3xl m-2 flex flex-col gap-2">
|
<div v-if="!loading" class="text-3xl flex flex-col gap-2 min-h-dvh">
|
||||||
<span>{{ $t('mainTitle') }}</span>
|
<div class="flex flex-col p-2 gap-2">
|
||||||
<div class="flex gap-2">
|
<span>{{ $t('mainTitle') }}</span>
|
||||||
<CountryFlag
|
<div class="flex gap-2">
|
||||||
class="block border border-1 border-black"
|
<CountryFlag
|
||||||
:country="langSelect != 'en' ? langSelect : 'gb'"
|
class="block border border-1 border-black"
|
||||||
size="big"
|
:country="langSelect != 'en' ? langSelect : 'gb'"
|
||||||
/>
|
size="big"
|
||||||
<select v-model="langSelect" class="select" @change="changeLanguage">
|
|
||||||
<option value="pl">Polish (Polski)</option>
|
|
||||||
<option value="en">English</option>
|
|
||||||
<option value="de">German (Deutsch)</option>
|
|
||||||
<option value="ua">Ukrainian (Українська)</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div class="flex gap-2">
|
|
||||||
<label class="flex cursor-pointer gap-2 text-lg items-center">
|
|
||||||
{{ $t('theme') }}: {{ $t('light') }}
|
|
||||||
<input
|
|
||||||
v-model="dark"
|
|
||||||
type="checkbox"
|
|
||||||
value="dark"
|
|
||||||
class="toggle theme-controller"
|
|
||||||
@change="themeStore.set(dark ? 'dark' : 'light')"
|
|
||||||
/>
|
/>
|
||||||
{{ $t('dark') }}
|
<select v-model="langSelect" class="select" @change="changeLanguage">
|
||||||
</label>
|
<option value="pl">Polish (Polski)</option>
|
||||||
<div class="btn btn-soft btn-sm" @click="themeAuto()">
|
<option value="en">English</option>
|
||||||
{{ $t('auto') }}
|
<option value="de">German (Deutsch)</option>
|
||||||
|
<option value="ua">Ukrainian (Українська)</option>
|
||||||
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="flex gap-2">
|
||||||
<div
|
<label class="flex cursor-pointer gap-2 text-lg items-center">
|
||||||
class="flex flex-col flex-wrap gap-2 items-start p-4 bg-base-300 border-1 border-slate-500 rounded-xl w-fit"
|
{{ $t('theme') }}: {{ $t('light') }}
|
||||||
>
|
<input
|
||||||
<div
|
v-model="dark"
|
||||||
v-for="category in categories"
|
type="checkbox"
|
||||||
:key="`btn-${category}`"
|
value="dark"
|
||||||
class="flex flex-row gap-3 items-center"
|
class="toggle theme-controller"
|
||||||
>
|
@change="themeStore.set(dark ? 'dark' : 'light')"
|
||||||
<button class="btn btn-xl btn-secondary" @click="setAndGo(category)">
|
/>
|
||||||
{{ category }}
|
{{ $t('dark') }}
|
||||||
</button>
|
</label>
|
||||||
<div class="flex flex-col text-sm">
|
<div class="btn btn-soft btn-sm" @click="themeAuto()">
|
||||||
<div>{{ $t(`category.description.${category}`) }}</div>
|
{{ $t('auto') }}
|
||||||
<div>{{ $t(`category.age.${category}`) }}</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div
|
||||||
|
class="flex flex-col flex-wrap gap-2 items-start p-4 bg-base-300 border-1 border-slate-500 rounded-xl w-fit"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
v-for="category in categories"
|
||||||
|
:key="`btn-${category}`"
|
||||||
|
class="flex flex-row gap-3 items-center"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
class="btn btn-xl btn-secondary"
|
||||||
|
@click="setAndGo(category)"
|
||||||
|
>
|
||||||
|
{{ category }}
|
||||||
|
</button>
|
||||||
|
<div class="flex flex-col text-sm">
|
||||||
|
<div>{{ $t(`category.description.${category}`) }}</div>
|
||||||
|
<div>{{ $t(`category.age.${category}`) }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex-1"></div>
|
||||||
|
<div class="text-sm text-center bg-base-200 p-1">
|
||||||
|
<!--
|
||||||
|
You need to leave such an unavoidable mention as one below of the
|
||||||
|
original software, its creator and license - this is required under AGPL.
|
||||||
|
START MENTION
|
||||||
|
-->
|
||||||
|
<NuxtLink
|
||||||
|
class="link"
|
||||||
|
to="https://git.mandarynki.eu/netman/nuxt-prawo-jazdy"
|
||||||
|
>
|
||||||
|
nuxt-prawo-jazdy
|
||||||
|
</NuxtLink>
|
||||||
|
by
|
||||||
|
<NuxtLink class="link" to="https://netman.ovh">netman</NuxtLink>
|
||||||
|
(<NuxtLink
|
||||||
|
class="link"
|
||||||
|
to="https://git.mandarynki.eu/netman/nuxt-prawo-jazdy/src/branch/main/LICENSE"
|
||||||
|
>AGPL-3.0-only</NuxtLink
|
||||||
|
>)
|
||||||
|
<!-- END MENTION -->
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<LoadingScreen v-else />
|
<LoadingScreen v-else />
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue