Implementiere i18n für Frontend, Admin und Datenbank
This commit is contained in:
@@ -1,22 +1,15 @@
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
import { PrismaClient, Genre, Special } from '@prisma/client';
|
||||
import { getTodayISOString } from './dateUtils';
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
export async function getOrCreateDailyPuzzle(genreName: string | null = null) {
|
||||
export async function getOrCreateDailyPuzzle(genre: Genre | null = null) {
|
||||
try {
|
||||
const today = getTodayISOString();
|
||||
let genreId: number | null = null;
|
||||
|
||||
if (genreName) {
|
||||
const genre = await prisma.genre.findUnique({
|
||||
where: { name: genreName }
|
||||
});
|
||||
if (genre) {
|
||||
genreId = genre.id;
|
||||
} else {
|
||||
return null; // Genre not found
|
||||
}
|
||||
if (genre) {
|
||||
genreId = genre.id;
|
||||
}
|
||||
|
||||
let dailyPuzzle = await prisma.dailyPuzzle.findFirst({
|
||||
@@ -27,8 +20,6 @@ export async function getOrCreateDailyPuzzle(genreName: string | null = null) {
|
||||
include: { song: true },
|
||||
});
|
||||
|
||||
|
||||
|
||||
if (!dailyPuzzle) {
|
||||
// Get songs available for this genre
|
||||
const whereClause = genreId
|
||||
@@ -45,7 +36,7 @@ export async function getOrCreateDailyPuzzle(genreName: string | null = null) {
|
||||
});
|
||||
|
||||
if (allSongs.length === 0) {
|
||||
console.log(`[Daily Puzzle] No songs available for genre: ${genreName || 'Global'}`);
|
||||
console.log(`[Daily Puzzle] No songs available for genre: ${genre ? JSON.stringify(genre.name) : 'Global'}`);
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -80,7 +71,7 @@ export async function getOrCreateDailyPuzzle(genreName: string | null = null) {
|
||||
},
|
||||
include: { song: true },
|
||||
});
|
||||
console.log(`[Daily Puzzle] Created new puzzle for ${today} (Genre: ${genreName || 'Global'}) with song: ${selectedSong.title}`);
|
||||
console.log(`[Daily Puzzle] Created new puzzle for ${today} (Genre: ${genre ? JSON.stringify(genre.name) : 'Global'}) with song: ${selectedSong.title}`);
|
||||
} catch (e) {
|
||||
// Handle race condition
|
||||
console.log('[Daily Puzzle] Creation failed, trying to fetch again (likely race condition)');
|
||||
@@ -119,7 +110,7 @@ export async function getOrCreateDailyPuzzle(genreName: string | null = null) {
|
||||
artist: dailyPuzzle.song.artist,
|
||||
coverImage: dailyPuzzle.song.coverImage ? `/uploads/covers/${dailyPuzzle.song.coverImage}` : null,
|
||||
releaseYear: dailyPuzzle.song.releaseYear,
|
||||
genre: genreName
|
||||
genre: genre ? genre.name : null
|
||||
};
|
||||
|
||||
} catch (error) {
|
||||
@@ -128,16 +119,10 @@ export async function getOrCreateDailyPuzzle(genreName: string | null = null) {
|
||||
}
|
||||
}
|
||||
|
||||
export async function getOrCreateSpecialPuzzle(specialName: string) {
|
||||
export async function getOrCreateSpecialPuzzle(special: Special) {
|
||||
try {
|
||||
const today = getTodayISOString();
|
||||
|
||||
const special = await prisma.special.findUnique({
|
||||
where: { name: specialName }
|
||||
});
|
||||
|
||||
if (!special) return null;
|
||||
|
||||
let dailyPuzzle = await prisma.dailyPuzzle.findFirst({
|
||||
where: {
|
||||
date: today,
|
||||
@@ -232,7 +217,7 @@ export async function getOrCreateSpecialPuzzle(specialName: string) {
|
||||
artist: dailyPuzzle.song.artist,
|
||||
coverImage: dailyPuzzle.song.coverImage ? `/uploads/covers/${dailyPuzzle.song.coverImage}` : null,
|
||||
releaseYear: dailyPuzzle.song.releaseYear,
|
||||
special: specialName,
|
||||
special: special.name,
|
||||
maxAttempts: special.maxAttempts,
|
||||
unlockSteps: JSON.parse(special.unlockSteps),
|
||||
startTime: specialSong?.startTime || 0
|
||||
|
||||
41
lib/i18n.ts
Normal file
41
lib/i18n.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
export type LocalizedString = {
|
||||
[key: string]: string;
|
||||
};
|
||||
|
||||
export function getLocalizedValue(
|
||||
value: any,
|
||||
locale: string,
|
||||
fallback: string = ''
|
||||
): string {
|
||||
if (!value) return fallback;
|
||||
|
||||
// If it's already a string, return it (backward compatibility or simple values)
|
||||
if (typeof value === 'string') return value;
|
||||
|
||||
// If it's an object, try to get the requested locale
|
||||
if (typeof value === 'object') {
|
||||
if (value[locale]) return value[locale];
|
||||
|
||||
// Fallback to 'de'
|
||||
if (value['de']) return value['de'];
|
||||
|
||||
// Fallback to 'en'
|
||||
if (value['en']) return value['en'];
|
||||
|
||||
// Fallback to first key
|
||||
const keys = Object.keys(value);
|
||||
if (keys.length > 0) return value[keys[0]];
|
||||
}
|
||||
|
||||
return fallback;
|
||||
}
|
||||
|
||||
export function createLocalizedObject(
|
||||
de: string,
|
||||
en?: string
|
||||
): LocalizedString {
|
||||
return {
|
||||
de: de.trim(),
|
||||
en: (en || de).trim()
|
||||
};
|
||||
}
|
||||
9
lib/navigation.ts
Normal file
9
lib/navigation.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { createNavigation } from 'next-intl/navigation';
|
||||
|
||||
export const locales = ['de', 'en'] as const;
|
||||
export const localePrefix = 'always'; // Default
|
||||
|
||||
export const { Link, redirect, usePathname, useRouter } = createNavigation({
|
||||
locales,
|
||||
localePrefix
|
||||
});
|
||||
Reference in New Issue
Block a user