feat: Implement i18n infrastructure

This commit is contained in:
2025-12-13 17:29:27 +09:00
parent 2fc8a32b5f
commit cae08acab3
10 changed files with 578 additions and 166 deletions
+12 -10
View File
@@ -3,6 +3,7 @@ import React from 'react';
import { Playlist, ServerType, PlexServerConnection } from '../types';
import PlaylistCard from './PlaylistCard';
import { RefreshCw, Server, Cloud, WifiOff, X } from 'lucide-react';
import { useLanguage } from '../LanguageContext';
interface ServerPanelProps {
type: ServerType;
@@ -14,6 +15,7 @@ interface ServerPanelProps {
}
const ServerPanel: React.FC<ServerPanelProps> = ({ type, playlists, isLoading, onRefresh, onCancel, serverInfo }) => {
const { t } = useLanguage();
const isLocal = type === ServerType.LOCAL;
let Icon = isLocal ? Server : Cloud;
@@ -28,17 +30,17 @@ const ServerPanel: React.FC<ServerPanelProps> = ({ type, playlists, isLoading, o
let displaySubtitle: React.ReactNode = null;
if (isLocal) {
displayTitle = 'Local Server';
displayTitle = t('server.local');
displaySubtitle = (
<p className="text-xs text-gray-400 font-medium mt-0.5 md:mt-0 md:ml-0">
{playlists.length} Playlists
{t('server.playlists', { count: playlists.length })}
</p>
);
} else {
// Cloud Logic
if (serverInfo) {
if (serverInfo.isConnected) {
displayTitle = serverInfo.name || 'Cloud Server';
displayTitle = serverInfo.name || t('server.cloud');
displaySubtitle = (
<div className="flex items-center text-xs text-gray-300 font-medium space-x-1.5 truncate mt-0.5 md:mt-0">
<span className="text-plex-orange truncate font-semibold">{serverInfo.libraryName}</span>
@@ -47,20 +49,20 @@ const ServerPanel: React.FC<ServerPanelProps> = ({ type, playlists, isLoading, o
</div>
);
} else {
displayTitle = 'Not Connected';
displayTitle = t('server.notConnected');
Icon = WifiOff;
headerColor = 'text-red-400';
displaySubtitle = (
<p className="text-xs text-gray-500 font-medium mt-0.5">
Connection failed
{t('server.connectionFailed')}
</p>
);
}
} else {
displayTitle = 'Cloud Server';
displayTitle = t('server.cloud');
displaySubtitle = (
<p className="text-xs text-gray-500 font-medium mt-0.5">
{isLoading ? 'Connecting...' : 'Waiting...'}
{isLoading ? t('server.connecting') : t('server.waiting')}
</p>
);
}
@@ -121,7 +123,7 @@ const ServerPanel: React.FC<ServerPanelProps> = ({ type, playlists, isLoading, o
: 'text-gray-400 hover:text-white hover:bg-white/10'
}
`}
title={isLoading ? "Cancel Refresh" : "Refresh Playlists"}
title={isLoading ? t('server.cancelRefresh') : t('server.refreshPlaylists')}
>
{isLoading ? (
<div className="relative flex items-center justify-center">
@@ -141,11 +143,11 @@ const ServerPanel: React.FC<ServerPanelProps> = ({ type, playlists, isLoading, o
{isLoading && playlists.length === 0 ? (
<div className="flex flex-col items-center justify-center h-full text-gray-500 space-y-3">
<RefreshCw size={24} className="animate-spin text-plex-orange/50" />
<p className="text-xs font-medium tracking-wide uppercase">Syncing...</p>
<p className="text-xs font-medium tracking-wide uppercase">{t('server.syncing')}</p>
</div>
) : playlists.length === 0 ? (
<div className="flex flex-col items-center justify-center h-full text-gray-500">
<p className="text-sm">No playlists found.</p>
<p className="text-sm">{t('server.noPlaylists')}</p>
</div>
) : (
<div className="space-y-2.5 md:space-y-3">