Add language field and API

This commit is contained in:
Christian Cueni 2023-02-08 13:15:04 +01:00
parent b5e4c30d40
commit b667140d3e
7 changed files with 75 additions and 10 deletions

View File

@ -1,13 +1,15 @@
<script setup lang="ts"> <script setup lang="ts">
import { loadLocaleMessages, setI18nLanguage } from "@/i18n"; import type { availableLanguages } from "@/stores/user";
import { useUserStore } from "@/stores/user";
import * as log from "loglevel"; import * as log from "loglevel";
log.debug("AppFooter created"); log.debug("AppFooter created");
const userStore = useUserStore();
async function changeLocale(event: Event) { async function changeLocale(event: Event) {
const target = event.target as HTMLSelectElement; const target = event.target as HTMLSelectElement;
await loadLocaleMessages(target.value); userStore.setUserLanguages(target.value as availableLanguages);
setI18nLanguage(target.value);
} }
</script> </script>
@ -22,9 +24,16 @@ async function changeLocale(event: Event) {
<div class="lg:ml-8">Deutsch</div> <div class="lg:ml-8">Deutsch</div>
<!--div class="locale-changer"> <!--div class="locale-changer">
<select @change="changeLocale($event)"> <select @change="changeLocale($event)">
<option v-for="locale in ['de', 'fr']" :key="`locale-${locale}`" :value="locale">{{ locale }}</option> <option
v-for="locale in ['de', 'fr']"
:key="`locale-${locale}`"
:value="locale"
:selected="locale === userStore.language"
>
{{ locale }}
</option>
</select> </select>
</div--> </div -->
<div class="lg:ml-8">{{ $t("footer.contact") }}</div> <div class="lg:ml-8">{{ $t("footer.contact") }}</div>
</footer> </footer>
</template> </template>

View File

@ -6,7 +6,9 @@ import { createI18n } from "vue-i18n";
export const SUPPORT_LOCALES = ["de", "fr", "it"]; export const SUPPORT_LOCALES = ["de", "fr", "it"];
let i18n: any = null; let i18n: any = null;
export function setupI18n(options = { locale: "de", legacy: false }) { export function setupI18n(
options = { locale: "de", legacy: false, fallbackLocale: "de" }
) {
i18n = createI18n(options); i18n = createI18n(options);
setI18nLanguage(options.locale); setI18nLanguage(options.locale);
dayjs.locale(options.locale); dayjs.locale(options.locale);

View File

@ -1,12 +1,15 @@
import log from "loglevel"; import log from "loglevel";
import { bustItGetCache, itGetCached, itPost } from "@/fetchHelpers"; import { bustItGetCache, itGetCached, itPost } from "@/fetchHelpers";
import { loadLocaleMessages, setI18nLanguage } from "@/i18n";
import { useAppStore } from "@/stores/app"; import { useAppStore } from "@/stores/app";
import { defineStore } from "pinia"; import { defineStore } from "pinia";
const logoutRedirectUrl = import.meta.env.VITE_LOGOUT_REDIRECT; const logoutRedirectUrl = import.meta.env.VITE_LOGOUT_REDIRECT;
// typed state https://stackoverflow.com/questions/71012513/when-using-pinia-and-typescript-how-do-you-use-an-action-to-set-the-state // typed state https://stackoverflow.com/questions/71012513/when-using-pinia-and-typescript-how-do-you-use-an-action-to-set-the-state
export type availableLanguages = "de" | "fr" | "it";
export type UserState = { export type UserState = {
id: number; id: number;
first_name: string; first_name: string;
@ -17,6 +20,7 @@ export type UserState = {
is_superuser: boolean; is_superuser: boolean;
course_session_experts: number[]; course_session_experts: number[];
loggedIn: boolean; loggedIn: boolean;
language: availableLanguages;
}; };
const initialUserState: UserState = { const initialUserState: UserState = {
@ -29,8 +33,14 @@ const initialUserState: UserState = {
is_superuser: false, is_superuser: false,
course_session_experts: [], course_session_experts: [],
loggedIn: false, loggedIn: false,
language: "de",
}; };
async function setLocale(language: availableLanguages) {
await loadLocaleMessages(language);
setI18nLanguage(language);
}
export const useUserStore = defineStore({ export const useUserStore = defineStore({
id: "user", id: "user",
state: () => initialUserState as UserState, state: () => initialUserState as UserState,
@ -80,6 +90,12 @@ export const useUserStore = defineStore({
this.$state = data; this.$state = data;
this.loggedIn = true; this.loggedIn = true;
appStore.userLoaded = true; appStore.userLoaded = true;
await setLocale(data.language);
},
async setUserLanguages(language: availableLanguages) {
await setLocale(language);
this.$state.language = language;
await itPost("/api/core/me/", { language }, { method: "PUT" });
}, },
}, },
}); });

View File

@ -4,7 +4,6 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
("core", "0001_initial"), ("core", "0001_initial"),
] ]
@ -22,4 +21,13 @@ class Migration(migrations.Migration):
max_length=254, unique=True, verbose_name="email address" max_length=254, unique=True, verbose_name="email address"
), ),
), ),
migrations.AddField(
model_name="user",
name="language",
field=models.CharField(
choices=[("de", "Deutsch"), ("fr", "Français"), ("it", "Italiano")],
default="de",
max_length=2,
),
),
] ]

View File

@ -11,6 +11,12 @@ class User(AbstractUser):
If adding fields that need to be filled at user signup, If adding fields that need to be filled at user signup,
""" """
LANGUAGE_CHOICES = (
("de", "Deutsch"),
("fr", "Français"),
("it", "Italiano"),
)
# FIXME: look into it... # FIXME: look into it...
# objects = UserManager() # objects = UserManager()
avatar_url = models.CharField(max_length=254, blank=True, default="") avatar_url = models.CharField(max_length=254, blank=True, default="")
@ -19,6 +25,7 @@ class User(AbstractUser):
"SSO subscriber ID", unique=True, null=True, blank=True, default=None "SSO subscriber ID", unique=True, null=True, blank=True, default=None
) )
additional_json_data = JSONField(default=dict, blank=True) additional_json_data = JSONField(default=dict, blank=True)
language = models.CharField(max_length=2, choices=LANGUAGE_CHOICES, default="de")
objects = UserManager() objects = UserManager()

View File

@ -18,6 +18,15 @@ class UserSerializer(serializers.ModelSerializer):
"avatar_url", "avatar_url",
"is_superuser", "is_superuser",
"course_session_experts", "course_session_experts",
"language",
]
read_only_fields = [
"id",
"is_superuser",
"first_name",
"last_name",
"email",
"username",
] ]
def get_course_session_experts(self, obj): def get_course_session_experts(self, obj):

View File

@ -82,11 +82,25 @@ def vue_login(request):
) )
@api_view(["GET"]) @api_view(["GET", "PUT"])
def me_user_view(request): def me_user_view(request):
if request.user.is_authenticated: if not request.user.is_authenticated:
return Response(status=403)
if request.method == "GET":
return Response(UserSerializer(request.user).data) return Response(UserSerializer(request.user).data)
return Response(status=403)
if request.method == "PUT":
serializer = UserSerializer(
request.user,
data={"language": request.data.get("language", "de")},
partial=True,
)
if serializer.is_valid():
serializer.save()
return Response(UserSerializer(request.user).data)
return Response(status=400)
@api_view(["POST"]) @api_view(["POST"])