feat: add French localization support for character attributes and improve character display logic
All checks were successful
Build Docker Image / build (push) Successful in 1m18s
All checks were successful
Build Docker Image / build (push) Successful in 1m18s
- Added optional French names, affiliations, origins, and epithets to character records. - Updated character import logic to handle new French fields. - Enhanced character search and display components to show French names and epithets based on selected language. - Modified database schema to include French fields for characters. - Improved error handling in daily character setup to check for existing characters. - Refactored components to utilize helper functions for displaying names and attributes based on language.
This commit is contained in:
@@ -1,8 +1,57 @@
|
||||
<script lang="ts">
|
||||
import type { CharacterWithRelations } from "$lib/server/daily-character";
|
||||
import { t } from '$lib/i18n';
|
||||
import { language, t } from '$lib/i18n';
|
||||
|
||||
export let yesterdayCharacter: CharacterWithRelations | null;
|
||||
|
||||
$: isFrench = $language === 'fr';
|
||||
|
||||
function parseEpithets(value: unknown): string[] {
|
||||
if (Array.isArray(value)) {
|
||||
return value.filter((entry): entry is string => typeof entry === 'string' && entry.length > 0);
|
||||
}
|
||||
|
||||
if (typeof value === 'string') {
|
||||
try {
|
||||
const parsed = JSON.parse(value);
|
||||
if (Array.isArray(parsed)) {
|
||||
return parsed.filter((entry): entry is string => typeof entry === 'string' && entry.length > 0);
|
||||
}
|
||||
} catch {
|
||||
if (value.length > 0) {
|
||||
return [value];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
function getDisplayName(character: CharacterWithRelations): string {
|
||||
if (isFrench && typeof character.frName === 'string' && character.frName.length > 0) {
|
||||
return character.frName;
|
||||
}
|
||||
|
||||
return character.name;
|
||||
}
|
||||
|
||||
function getDisplayEpithets(character: CharacterWithRelations): string[] {
|
||||
const frenchEpithets = parseEpithets(character.frEpithets);
|
||||
if (isFrench && frenchEpithets.length > 0) {
|
||||
return frenchEpithets;
|
||||
}
|
||||
|
||||
return parseEpithets(character.epithets);
|
||||
}
|
||||
|
||||
function getWikiUrl(character: CharacterWithRelations): string {
|
||||
if (isFrench && typeof character.frUrl === 'string' && character.frUrl.length > 0) {
|
||||
return character.frUrl;
|
||||
}
|
||||
|
||||
return character.url || '';
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<section class="mt-8 rounded-3xl border border-white/10 bg-white/5 p-6 shadow-[0_24px_60px_rgba(0,0,0,0.45)] backdrop-blur">
|
||||
@@ -11,7 +60,7 @@
|
||||
{#if yesterdayCharacter.pictureUrl}
|
||||
<img
|
||||
src={yesterdayCharacter.pictureUrl}
|
||||
alt={yesterdayCharacter.name}
|
||||
alt={getDisplayName(yesterdayCharacter)}
|
||||
class="h-20 w-20 rounded-full border border-amber-200/40 object-cover"
|
||||
/>
|
||||
{:else}
|
||||
@@ -21,23 +70,32 @@
|
||||
{/if}
|
||||
<div class="flex-1">
|
||||
<p class="text-xs font-semibold uppercase tracking-[0.28em] text-amber-100">{$t.game.components.yesterdayCharacter.title}</p>
|
||||
<p class="mt-2 text-lg font-semibold text-white">{yesterdayCharacter.name}</p>
|
||||
{#if yesterdayCharacter.epithets}
|
||||
<p class="mt-2 text-lg font-semibold text-white">{getDisplayName(yesterdayCharacter)}</p>
|
||||
{#if getDisplayEpithets(yesterdayCharacter).length > 0}
|
||||
<p class="mt-1 text-sm text-slate-400">
|
||||
{typeof yesterdayCharacter.epithets === 'string'
|
||||
? JSON.parse(yesterdayCharacter.epithets).join(', ')
|
||||
: (yesterdayCharacter.epithets as string[]).join(', ')}
|
||||
{getDisplayEpithets(yesterdayCharacter).join(', ')}
|
||||
</p>
|
||||
{/if}
|
||||
</div>
|
||||
<a
|
||||
href={"https://onepiece.fandom.com/fr/wiki/" + yesterdayCharacter.url}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="w-full rounded-full border border-amber-200/40 bg-transparent px-5 py-3 text-sm font-semibold text-amber-100 transition hover:border-amber-200 hover:text-amber-50 sm:w-auto"
|
||||
>
|
||||
{$t.game.components.yesterdayCharacter.openPage}
|
||||
</a>
|
||||
{#if isFrench}
|
||||
<a
|
||||
href="https://onepiece.fandom.com/fr/wiki/{getWikiUrl(yesterdayCharacter)}"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="w-full rounded-full border border-amber-200/40 bg-transparent px-5 py-3 text-sm font-semibold text-amber-100 transition hover:border-amber-200 hover:text-amber-50 sm:w-auto"
|
||||
>
|
||||
{$t.game.components.yesterdayCharacter.openPage}
|
||||
</a>
|
||||
{:else}
|
||||
<a
|
||||
href="https://onepiece.fandom.com/wiki/{getWikiUrl(yesterdayCharacter)}"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="w-full rounded-full border border-amber-200/40 bg-transparent px-5 py-3 text-sm font-semibold text-amber-100 transition hover:border-amber-200 hover:text-amber-50 sm:w-auto"
|
||||
>
|
||||
{$t.game.components.yesterdayCharacter.openPage}
|
||||
</a>
|
||||
{/if}
|
||||
</div>
|
||||
{:else}
|
||||
<div class="flex flex-col items-center gap-5 text-center sm:flex-row sm:text-left">
|
||||
|
||||
Reference in New Issue
Block a user