Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Language(Chinese) #137

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 28 additions & 4 deletions src/lib/components/Chatroom.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import { Mic, Send, Square } from 'lucide-svelte'; // Added Square icon import
import AudioPlayer from './AudioPlayer.svelte';
import { renderMarkdown } from '$lib/utils/renderMarkdown';
import { language } from '$lib/stores/language'; // Import the global language store

interface Conversation {
name: string;
Expand Down Expand Up @@ -35,6 +36,25 @@
let messagesContainer: HTMLDivElement;
let dots = $state('...');

const translations = {
en: {
placeholder: 'Type your message...(max 500 characters)',
send: 'Send',
record: 'Record',
waiting: 'Waiting',
stop: 'Stop',
thinking: 'Thinking'
},
zh: {
placeholder: '手動輸入文字...(最多500個字元)',
send: '送出',
record: '錄音',
waiting: '等待',
stop: '停止',
thinking: '正在思考'
}
};

function scrollToBottom() {
if (!messagesContainer || !autoscroll) return;

Expand Down Expand Up @@ -147,7 +167,7 @@
<Card class="w-fit max-w-[80%]">
<div class="-my-2">
<p class="prose prose-hina text-gray-600">
{#await renderMarkdown(`正在思考${dots}`)}
{#await renderMarkdown(`${translations[$language].thinking}${dots}`)}
Loading ...
{:then content}
<!-- eslint-disable-next-line svelte/no-at-html-tags -->
Expand All @@ -167,7 +187,7 @@
<div class="flex min-w-[200px] flex-1 flex-col">
<Textarea
class="max-h-32 min-h-14 flex-1"
placeholder="Type your message...(max 500 characters)"
placeholder={translations[$language].placeholder}
rows={1}
bind:value={text}
disabled={operating}
Expand All @@ -190,7 +210,11 @@
{:else}
<Mic />
{/if}
{recording ? (operating ? 'Waiting' : 'Stop') : 'Record'}
{recording
? operating
? translations[$language].waiting
: translations[$language].stop
: translations[$language].record}
</Button>
<Button
color="primary"
Expand All @@ -199,7 +223,7 @@
on:click={handleSend}
>
<Send class={operating ? 'animate-pulse' : ''} />
Send
{translations[$language].send}
</Button>
</div>
</div>
Expand Down
50 changes: 38 additions & 12 deletions src/lib/components/Navbar.svelte
Original file line number Diff line number Diff line change
@@ -1,14 +1,32 @@
<script>
<script lang="ts">
import { Navbar, NavBrand, Avatar, Dropdown, DropdownItem, Button } from 'flowbite-svelte';
import { LogOut, User, LayoutDashboard } from 'lucide-svelte';
import { signOut, user } from '$lib/stores/auth';
import { profile } from '$lib/stores/profile';
import { onMount } from 'svelte';
import { page } from '$app/state';
import { language } from '$lib/stores/language'; // Import the global language store

let hinagiku = $state('Hinagiku');
let highlight = $state(0);

const translations = {
en: {
welcome: 'Welcome to Hinagiku!',
profile: 'Profile',
dashboard: 'Dashboard',
signOut: 'Sign out',
login: 'Login'
},
zh: {
welcome: '歡迎來到Hinagiku!',
profile: '個人资料',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

歡迎來到 Hinagiku!

dashboard: '儀表板',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

個人資料

signOut: '登出',
login: '登入'
}
};

onMount(() => {
const interval = setInterval(() => {
let newHighlight;
Expand All @@ -20,11 +38,16 @@

return () => clearInterval(interval);
});

function toggleLanguage() {
language.update((value) => (value === 'en' ? 'zh' : 'en'));
console.log('Language:', $language);
}
</script>

<Navbar class="fixed left-0 top-0 z-50 w-full shadow-sm">
<NavBrand href="/">
<img src="/Icon.png" class="mr-3 h-8" alt="Welcome to Hinagiku!" />
<img src="/Icon.png" class="mr-3 h-8" alt={translations[$language].welcome} />
<span class="self-center whitespace-nowrap text-2xl font-bold">
{#each hinagiku as c, i}<span
class="transition-colors duration-500"
Expand All @@ -33,25 +56,28 @@
</span>
</NavBrand>
<div class="ml-auto flex items-center">
<Button on:click={toggleLanguage} class="mr-2">
{$language === 'en' ? 'English' : '中文'}
</Button>
{#if $user}
<Avatar id="user-menu" src={$user.photoURL || ''} alt="User" class="cursor-pointer" />
<Dropdown triggeredBy="#user-menu" class="w-48">
<div class="px-4 py-3">
<p class="text-sm text-gray-900">{$profile?.displayName}</p>
<p class="truncate text-sm font-medium text-gray-500">{$user.email}</p>
</div>
<DropdownItem href="/profile" class="flex items-center"
><User class="mr-2 h-4 w-4" />Profile</DropdownItem
>
<DropdownItem href="/dashboard" class="flex items-center"
><LayoutDashboard class="mr-2 h-4 w-4" />Dashbaord</DropdownItem
>
<DropdownItem on:click={() => signOut()} class="flex items-center"
><LogOut class="mr-2 h-4 w-4" />Sign out</DropdownItem
>
<DropdownItem href="/profile" class="flex items-center">
<User class="mr-2 h-4 w-4" />{translations[$language].profile}
</DropdownItem>
<DropdownItem href="/dashboard" class="flex items-center">
<LayoutDashboard class="mr-2 h-4 w-4" />{translations[$language].dashboard}
</DropdownItem>
<DropdownItem on:click={() => signOut()} class="flex items-center">
<LogOut class="mr-2 h-4 w-4" />{translations[$language].signOut}
</DropdownItem>
</Dropdown>
{:else if !page.url.pathname.startsWith('/login')}
<Button href="/login" class="">Login</Button>
<Button href="/login" class="">{translations[$language].login}</Button>
{/if}
</div>
</Navbar>
37 changes: 29 additions & 8 deletions src/lib/components/QrScanner.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import { notifications } from '$lib/stores/notifications';
import { Html5Qrcode } from 'html5-qrcode';
import { onMount, onDestroy } from 'svelte';
import { language } from '$lib/stores/language'; // Import the global language store

let { onScan } = $props<{
onScan: (code: string) => void;
Expand All @@ -11,6 +12,28 @@
let scanning = $state(false);
let fileInput: HTMLInputElement;

const translations = {
en: {
stopCamera: 'Stop Camera',
startCamera: 'Start Camera',
uploadQrImage: 'Upload QR Code Image',
errorScanning: 'error during scanning: ',
errorStartingCamera: 'error during starting camera: ',
errorScanningFile: 'error during scanning file: ',
unableToFindQr:
'Unable to find QR code in the image. Please ensure the image is clear and contains a valid QR code.'
},
zh: {
stopCamera: '停止相機',
startCamera: '啟動相機',
uploadQrImage: '上傳二維碼圖片',
errorScanning: '掃描過程中出錯:',
errorStartingCamera: '啟動相機過程中出錯:',
errorScanningFile: '掃描文件過程中出錯:',
unableToFindQr: '無法在圖像中找到二維碼。請確保圖像清晰並包含有效的二維碼。'
}
};

onMount(() => {
scanner = new Html5Qrcode('qr-reader');
});
Expand Down Expand Up @@ -39,11 +62,11 @@
if ((err as unknown as Error).toString().includes('NotFoundException')) {
return;
}
// notifications.error(`error during scanning: ${err}`);
// notifications.error(`${translations[$language].errorScanning} ${err}`);
}
);
} catch (err) {
notifications.error(`error during starting camera: ${err}`);
notifications.error(`${translations[$language].errorStartingCamera} ${err}`);
scanning = false;
}
}
Expand All @@ -57,11 +80,9 @@
onScan(result);
} catch (err) {
if ((err as unknown as Error).toString().includes('NotFoundException')) {
notifications.error(
'Unable to find QR code in the image. Please ensure the image is clear and contains a valid QR code.'
);
notifications.error(translations[$language].unableToFindQr);
} else {
notifications.error(`error during scanning file: ${err}`);
notifications.error(`${translations[$language].errorScanningFile} ${err}`);
}
} finally {
fileInput.value = '';
Expand All @@ -78,7 +99,7 @@
onclick={scanning ? () => scanner.stop() : startCamera}
class="w-full rounded-lg border px-6 py-2 hover:bg-gray-50"
>
{scanning ? 'Stop Camera' : 'Start Camera'}
{scanning ? translations[$language].stopCamera : translations[$language].startCamera}
</button>

<div class="relative">
Expand All @@ -94,7 +115,7 @@
for="qr-image-input"
class="block w-full cursor-pointer rounded-lg border px-6 py-2 text-center hover:bg-gray-50"
>
Upload QR Code Image
{translations[$language].uploadQrImage}
</label>
</div>
</div>
Expand Down
18 changes: 16 additions & 2 deletions src/lib/components/SessionCard.svelte
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<script lang="ts">
import { Button, Card } from 'flowbite-svelte';
import ResolveUsername from './ResolveUsername.svelte';
import { language } from '$lib/stores/language'; // Import the global language store

let {
id,
Expand All @@ -19,6 +20,17 @@
host?: string;
createdAt: Date;
} = $props();

const translations = {
en: {
hostedBy: 'Hosted by',
viewSession: 'View Session'
},
zh: {
hostedBy: '主持人',
viewSession: '查看會話'
}
};
</script>

<Card padding="lg" class="transition-all hover:border-primary-500">
Expand Down Expand Up @@ -52,15 +64,17 @@
<div class="mt-auto w-full">
{#if host}
<div class="flex items-center gap-4">
<span class="text-sm text-gray-500">Hosted by <ResolveUsername id={host} /></span>
<span class="text-sm text-gray-500"
>{translations[$language].hostedBy} <ResolveUsername id={host} /></span
>
</div>
{/if}
<div class="mb-4 flex items-center gap-4">
<span class="text-sm text-gray-500">
{createdAt.toLocaleString()}
</span>
</div>
<Button href="/session/{id}" class="w-full">View Session</Button>
<Button href="/session/{id}" class="w-full">{translations[$language].viewSession}</Button>
</div>
</div>
</Card>
Loading
Loading