🌐 Added some missing translations
This commit is contained in:
@@ -132,7 +132,7 @@
|
||||
{#if selected_question + 1 === quiz_data.questions.length && ((timer_res === '0' && question_results !== null) || quiz_data?.questions?.[selected_question]?.type === QuizQuestionType.SLIDE)}
|
||||
{#if JSON.stringify(final_results) === JSON.stringify([null])}
|
||||
<button on:click={get_final_results} class="admin-button"
|
||||
>Get final results
|
||||
>{$t('admin_page.get_final_results')}
|
||||
</button>
|
||||
{/if}
|
||||
{:else if timer_res === '0' || selected_question === -1}
|
||||
@@ -142,7 +142,7 @@
|
||||
set_question_number(selected_question + 1);
|
||||
}}
|
||||
class="admin-button"
|
||||
>Next Question ({selected_question + 2})
|
||||
>{$t('admin_page.next_question', { question: selected_question + 2 })}
|
||||
</button>
|
||||
{/if}
|
||||
{#if question_results === null && selected_question !== -1}
|
||||
@@ -152,11 +152,11 @@
|
||||
set_question_number(selected_question + 1);
|
||||
}}
|
||||
class="admin-button"
|
||||
>Next Question ({selected_question + 2})
|
||||
>{$t('admin_page.next_question', { question: selected_question + 2 })}
|
||||
</button>
|
||||
{:else}
|
||||
<button on:click={get_question_results} class="admin-button"
|
||||
>Show results
|
||||
>{$t('admin_page.show_results')}
|
||||
</button>
|
||||
{/if}
|
||||
{/if}
|
||||
@@ -167,11 +167,11 @@
|
||||
set_question_number(selected_question + 1);
|
||||
}}
|
||||
class="admin-button"
|
||||
>Next Question ({selected_question + 2})
|
||||
>{$t('admin_page.next_question', { question: selected_question + 2 })}
|
||||
</button>
|
||||
{:else}
|
||||
<button on:click={show_solutions} class="admin-button"
|
||||
>Stop time and show solutions
|
||||
>{$t('admin_page.stop_time_and_solutions')}
|
||||
</button>
|
||||
{/if}
|
||||
{:else}
|
||||
@@ -262,7 +262,7 @@
|
||||
</div>
|
||||
{:else}
|
||||
<div class="flex justify-center">
|
||||
<p class="text-2xl">Enter your answer into the input field!</p>
|
||||
<p class="text-2xl">{$t('admin_page.enter_answer_into_field')}</p>
|
||||
</div>
|
||||
{/if}
|
||||
{/if}
|
||||
|
||||
@@ -11,6 +11,9 @@
|
||||
import SettingsCard from '$lib/editor/settings-card.svelte';
|
||||
import QuizCard from '$lib/editor/card.svelte';
|
||||
import Spinner from './Spinner.svelte';
|
||||
import { getLocalization } from '$lib/i18n';
|
||||
|
||||
const { t } = getLocalization();
|
||||
|
||||
let schemaInvalid = false;
|
||||
let yupErrorMessage = '';
|
||||
@@ -152,10 +155,10 @@
|
||||
</p>
|
||||
{/if}
|
||||
<button
|
||||
class="pr-2 align-middle bg-purple-400 pl-2 ml-auto whitespace-nowrap disabled:opacity-60 rounded-br-lg"
|
||||
class="pr-2 align-middle bg-[#B07156] pl-2 ml-auto whitespace-nowrap disabled:opacity-60 rounded-br-lg"
|
||||
disabled={schemaInvalid}
|
||||
>
|
||||
<span>Save</span>
|
||||
<span>{$t('words.save')}</span>
|
||||
<svg
|
||||
class="w-6 h-6 inline-block"
|
||||
fill="none"
|
||||
|
||||
@@ -80,7 +80,7 @@
|
||||
type="text"
|
||||
class="border-b-2 border-dotted w-5/6 text-center rounded-lg bg-transparent"
|
||||
style="background-color: {answer.color ?? 'transparent'}"
|
||||
placeholder="Empty..."
|
||||
placeholder={$t('editor.empty')}
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
|
||||
@@ -141,7 +141,7 @@
|
||||
type="text"
|
||||
class="border-b-2 border-dotted w-5/6 text-center rounded-lg bg-transparent"
|
||||
style="background-color: {answer.color ?? 'transparent'}"
|
||||
placeholder="Empty..."
|
||||
placeholder={$t('editor.empty')}
|
||||
/>
|
||||
<input
|
||||
class="rounded-lg p-1 border-black border"
|
||||
|
||||
@@ -74,7 +74,7 @@
|
||||
bind:value={answer.answer}
|
||||
type="text"
|
||||
class="border-b-2 border-dotted w-5/6 text-center rounded-lg bg-transparent"
|
||||
placeholder="Empty..."
|
||||
placeholder={$t('editor.empty')}
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
|
||||
@@ -79,7 +79,7 @@
|
||||
type="text"
|
||||
class="border-b-2 border-dotted w-5/6 text-center rounded-lg"
|
||||
style="background-color: {answer.color ?? 'transparent'}"
|
||||
placeholder="Empty..."
|
||||
placeholder={$t('editor.empty')}
|
||||
/>
|
||||
<input
|
||||
class="rounded-lg p-1 border-black border"
|
||||
|
||||
@@ -42,9 +42,15 @@
|
||||
.toString()
|
||||
.slice(0, 3);
|
||||
}
|
||||
};
|
||||
const set_unique = () => {
|
||||
unique = {};
|
||||
};
|
||||
$: correctTimeInput(data.questions[selected_question].time);
|
||||
$: {
|
||||
selected_question;
|
||||
set_unique();
|
||||
}
|
||||
/*
|
||||
if (typeof data.questions[selected_question].type !== QuizQuestionType) {
|
||||
console.log(data.questions[selected_question].type !== QuizQuestionType.ABCD || data.questions[selected_question].type !== QuizQuestionType.RANGE)
|
||||
|
||||
@@ -180,7 +180,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-center pt-10">
|
||||
<h3>Background-Image</h3>
|
||||
<h3>{$t('editor.bg_image')}</h3>
|
||||
</div>
|
||||
<div class="w-full flex justify-center -mt-8">
|
||||
{#if data.background_image}
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
import { reach } from 'yup';
|
||||
import { ABCDQuestionSchema, dataSchema } from '../yupSchemas';
|
||||
import { createTippy } from 'svelte-tippy';
|
||||
import { getLocalization } from '$lib/i18n';
|
||||
const { t } = getLocalization();
|
||||
|
||||
export let data: EditorData;
|
||||
export let selected_question = -1;
|
||||
@@ -78,7 +80,7 @@
|
||||
{#if data.title}
|
||||
{@html data.title}
|
||||
{:else}
|
||||
<i>No title...</i>
|
||||
<i>{$t('editor.no_title')}</i>
|
||||
{/if}
|
||||
</p>
|
||||
</div>
|
||||
@@ -121,7 +123,7 @@
|
||||
d="M3.055 11H5a2 2 0 012 2v1a2 2 0 002 2 2 2 0 012 2v2.945M8 3.935V5.5A2.5 2.5 0 0010.5 8h.5a2 2 0 012 2 2 2 0 104 0 2 2 0 012-2h1.064M15 20.488V18a2 2 0 012-2h3.064M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
|
||||
/>
|
||||
</svg>
|
||||
<span>Public</span>
|
||||
<span>{$t('words.public')}</span>
|
||||
{:else}
|
||||
<svg
|
||||
class="w-5 h-5 inline-block"
|
||||
@@ -137,7 +139,7 @@
|
||||
d="M13.875 18.825A10.05 10.05 0 0112 19c-4.478 0-8.268-2.943-9.543-7a9.97 9.97 0 011.563-3.029m5.858.908a3 3 0 114.243 4.243M9.878 9.878l4.242 4.242M9.88 9.88l-3.29-3.29m7.532 7.532l3.29 3.29M3 3l3.59 3.59m0 0A9.953 9.953 0 0112 5c4.478 0 8.268 2.943 9.543 7a10.025 10.025 0 01-4.132 5.411m0 0L21 21"
|
||||
/>
|
||||
</svg>
|
||||
<span>Private</span>
|
||||
<span>{$t('words.private')}</span>
|
||||
{/if}
|
||||
</button>
|
||||
</div>
|
||||
@@ -190,7 +192,7 @@
|
||||
class:dark:text-black={index === selected_question}
|
||||
>
|
||||
{#if question.question === ''}
|
||||
<span class="italic text-gray-500">No title...</span>
|
||||
<span class="italic text-gray-500">{$t('editor.no_title')}</span>
|
||||
{:else}
|
||||
{@html question.question}
|
||||
{/if}
|
||||
@@ -222,10 +224,11 @@
|
||||
'answer'
|
||||
).isValidSync(answer.answer)}
|
||||
use:tippy={{
|
||||
content: answer.answer === '' ? 'Empty...' : answer.answer
|
||||
content:
|
||||
answer.answer === '' ? $t('editor.empty') : answer.answer
|
||||
}}
|
||||
>{#if answer.answer === ''}
|
||||
<i>Empty...</i>
|
||||
<i>{$t('editor.empty')}</i>
|
||||
{:else}
|
||||
{answer.answer}
|
||||
{/if}</span
|
||||
@@ -252,10 +255,11 @@
|
||||
'answer'
|
||||
).isValidSync(answer.answer)}
|
||||
use:tippy={{
|
||||
content: answer.answer === '' ? 'Empty...' : answer.answer
|
||||
content:
|
||||
answer.answer === '' ? $t('editor.empty') : answer.answer
|
||||
}}
|
||||
>{#if answer.answer === ''}
|
||||
<i>Empty...</i>
|
||||
<i>{$t('editor.empty')}</i>
|
||||
{:else}
|
||||
{answer.answer}
|
||||
{/if}</span
|
||||
@@ -280,7 +284,7 @@
|
||||
data.questions = [...data.questions, { ...empty_question }];
|
||||
}}
|
||||
>
|
||||
<span class="w-full text-center">Question</span>
|
||||
<span class="w-full text-center">{$t('words.question')}</span>
|
||||
<svg
|
||||
class="w-5/6 m-auto"
|
||||
fill="none"
|
||||
@@ -303,7 +307,7 @@
|
||||
data.questions = [...data.questions, { ...empy_slide }];
|
||||
}}
|
||||
>
|
||||
<span class="w-full text-center">Slide</span>
|
||||
<span class="w-full text-center">{$t('words.slide')}</span>
|
||||
<svg
|
||||
class="w-5/6 m-auto"
|
||||
fill="none"
|
||||
|
||||
@@ -7,7 +7,9 @@
|
||||
import { ElementTypes } from '$lib/quiz_types';
|
||||
import { onMount } from 'svelte';
|
||||
import { fade } from 'svelte/transition';
|
||||
import { getLocalization } from '$lib/i18n';
|
||||
|
||||
const { t } = getLocalization();
|
||||
export let selected_element;
|
||||
const keybinding_list = {
|
||||
t: ElementTypes.Text,
|
||||
@@ -40,22 +42,22 @@
|
||||
shortcut: string;
|
||||
}> = [
|
||||
{
|
||||
name: 'Headline',
|
||||
description: 'A bold text for headlines',
|
||||
name: $t('editor.slide.headline'),
|
||||
description: $t('editor.slide.headline_description'),
|
||||
type: ElementTypes.Headline,
|
||||
icon: undefined,
|
||||
shortcut: 'h'
|
||||
},
|
||||
{
|
||||
name: 'Text',
|
||||
description: 'Smaller longer text',
|
||||
name: $t('editor.slide.text'),
|
||||
description: $t('editor.slide.text_description'),
|
||||
type: ElementTypes.Text,
|
||||
icon: undefined,
|
||||
shortcut: 't'
|
||||
},
|
||||
{
|
||||
name: 'Rectangle',
|
||||
description: 'Just a rectangle',
|
||||
name: $t('editor.slide.rectangle'),
|
||||
description: $t('editor.slide.rectangle_description'),
|
||||
type: ElementTypes.Rectangle,
|
||||
icon: undefined,
|
||||
shortcut: 'r'
|
||||
|
||||
@@ -48,7 +48,8 @@
|
||||
"community_driven_content": "ClassQuiz hängt von der Community ab, die ClassQuiz mit Spenden, Feature-Requests, Übersetzungen und mehr versorgt! Du kannst auch ein Teil der ClassQuiz-Community werden!",
|
||||
"download_quizzes_content": "Quiz können als einzige Datei heruntergeladen werden und jederzeit importiert werden, sodass du auch einfach auf eine andere Instanz von ClassQuiz umziehen kannst!",
|
||||
"community_driven": "Von der Community betrieben",
|
||||
"download_quizzes": "Quiz herunterladen"
|
||||
"download_quizzes": "Quiz herunterladen",
|
||||
"how_does_classquiz_work": "Wie funktioniert ClassQuiz überhaupt?"
|
||||
},
|
||||
"overview_page": {
|
||||
"created_at": "Erstellt am",
|
||||
@@ -161,7 +162,8 @@
|
||||
"score": "Punkte",
|
||||
"results": "Ergebnisse",
|
||||
"note": "Notiz",
|
||||
"player_plural": "Spieler"
|
||||
"player_plural": "Spieler",
|
||||
"slide": "Folie"
|
||||
},
|
||||
"editor": {
|
||||
"time_in_seconds": "Zeit in Sekunden",
|
||||
@@ -170,7 +172,10 @@
|
||||
"add_new_question": "Neue Frage hinzufügen",
|
||||
"delete_question": "Frage löschen",
|
||||
"delete_answer": "Antwort löschen",
|
||||
"not_all_links_imgur_links": "Nicht alle Links sind Imgur-Links!"
|
||||
"not_all_links_imgur_links": "Nicht alle Links sind Imgur-Links!",
|
||||
"no_title": "Kein Titel...",
|
||||
"empty": "Leer...",
|
||||
"bg_image": "Hintergrundbild"
|
||||
},
|
||||
"import": {
|
||||
"need_help": "",
|
||||
@@ -279,5 +284,8 @@
|
||||
"time_taken": "benötigte Zeit",
|
||||
"player_name": "Spielername",
|
||||
"correct_answer_plural": "{{count}} richtige Antworten"
|
||||
},
|
||||
"navbar": {
|
||||
"donate": "Spenden"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,7 +48,8 @@
|
||||
"download_quizzes": "Download Quizzes",
|
||||
"download_quizzes_content": "Quizzes can be downloaded as one file and imported at any time. This also lets you move your quizzes to other ClassQuiz instances.",
|
||||
"community_driven": "Community-driven",
|
||||
"community_driven_content": "ClassQuiz depends on its community for funding, testing ideas, feature requests, translations and more! You can also be a part of the ClassQuiz-community!"
|
||||
"community_driven_content": "ClassQuiz depends on its community for funding, testing ideas, feature requests, translations and more! You can also be a part of the ClassQuiz-community!",
|
||||
"how_does_classquiz_work": "How does ClassQuiz even work?"
|
||||
},
|
||||
"overview_page": {
|
||||
"created_at": "Created at",
|
||||
@@ -161,7 +162,13 @@
|
||||
"results": "Results",
|
||||
"note": "Note",
|
||||
"player_plural": "Players",
|
||||
"score": "Score"
|
||||
"score": "Score",
|
||||
"slide": "Slide",
|
||||
"name": "Name",
|
||||
"point": "Point",
|
||||
"point_plural": "Points",
|
||||
"back": "Back",
|
||||
"finish": "Finish"
|
||||
},
|
||||
"editor": {
|
||||
"time_in_seconds": "Time in seconds",
|
||||
@@ -170,7 +177,18 @@
|
||||
"add_new_question": "Add new question",
|
||||
"delete_question": "Delete question",
|
||||
"delete_answer": "Delete answer",
|
||||
"not_all_links_imgur_links": "Not all links are Imgur-links!"
|
||||
"not_all_links_imgur_links": "Not all links are Imgur-links!",
|
||||
"no_title": "No title...",
|
||||
"empty": "Empty...",
|
||||
"bg_image": "Background image",
|
||||
"slide": {
|
||||
"headline": "Headline",
|
||||
"headline_description": "A bold text for headlines",
|
||||
"text": "Text",
|
||||
"text_description": "Smaller longer text",
|
||||
"rectangle": "Rectangle",
|
||||
"rectangle_description": "Just a rectangle"
|
||||
}
|
||||
},
|
||||
"import_page": {
|
||||
"need_help": "Need help?",
|
||||
@@ -194,7 +212,11 @@
|
||||
"start_by_showing_first_question": "Start by showing the first question.",
|
||||
"no_answers": "No answers!",
|
||||
"stop_time": "Stop time",
|
||||
"save_results": "Save results"
|
||||
"save_results": "Save results",
|
||||
"next_question": "Next Question ({{question}})",
|
||||
"show_results": "Show results",
|
||||
"stop_time_and_solutions": "Stop time and show solutions",
|
||||
"enter_answer_into_field": "Enter your answer into the input field!"
|
||||
},
|
||||
"password_reset_page": {
|
||||
"reset_password": "Reset password"
|
||||
@@ -207,7 +229,9 @@
|
||||
"last_seen": "Last seen",
|
||||
"check_location": "Check location",
|
||||
"delete_this_session": "Delete this session",
|
||||
"this_session?": "This session?"
|
||||
"this_session?": "This session?",
|
||||
"change_avatar": "Change avatar",
|
||||
"security_settings": "Security-Settings"
|
||||
},
|
||||
"explore_page": {
|
||||
"made_by": "Made by",
|
||||
@@ -222,7 +246,12 @@
|
||||
"1st_place": "1st Place",
|
||||
"2nd_place": "2nd Place",
|
||||
"3rd place": "3rd Place",
|
||||
"with_out_of": "with {{correct_questions}} out of {{total_question_count}}"
|
||||
"with_out_of": "with {{correct_questions}} out of {{total_question_count}}",
|
||||
"final_result_rank": "{{place}}: {{username}} with {{points}} points",
|
||||
"your_score": "Your score: {{score}}",
|
||||
"join_description": "Join at {{url}} and enter {{pin}}.",
|
||||
"join_by_entering_code": "Join by entering the following code",
|
||||
"points_added": "Points added"
|
||||
},
|
||||
"editor_page": {
|
||||
"add_an_answer": "Add an answer",
|
||||
@@ -257,7 +286,8 @@
|
||||
"clothe_color": "Clothing color",
|
||||
"clothe_graphic_type": "Graphic",
|
||||
"thats_you": "That's You!",
|
||||
"start_over": "Start over"
|
||||
"start_over": "Start over",
|
||||
"go_back": "Go back"
|
||||
},
|
||||
"results_page": {
|
||||
"no_results_so_far": "No results saved so far...",
|
||||
@@ -272,5 +302,35 @@
|
||||
"correct_answer": "{{count}} correct answer",
|
||||
"correct_answer_plural": "{{count}} correct answers",
|
||||
"time_taken": "Time taken"
|
||||
},
|
||||
"navbar": {
|
||||
"donate": "Donate"
|
||||
},
|
||||
"security_settings": {
|
||||
"backup_code": "Backup-Code",
|
||||
"get_backup_code": "Get Backup-Code",
|
||||
"activate_2fa": "Activate Two Factor Authentication",
|
||||
"2fa_activated": "Two Factor authentication is activated",
|
||||
"2fa_deactivated": "Two Factor authentication is deactivated",
|
||||
"webauthn": "Webauthn",
|
||||
"webauthn_available": "Webauthn is available",
|
||||
"webauthn_unavailable": "Webauthn is not available",
|
||||
"add_security_key": "Add Security-Key",
|
||||
"totp": "Totp",
|
||||
"totp_available": "Totp is available",
|
||||
"totp_unavailable": "Totp is not available",
|
||||
"disable_totp": "Disable Totp",
|
||||
"enable_totp": "Enable Totp",
|
||||
"backup_codes": {
|
||||
"your_backup_code": "Your Backup-Code",
|
||||
"save_somewhere_save": "Save this somewhere safe!",
|
||||
"download_code": "Download code"
|
||||
},
|
||||
"totp_setup": {
|
||||
"scan_to_set_up": "Scan this QR-code to set up the code",
|
||||
"enter_as_secret_if_no_see_code": "Enter this as the secret if you can't scan the QR-code",
|
||||
"totp_setup": "Totp-Setup",
|
||||
"do_not_forget_backup_code": "Do not forget to save your recovery-code!"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,7 +109,7 @@
|
||||
<ul id="menu-items" class="lg:flex w-full flex-col lg:flex-row" class:hidden={openMenu}>
|
||||
<li class="py-2 lg:hidden">
|
||||
<BrownButton href="https://mawoka.eu/donate" target="_blank"
|
||||
>Donate <span class="">❤️</span></BrownButton
|
||||
>{$t('navbar.donate')} <span class="">❤️</span></BrownButton
|
||||
>
|
||||
</li>
|
||||
{#if $signedIn}
|
||||
@@ -183,7 +183,7 @@
|
||||
>
|
||||
<div class="whitespace-nowrap hidden lg:block">
|
||||
<BrownButton href="https://mawoka.eu/donate" target="_blank"
|
||||
>Donate <span class="">❤️</span></BrownButton
|
||||
>{$t('navbar.donate')} <span class="">❤️</span></BrownButton
|
||||
>
|
||||
</div>
|
||||
{#if darkMode}
|
||||
|
||||
@@ -5,6 +5,9 @@
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { onMount } from 'svelte';
|
||||
import { getLocalization } from '$lib/i18n';
|
||||
|
||||
const { t } = getLocalization();
|
||||
|
||||
export let data;
|
||||
export let username;
|
||||
@@ -53,8 +56,11 @@
|
||||
style="font-size: {player_count_or_five - i / 2}rem"
|
||||
class="text-center"
|
||||
>
|
||||
{i + 1}
|
||||
: {player} with {data[player]} points
|
||||
{$t('play_page.final_result_rank', {
|
||||
place: i + 1,
|
||||
username: player,
|
||||
points: data[player]
|
||||
})}
|
||||
</p>
|
||||
{/if}
|
||||
{/each}
|
||||
@@ -62,7 +68,7 @@
|
||||
{#if data[username]}
|
||||
<div class="fixed bottom-0 left-0 flex justify-center w-full mb-6">
|
||||
<div class="mx-auto p-2 border-[#B07156] border-4 rounded">
|
||||
<p>Your score: <b>{data[username]}</b></p>
|
||||
<p>{$t('play_page.your_score', { score: data[username] })}</p>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
@@ -43,7 +43,10 @@
|
||||
<div class="grid grid-cols-3 mt-12">
|
||||
<div class="flex justify-center">
|
||||
<p class="m-auto text-2xl">
|
||||
Join at <b>{window.location.host}/play</b> and enter <b>{game_pin}</b>.
|
||||
{$t('play_page.join_description', {
|
||||
url: `${window.location.host}/play`,
|
||||
pin: game_pin
|
||||
})}
|
||||
</p>
|
||||
</div>
|
||||
<img
|
||||
@@ -54,7 +57,7 @@
|
||||
{#if cqc_code}
|
||||
<div class="m-auto">
|
||||
<div class="flex-col flex justify-center">
|
||||
<p class="mx-auto">Join by entering the following code</p>
|
||||
<p class="mx-auto">{$t('play_page.join_by_entering_code')}</p>
|
||||
<div class="flex flex-row gap-2 mx-auto">
|
||||
{#each cqc_code as c}
|
||||
<div class="flex flex-col">
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
import { flip } from 'svelte/animate';
|
||||
import { fly } from 'svelte/transition';
|
||||
import { onMount } from 'svelte';
|
||||
import { getLocalization } from '$lib/i18n';
|
||||
const { t } = getLocalization();
|
||||
|
||||
export let data;
|
||||
|
||||
@@ -91,11 +93,13 @@
|
||||
<div>
|
||||
<table class="table-auto text-xl">
|
||||
<tr>
|
||||
<th class="p-2 border-r border-r-black border-b-2 border-b-black">Name</th>
|
||||
<th class="p-2 border-b-2 border-b-black">Points</th>
|
||||
<th class="p-2 border-r border-r-black border-b-2 border-b-black"
|
||||
>{$t('words.name')}</th
|
||||
>
|
||||
<th class="p-2 border-b-2 border-b-black">{$t('words.point', { count: 2 })}</th>
|
||||
{#if show_new_score_clicked}
|
||||
<th in:fly={{ x: 300 }} class="p-2 border-b-2 border-b-black"
|
||||
>Points added
|
||||
>{$t('play_page.points_added')}
|
||||
</th>
|
||||
{/if}
|
||||
</tr>
|
||||
|
||||
@@ -208,7 +208,7 @@
|
||||
</div>
|
||||
</section>
|
||||
<section>
|
||||
<h2 class="text-center text-5xl mb-6">How does ClassQuiz even work?</h2>
|
||||
<h2 class="text-center text-5xl mb-6">{$t('index_page.how_does_classquiz_work')}</h2>
|
||||
|
||||
<div class="flex justify-center w-full">
|
||||
<h3 class="text-center text-3xl rounded-t-lg bg-opacity-40 bg-white py-2 px-6">
|
||||
|
||||
@@ -170,7 +170,9 @@
|
||||
alt="Profile image of {user.username}"
|
||||
/>
|
||||
<div class="m-2 flex justify-center">
|
||||
<BrownButton href="/account/settings/avatar">Change avatar</BrownButton>
|
||||
<BrownButton href="/account/settings/avatar"
|
||||
>{$t('settings_page.change_avatar')}</BrownButton
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid grid-rows-2 col-start-2 col-end-7">
|
||||
@@ -184,7 +186,7 @@
|
||||
<div class="p-4 flex justify-center">
|
||||
<div class="m-auto">
|
||||
<BrownButton href="/account/settings/security"
|
||||
>Security-Settings
|
||||
>{$t('settings_page.security_settings')}
|
||||
</BrownButton>
|
||||
</div>
|
||||
</div>
|
||||
@@ -219,7 +221,7 @@
|
||||
</div>
|
||||
</form>
|
||||
<div>
|
||||
<button on:click={add_api_key}>Add API-Key</button>
|
||||
<button on:click={add_api_key}>{$t('settings_page.security_settings')}</button>
|
||||
{#await api_keys}
|
||||
<Spinner />
|
||||
{:then keys}
|
||||
@@ -231,7 +233,7 @@
|
||||
delete_api_key(key.key);
|
||||
}}
|
||||
class="admin-button"
|
||||
>Delete
|
||||
>{$t('words.delete')}
|
||||
</button>
|
||||
</div>
|
||||
{/each}
|
||||
|
||||
@@ -94,7 +94,7 @@
|
||||
on:click={() => {
|
||||
index = index - 1;
|
||||
}}
|
||||
disabled={index < 1}>Back</BrownButton
|
||||
disabled={index < 1}>{$t('words.back')}</BrownButton
|
||||
>
|
||||
</div>
|
||||
<div class="mx-auto">
|
||||
@@ -103,7 +103,7 @@
|
||||
</h2>
|
||||
</div>
|
||||
<div class="ml-auto">
|
||||
<BrownButton disabled={index < 11}>Finish</BrownButton>
|
||||
<BrownButton disabled={index < 11}>{$t('words.finish')}</BrownButton>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid grid-cols-4">
|
||||
@@ -167,11 +167,11 @@
|
||||
<Spinner my_20={false} />
|
||||
{/if}
|
||||
</BrownButton>
|
||||
<BrownButton href="/account/settings">Go back</BrownButton>
|
||||
<BrownButton href="/account/settings">{$t('avatar_settings.go_back')}</BrownButton>
|
||||
<BrownButton
|
||||
on:click={() => {
|
||||
finished = false;
|
||||
}}>Close</BrownButton
|
||||
}}>{$t('words.close')}</BrownButton
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -10,6 +10,9 @@
|
||||
import TotpSetup from './totp_setup.svelte';
|
||||
import BackupCodes from './backup_codes.svelte';
|
||||
import BrownButton from '$lib/components/buttons/brown.svelte';
|
||||
import { getLocalization } from '$lib/i18n';
|
||||
|
||||
const { t } = getLocalization();
|
||||
|
||||
let user_data: object | undefined;
|
||||
let security_keys: Array<{ id: number }> | undefined;
|
||||
@@ -101,15 +104,17 @@
|
||||
<div class="grid grid-rows-2 h-screen">
|
||||
<div class="grid grid-cols-2 h-full border-b-2 border-black">
|
||||
<div class="h-full w-full border-r-2 border-black">
|
||||
<h2 class="text-center text-2xl">Backup-Code</h2>
|
||||
<h2 class="text-center text-2xl">{$t('security_settings.backup_code')}</h2>
|
||||
<div class="flex h-full w-full justify-center">
|
||||
<div class="m-auto">
|
||||
<BrownButton on:click={get_backup_code}>Get Backup-Codes</BrownButton>
|
||||
<BrownButton on:click={get_backup_code}
|
||||
>{$t('security_settings.get_backup_code')}</BrownButton
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="h-full w-full">
|
||||
<h2 class="text-center text-2xl">Activate 2 Factor</h2>
|
||||
<h2 class="text-center text-2xl">{$t('security_settings.activate_2fa')}</h2>
|
||||
<div class="flex h-full w-full justify-center flex-col">
|
||||
<div class="m-auto">
|
||||
{#if user_data.require_password}
|
||||
@@ -130,7 +135,7 @@
|
||||
/>
|
||||
</button>
|
||||
<span class="text-sm font-medium text-gray-700 dark:text-white"
|
||||
>Two Factor authentication is activated</span
|
||||
>{$t('security_settings.2fa_activated')}</span
|
||||
>
|
||||
</div>
|
||||
{:else}
|
||||
@@ -151,7 +156,7 @@
|
||||
/>
|
||||
</button>
|
||||
<span class="text-sm font-medium text-gray-700 dark:text-white"
|
||||
>Two Factor authentication is deactivated</span
|
||||
>{$t('security_settings.2fa_deactivated')}</span
|
||||
>
|
||||
</div>
|
||||
{/if}
|
||||
@@ -161,17 +166,19 @@
|
||||
</div>
|
||||
<div class="grid grid-cols-2 h-full">
|
||||
<div class="h-full w-full flex flex-col border-r-2 border-black">
|
||||
<h2 class="text-center text-2xl">Webauthn</h2>
|
||||
<h2 class="text-center text-2xl">{$t('security_settings.webauthn')}</h2>
|
||||
<div class="flex justify-center">
|
||||
{#if security_keys.length > 0}
|
||||
<p>Webauthn is available</p>
|
||||
<p>{$t('security_settings.webauthn_available')}</p>
|
||||
{:else}
|
||||
<p>Webauthn is not available</p>
|
||||
<p>{$t('security_settings.webauthn_unavailable')}</p>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="flex justify-center">
|
||||
<div class="m-auto">
|
||||
<BrownButton on:click={add_security_key}>Add Security-Key</BrownButton>
|
||||
<BrownButton on:click={add_security_key}
|
||||
>{$t('security_settings.add_security_key')}</BrownButton
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-center">
|
||||
@@ -190,21 +197,25 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="h-full w-full flex flex-col">
|
||||
<h2 class="text-center text-2xl">Totp</h2>
|
||||
<h2 class="text-center text-2xl">{$t('security_settings.totp')}</h2>
|
||||
<div class="flex justify-center">
|
||||
{#if totp_activated}
|
||||
<p>Totp is available</p>
|
||||
<p>{$t('security_settings.totp_available')}</p>
|
||||
{:else}
|
||||
<p>Totp is not available</p>
|
||||
<p>{$t('security_settings.totp_unavailable')}</p>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<div class="flex justify-center">
|
||||
<div class="m-auto">
|
||||
{#if totp_activated}
|
||||
<BrownButton on:click={disable_totp}>Disable Totp</BrownButton>
|
||||
<BrownButton on:click={disable_totp}
|
||||
>{$t('security_settings.disable_totp')}</BrownButton
|
||||
>
|
||||
{:else}
|
||||
<BrownButton on:click={enable_totp}>Enable Totp</BrownButton>
|
||||
<BrownButton on:click={enable_totp}
|
||||
>{$t('security_settings.enable_totp')}</BrownButton
|
||||
>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
- file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { getLocalization } from '$lib/i18n';
|
||||
|
||||
const { t } = getLocalization();
|
||||
export let backup_code;
|
||||
|
||||
let already_downloaded = false;
|
||||
@@ -30,12 +33,12 @@
|
||||
on:click={() => {
|
||||
backup_code = undefined;
|
||||
}}
|
||||
>Close
|
||||
>{$t('words.close')}
|
||||
</button>
|
||||
<div
|
||||
class="bg-white dark:bg-gray-700 rounded-b-lg rounded-tr-lg w-full h-full flex flex-col"
|
||||
>
|
||||
<h2 class="text-3xl m-auto">Your Backup-Code</h2>
|
||||
<h2 class="text-3xl m-auto">{$t('security_settings.backup_codes.your_backup_code')}</h2>
|
||||
<p
|
||||
class="select-all font-mono text-xl m-auto"
|
||||
on:click={() => {
|
||||
@@ -44,13 +47,14 @@
|
||||
>
|
||||
{backup_code}
|
||||
</p>
|
||||
<p class="m-auto">Save this somewhere safe!</p>
|
||||
<p class="m-auto">{$t('security_settings.backup_codes.save_somewhere_save')}</p>
|
||||
<button
|
||||
on:click={() => {
|
||||
download_code(true);
|
||||
}}
|
||||
class="m-auto p-2 bg-[#B07156] rounded-lg">Download code</button
|
||||
>
|
||||
class="m-auto p-2 bg-[#B07156] rounded-lg"
|
||||
>{$t('security_settings.backup_codes.download_code')}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -6,6 +6,9 @@
|
||||
<script lang="ts">
|
||||
import QRCode from 'qrcode';
|
||||
import Spinner from '$lib/Spinner.svelte';
|
||||
import { getLocalization } from '$lib/i18n';
|
||||
|
||||
const { t } = getLocalization();
|
||||
|
||||
export let totp_data: { url: string; secret: string } | undefined;
|
||||
|
||||
@@ -21,23 +24,25 @@
|
||||
on:click={() => {
|
||||
totp_data = undefined;
|
||||
}}
|
||||
>Close
|
||||
>{$t('words.close')}
|
||||
</button>
|
||||
<div class="bg-white dark:bg-gray-700 rounded-b-lg rounded-tr-lg w-full h-full">
|
||||
<div class="grid grid-cols-3 w-full h-full">
|
||||
<div class="flex flex-col justify-center w-full h-5/6">
|
||||
<span class="m-auto" />
|
||||
<div class="h-5/6 flex">
|
||||
<p class="my-auto ml-auto">Scan this to set up the code</p>
|
||||
<p class="my-auto ml-auto">
|
||||
{$t('security_settings.totp_setup.scan_to_set_up')}
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex">
|
||||
<p class="my-auto ml-auto">
|
||||
Enter this as the secret if you can't scan the code
|
||||
{$t('security_settings.totp_setup.enter_as_secret_if_no_see_code')}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col justify-start w-full h-5/6">
|
||||
<h2 class="text-2xl m-auto">Totp-Setup</h2>
|
||||
<h2 class="text-2xl m-auto">{$t('security_settings.totp_setup.totp_setup')}</h2>
|
||||
{#await get_image_url()}
|
||||
<Spinner my_20={false} />
|
||||
{:then data}
|
||||
@@ -52,7 +57,9 @@
|
||||
<p class="m-auto select-all font-mono">{totp_data.secret}</p>
|
||||
</div>
|
||||
<div class="flex justify-center h-5/6 w-full">
|
||||
<p class="m-auto text-3xl p-4">Do not forget to save your recovery-code!</p>
|
||||
<p class="m-auto text-3xl p-4">
|
||||
{$t('security_settings.totp_setup.do_not_forget_backup_code')}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -5,6 +5,9 @@
|
||||
-->
|
||||
<script lang="ts">
|
||||
import type { Question } from '$lib/quiz_types';
|
||||
import { getLocalization } from '$lib/i18n';
|
||||
|
||||
const { t } = getLocalization();
|
||||
|
||||
export let questions: Question[];
|
||||
export let answers: {
|
||||
@@ -41,10 +44,12 @@
|
||||
<div class="w-full">
|
||||
<div class="flex justify-center w-full">
|
||||
<p class="text-3xl w-5/6 text-center">
|
||||
The quiz with the title '<strong>{title}</strong>' was played on
|
||||
<strong>{new Date(timestamp).toLocaleString()}</strong>
|
||||
with <strong>{usernames.length}</strong> players. The players achieved an average score
|
||||
of <strong>{get_average_final_score()}</strong>.
|
||||
{$t('results_page.general_overview.sentence', {
|
||||
title,
|
||||
date: new Date(timestamp).toLocaleString(),
|
||||
player_count: usernames.length,
|
||||
average_score: get_average_final_score()
|
||||
})}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
<th class="border-r dark:border-gray-500 p-1 mx-auto border-gray-300"
|
||||
>{$t('result_page.player_name')}
|
||||
</th>
|
||||
<th class="p-1 mx-auto">Player Score</th>
|
||||
<th class="p-1 mx-auto">{$t('result_page.player_score')}</th>
|
||||
{#if Object.keys(custom_field).length !== 0}
|
||||
<th class="border-l dark:border-gray-500 p-1 mx-auto border-gray-300"
|
||||
>{$t('result_page.custom_field')}
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
<div class="grid grid-cols-6 h-full">
|
||||
<div class="pl-2">
|
||||
{#if data.user.username === undefined}
|
||||
<h2 class="text-4xl text-center p-4">User not found</h2>
|
||||
<h2 class="text-4xl text-center p-4">{$t('public_user_page.user_not_found')}</h2>
|
||||
{:else}
|
||||
<div class="flex justify-center">
|
||||
<img src={`/api/v1/users/avatar/${data.user.id}`} alt="profile" />
|
||||
@@ -49,7 +49,9 @@
|
||||
@{data.user.username}
|
||||
</h2>
|
||||
<p class="italic text-center">
|
||||
Joined on {new Date(data.user.created_at).toLocaleDateString()}
|
||||
{$t('public_user_page.joined_on', {
|
||||
date: new Date(data.user.created_at).toLocaleDateString()
|
||||
})}
|
||||
</p>
|
||||
{/if}
|
||||
</div>
|
||||
@@ -57,7 +59,7 @@
|
||||
class="col-start-2 col-end-7 border-l border-black h-full p-4 overflow-y-scroll flex flex-col gap-4"
|
||||
>
|
||||
{#if data.quizzes.length === 0}
|
||||
<p class="text-center text-4xl">No original quizzes found...</p>
|
||||
<p class="text-center text-4xl">{$t('public_user_page.no_original_quizzes')}</p>
|
||||
{:else}
|
||||
{#each data.quizzes as quiz}
|
||||
<div
|
||||
|
||||
@@ -71,7 +71,8 @@
|
||||
<p>{@html quiz.description}</p>
|
||||
</div>
|
||||
<p class="text-center">
|
||||
Made by <a href="/user/{quiz.user_id.id}" class="underline">@{quiz.user_id.username}</a>
|
||||
{$t('view_quiz_page.made_by')}
|
||||
<a href="/user/{quiz.user_id.id}" class="underline">@{quiz.user_id.username}</a>
|
||||
</p>
|
||||
{#if quiz.cover_image}
|
||||
<div class="flex justify-center align-middle items-center">
|
||||
@@ -95,7 +96,7 @@
|
||||
href="https://create.kahoot.it/details/{quiz.kahoot_id}"
|
||||
target="_blank"
|
||||
>
|
||||
View on <i>Kahoot!</i>
|
||||
{$t('view_quiz_page.view_on_kahoot')}
|
||||
</GrayButton>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
Reference in New Issue
Block a user