Skip to content

Commit

Permalink
add language drop down menu, fix text errors (#139)
Browse files Browse the repository at this point in the history
* feat: add language support
current support web
Chatroom
Navbar
dashboard
login
template

* feat: add language support
view template

* feat: complete language support
now support English and Chinese

* fix: fix my git,Idk what's going on

* deleted:    ParticipantView.svelte

* fix: add ParticipantView component back

* feat: add language drop-down menu to navbar
fix: fix parts of the translation texts
  • Loading branch information
Buffett111 authored Feb 14, 2025
1 parent 6498935 commit 8184c49
Show file tree
Hide file tree
Showing 21 changed files with 893 additions and 227 deletions.
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
64 changes: 52 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: '個人資料',
dashboard: '儀表板',
signOut: '登出',
login: '登入'
}
};
onMount(() => {
const interval = setInterval(() => {
let newHighlight;
Expand All @@ -20,11 +38,15 @@
return () => clearInterval(interval);
});
function setLanguage(lang: 'en' | 'zh') {
language.set(lang);
}
</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 @@ -40,18 +62,36 @@
<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}

<!-- Remove the old toggle button and add a dropdown for language selection(PM requested) -->
<Avatar
id="language-menu"
src={$language === 'en' ? '/icons/flag-us.png' : '/icons/flag-zh.jpg'}
alt="Lang"
class="ml-2 cursor-pointer"
/>
<Dropdown triggeredBy="#language-menu" class="w-36">
<DropdownItem class="flex items-center" on:click={() => setLanguage('en')}>
<img src="/icons/flag-us.png" alt="English" class="mr-2 h-4 w-4" />
English
</DropdownItem>
<DropdownItem class="flex items-center" on:click={() => setLanguage('zh')}>
<img src="/icons/flag-zh.jpg" alt="中文" class="mr-2 h-4 w-4" />
繁體中文
</DropdownItem>
</Dropdown>
</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

0 comments on commit 8184c49

Please sign in to comment.