i18n: questions in all langs
minor: readme tweaks
This commit is contained in:
parent
6f87d74c34
commit
36c8115bb6
4 changed files with 58 additions and 29 deletions
17
README.md
17
README.md
|
|
@ -35,19 +35,18 @@ The newest at the moment of me writing this (December 16th 2025) are the (visual
|
||||||
- [x] en
|
- [x] en
|
||||||
- [ ] de
|
- [ ] de
|
||||||
- [ ] ua
|
- [ ] ua
|
||||||
- [ ] db: examstore add language field, api handle languages
|
- [x] db: examstore add language field, api handle languages (questions lang)
|
||||||
- [ ] db: (revise) script for processing, (revise and) share appropriate files
|
|
||||||
- [ ] 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
|
||||||
|
|
||||||
My intention is, to share access to test exams free of charge, you don't have to pay me - although you can, I greatly appreciate if you donate!
|
My intention is, to share access to test exams free of charge, you don't have to pay me - although you can, I greatly appreciate if you donate!
|
||||||
|
|
||||||
In the future I will host this project publicly `aaS`, and will probably put non-invasive, privacy friendly ads if it gains enough traction
|
I'm planning to host this project publicly and to put non-invasive ads if it gains enough traction
|
||||||
|
|
||||||
All data used by this software is public information by definition provided in the Polish Constitution - (article 61.)[https://www.sejm.gov.pl/prawo/konst/polski/kon1.htm], and can be acquired by either checking above links on the gov website, or by writing to the Ministry ((if something happened to be missing))[placeholder_for_post_about_missing_points_column]
|
All data used by this software is public information by definition provided in the Polish Constitution - [article 61.](https://www.sejm.gov.pl/prawo/konst/polski/kon1.htm), and can be acquired by either checking above links on the gov website, or by writing to the Ministry [(if something happened to be missing)](placeholder_for_post_about_missing_points_column) ==> (blog post to write in the future)
|
||||||
|
|
||||||
This project is a website mimicking an official driver's license theoritical exam (for different license categories) with a seperate media server, connected using drizzle ORM to a SQLite database
|
This project is a website mimicking an official driver's license theoritical exam (for all license categories provided by the Ministry: A, A1, A2, AM, B, B1, C, C1, D, D1, T, PT) with a seperate media http server (not included here), connected using drizzle ORM to a SQLite database
|
||||||
|
|
||||||
## Setup
|
## Setup
|
||||||
|
|
||||||
|
|
@ -57,7 +56,11 @@ This project utilizes `pnpm`, thus it is recommended
|
||||||
pnpm install
|
pnpm install
|
||||||
```
|
```
|
||||||
|
|
||||||
## Development Server
|
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
|
||||||
|
|
||||||
Start the development server on `http://localhost:3000`:
|
Start the development server on `http://localhost:3000`:
|
||||||
|
|
||||||
|
|
@ -65,7 +68,7 @@ Start the development server on `http://localhost:3000`:
|
||||||
pnpm run dev
|
pnpm run dev
|
||||||
```
|
```
|
||||||
|
|
||||||
## Production
|
### Production
|
||||||
|
|
||||||
Build the application for production:
|
Build the application for production:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -116,6 +116,7 @@ const {
|
||||||
} = await useLazyFetch<BasicQuestion[]>(`/api/basic`, {
|
} = await useLazyFetch<BasicQuestion[]>(`/api/basic`, {
|
||||||
query: {
|
query: {
|
||||||
category: examStore.category,
|
category: examStore.category,
|
||||||
|
lang: examStore.lang,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -126,6 +127,7 @@ const {
|
||||||
} = await useLazyFetch<AdvancedQuestion[]>(`/api/advanced`, {
|
} = await useLazyFetch<AdvancedQuestion[]>(`/api/advanced`, {
|
||||||
query: {
|
query: {
|
||||||
category: examStore.category,
|
category: examStore.category,
|
||||||
|
lang: examStore.lang,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,22 +9,34 @@ import categories from '~/categories';
|
||||||
export default defineEventHandler(async (event) => {
|
export default defineEventHandler(async (event) => {
|
||||||
const query = getQuery(event);
|
const query = getQuery(event);
|
||||||
const category = query.category;
|
const category = query.category;
|
||||||
|
const lang = query.lang;
|
||||||
|
|
||||||
if (category === '' || typeof category !== 'string') {
|
if (
|
||||||
throw createError({
|
typeof category !== 'string' ||
|
||||||
statusCode: 400,
|
!categories.includes(`${category.toUpperCase()}`)
|
||||||
statusMessage:
|
) {
|
||||||
'category argument has to be string (or not to be defined at all)',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (!categories.includes(`${category.toUpperCase()}`)) {
|
|
||||||
throw createError({
|
throw createError({
|
||||||
statusCode: 400,
|
statusCode: 400,
|
||||||
statusMessage: `category argument has to be equal to either: ${categories}`,
|
statusMessage: `category argument has to be equal to either: ${categories}`,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getFromDb(points: number, limit: number, category: string) {
|
if (
|
||||||
|
typeof lang !== 'string' ||
|
||||||
|
!['PL', 'EN', 'DE', 'UA'].includes(`${lang.toUpperCase()}`)
|
||||||
|
) {
|
||||||
|
throw createError({
|
||||||
|
statusCode: 400,
|
||||||
|
statusMessage: `lang argument has to be equal to either: pl, en, de, ua`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getFromDb(
|
||||||
|
points: number,
|
||||||
|
limit: number,
|
||||||
|
category: string,
|
||||||
|
lang: string,
|
||||||
|
) {
|
||||||
return await db
|
return await db
|
||||||
.select({
|
.select({
|
||||||
id: tasks_advanced.id,
|
id: tasks_advanced.id,
|
||||||
|
|
@ -45,7 +57,7 @@ export default defineEventHandler(async (event) => {
|
||||||
.where(
|
.where(
|
||||||
and(
|
and(
|
||||||
eq(categories_db.name, category.toUpperCase()),
|
eq(categories_db.name, category.toUpperCase()),
|
||||||
eq(questions_advanced.lang, 'PL'),
|
eq(questions_advanced.lang, lang.toUpperCase()),
|
||||||
eq(tasks_advanced.weight, points),
|
eq(tasks_advanced.weight, points),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
@ -57,7 +69,7 @@ export default defineEventHandler(async (event) => {
|
||||||
const randomizedQuestions: AdvancedQuestion[] = [];
|
const randomizedQuestions: AdvancedQuestion[] = [];
|
||||||
|
|
||||||
for (const [key, value] of Object.entries({ 1: 2, 2: 4, 3: 6 })) {
|
for (const [key, value] of Object.entries({ 1: 2, 2: 4, 3: 6 })) {
|
||||||
randomizedQuestions.push(...(await getFromDb(+key, value, category)));
|
randomizedQuestions.push(...(await getFromDb(+key, value, category, lang)));
|
||||||
}
|
}
|
||||||
return arrayShuffle(randomizedQuestions);
|
return arrayShuffle(randomizedQuestions);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -9,22 +9,34 @@ import categories from '~/categories';
|
||||||
export default defineEventHandler(async (event) => {
|
export default defineEventHandler(async (event) => {
|
||||||
const query = getQuery(event);
|
const query = getQuery(event);
|
||||||
const category = query.category;
|
const category = query.category;
|
||||||
|
const lang = query.lang;
|
||||||
|
|
||||||
if (category === '' || typeof category !== 'string') {
|
if (
|
||||||
throw createError({
|
typeof category !== 'string' ||
|
||||||
statusCode: 400,
|
!categories.includes(`${category.toUpperCase()}`)
|
||||||
statusMessage:
|
) {
|
||||||
'category argument has to be string (or not to be defined at all)',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (!categories.includes(`${category.toUpperCase()}`)) {
|
|
||||||
throw createError({
|
throw createError({
|
||||||
statusCode: 400,
|
statusCode: 400,
|
||||||
statusMessage: `category argument has to be equal to either: ${categories}`,
|
statusMessage: `category argument has to be equal to either: ${categories}`,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getFromDb(points: number, limit: number, category: string) {
|
if (
|
||||||
|
typeof lang !== 'string' ||
|
||||||
|
!['PL', 'EN', 'DE', 'UA'].includes(`${lang.toUpperCase()}`)
|
||||||
|
) {
|
||||||
|
throw createError({
|
||||||
|
statusCode: 400,
|
||||||
|
statusMessage: `lang argument has to be equal to either: pl, en, de, ua`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getFromDb(
|
||||||
|
points: number,
|
||||||
|
limit: number,
|
||||||
|
category: string,
|
||||||
|
lang: string,
|
||||||
|
) {
|
||||||
return await db
|
return await db
|
||||||
.select({
|
.select({
|
||||||
id: tasks.id,
|
id: tasks.id,
|
||||||
|
|
@ -39,7 +51,7 @@ export default defineEventHandler(async (event) => {
|
||||||
.where(
|
.where(
|
||||||
and(
|
and(
|
||||||
eq(categories_db.name, category.toUpperCase()),
|
eq(categories_db.name, category.toUpperCase()),
|
||||||
eq(questions.lang, 'PL'),
|
eq(questions.lang, lang.toUpperCase()),
|
||||||
eq(tasks.weight, points),
|
eq(tasks.weight, points),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
@ -51,7 +63,7 @@ export default defineEventHandler(async (event) => {
|
||||||
const randomizedQuestions: BasicQuestion[] = [];
|
const randomizedQuestions: BasicQuestion[] = [];
|
||||||
|
|
||||||
for (const [key, value] of Object.entries({ 1: 4, 2: 6, 3: 10 })) {
|
for (const [key, value] of Object.entries({ 1: 4, 2: 6, 3: 10 })) {
|
||||||
randomizedQuestions.push(...(await getFromDb(+key, value, category)));
|
randomizedQuestions.push(...(await getFromDb(+key, value, category, lang)));
|
||||||
}
|
}
|
||||||
return arrayShuffle(randomizedQuestions);
|
return arrayShuffle(randomizedQuestions);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue