feat: add French localization support for character attributes and improve character display logic
Build Docker Image / build (push) Successful in 1m18s
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:
@@ -2,9 +2,58 @@
|
||||
export let data;
|
||||
|
||||
import { resolve } from '$app/paths';
|
||||
import { t } from '$lib/i18n';
|
||||
import { language, t } from '$lib/i18n';
|
||||
import type { CharacterWithRelations } from '$lib/server/daily-character';
|
||||
|
||||
$: yesterdayCharacter = data.yesterdayCharacter;
|
||||
$: 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 | null): string {
|
||||
if (isFrench && typeof character?.frName === 'string' && character.frName.length > 0) {
|
||||
return character.frName;
|
||||
}
|
||||
|
||||
return character?.name || '';
|
||||
}
|
||||
|
||||
function getDisplayEpithets(character: CharacterWithRelations | null): string[] {
|
||||
const frenchEpithets = parseEpithets(character?.frEpithets);
|
||||
if (isFrench && frenchEpithets.length > 0) {
|
||||
return frenchEpithets;
|
||||
}
|
||||
|
||||
return parseEpithets(character?.epithets);
|
||||
}
|
||||
|
||||
function getWikiUrl(character: CharacterWithRelations | null): string {
|
||||
if (isFrench && typeof character?.frUrl === 'string' && character.frUrl.length > 0) {
|
||||
return character.frUrl;
|
||||
}
|
||||
|
||||
return character?.url || '';
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
@@ -57,7 +106,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}
|
||||
@@ -67,23 +116,32 @@
|
||||
{/if}
|
||||
<div class="flex-1">
|
||||
<p class="text-xs font-semibold uppercase tracking-[0.28em] text-amber-100">{$t.game.home.yesterdayCharacter}</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.home.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.home.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.home.openPage}
|
||||
</a>
|
||||
{/if}
|
||||
</div>
|
||||
{:else}
|
||||
<div class="flex flex-col items-center gap-5 text-center sm:flex-row sm:text-left">
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
import WinPanel from '$lib/components/WinPanel.svelte';
|
||||
import HintsPanel from '$lib/components/HintsPanel.svelte';
|
||||
import type { CharacterWithRelations } from '$lib/server/daily-character.js';
|
||||
import { t } from '$lib/i18n';
|
||||
import { language, t } from '$lib/i18n';
|
||||
|
||||
export let data;
|
||||
|
||||
@@ -213,16 +213,32 @@
|
||||
}
|
||||
|
||||
$: allCharacters = data.characters || [];
|
||||
$: isFrench = $language === 'fr';
|
||||
|
||||
function getDisplayArcName(character: CharacterWithRelations, useFrench: boolean): string | null {
|
||||
if (useFrench && typeof character.frArcName === 'string' && character.frArcName.length > 0) {
|
||||
return character.frArcName;
|
||||
}
|
||||
|
||||
return character.arcName;
|
||||
}
|
||||
|
||||
// Extract unique arcs from all characters
|
||||
$: {
|
||||
const useFrench = isFrench;
|
||||
const arcMap = new Map<string, ArcFilterOption>(
|
||||
allCharacters
|
||||
.filter(
|
||||
(char: CharacterWithRelations): char is CharacterWithRelations & { arcId: string; arcName: string } =>
|
||||
typeof char.arcId === 'string' && char.arcId.length > 0 && typeof char.arcName === 'string' && char.arcName.length > 0
|
||||
(char: CharacterWithRelations): char is CharacterWithRelations & { arcId: string } =>
|
||||
typeof char.arcId === 'string' &&
|
||||
char.arcId.length > 0 &&
|
||||
typeof getDisplayArcName(char, useFrench) === 'string' &&
|
||||
getDisplayArcName(char, useFrench)!.length > 0
|
||||
)
|
||||
.map((char: CharacterWithRelations & { arcId: string; arcName: string }) => [char.arcId, { id: char.arcId, name: char.arcName }])
|
||||
.map((char: CharacterWithRelations & { arcId: string }) => [
|
||||
char.arcId,
|
||||
{ id: char.arcId, name: getDisplayArcName(char, useFrench) as string }
|
||||
])
|
||||
);
|
||||
|
||||
availableArcs = [...arcMap.values()].sort((a, b) => a.name.localeCompare(b.name));
|
||||
|
||||
Reference in New Issue
Block a user