Skip to content

Commit

Permalink
feat: make santa multilingual
Browse files Browse the repository at this point in the history
  • Loading branch information
louisjoecodes committed Dec 7, 2024
1 parent 41763d3 commit f9e2d7c
Show file tree
Hide file tree
Showing 6 changed files with 622 additions and 0 deletions.
222 changes: 222 additions & 0 deletions examples/conversational-ai/talk-to-santa/app/(main)/(santa)/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,188 @@ import { useEffect, useRef, useState } from "react";
import { toast } from "sonner";
import Image from "next/image";

export const LANGUAGES = [
{
code: "en",
name: "English",
firstSentence:
"Ho, ho, ho! Merry Christmas, my friend. Tell me, what is your name?",
},
{
code: "ar",
name: "Arabic",
firstSentence: "هو، هو، هو! عيد ميلاد مجيد يا صديقي. قل لي، ما اسمك؟",
},
{
code: "bg",
name: "Bulgarian",
firstSentence:
"Хо, хо, хо! Весела Коледа, приятелю. Кажи ми, как се казваш?",
},
{
code: "zh",
name: "Chinese",
firstSentence: "呵呵呵!圣诞快乐,我的朋友。告诉我,你叫什么名字?",
},
{
code: "hr",
name: "Croatian",
firstSentence:
"Ho, ho, ho! Sretan Božić, prijatelju. Reci mi, kako se zoveš?",
},
{
code: "cs",
name: "Czech",
firstSentence:
"Ho, ho, ho! Veselé Vánoce, příteli. Řekni mi, jak se jmenuješ?",
},
{
code: "da",
name: "Danish",
firstSentence:
"Ho, ho, ho! Glædelig jul, min ven. Fortæl mig, hvad er dit navn?",
},
{
code: "nl",
name: "Dutch",
firstSentence:
"Ho, ho, ho! Vrolijk kerstfeest, mijn vriend. Vertel me, wat is je naam?",
},
{
code: "fi",
name: "Finnish",
firstSentence:
"Ho, ho, ho! Hyvää joulua, ystäväni. Kerro minulle, mikä sinun nimesi on?",
},
{
code: "fr",
name: "French",
firstSentence:
"Ho, ho, ho ! Joyeux Noël, mon ami. Dis-moi, quel est ton nom ?",
},
{
code: "de",
name: "German",
firstSentence:
"Ho, ho, ho! Frohe Weihnachten, mein Freund. Sag mir, wie heißt du?",
},
{
code: "el",
name: "Greek",
firstSentence:
"Χο, χο, χο! Καλά Χριστούγεννα, φίλε μου. Πες μου, πώς σε λένε;",
},
{
code: "hi",
name: "Hindi",
firstSentence:
"हो, हो, हो! मेरी क्रिसमस, मेरे दोस्त। मुझे बताओ, तुम्हारा नाम क्या है?",
},
{
code: "hu",
name: "Hungarian",
firstSentence: "Ho, ho, ho! Boldog karácsonyt, barátom. Mondd, mi a neved?",
},
{
code: "id",
name: "Indonesian",
firstSentence:
"Ho, ho, ho! Selamat Natal, temanku. Katakan padaku, siapa namamu?",
},
{
code: "it",
name: "Italian",
firstSentence: "Ho, ho, ho! Buon Natale, amico mio. Dimmi, come ti chiami?",
},
{
code: "ja",
name: "Japanese",
firstSentence:
"ホーホーホー!メリークリスマス、私の友よ。教えて、お名前は何ですか?",
},
{
code: "ko",
name: "Korean",
firstSentence:
"호, 호, 호! 메리 크리스마스, 내 친구야. 말해줘, 네 이름이 뭐니?",
},
{
code: "ms",
name: "Malay",
firstSentence:
"Ho, ho, ho! Selamat Hari Natal, kawan. Beritahu saya, siapa nama awak?",
},
{
code: "no",
name: "Norwegian",
firstSentence: "Ho, ho, ho! God jul, min venn. Fortell meg, hva heter du?",
},
{
code: "pl",
name: "Polish",
firstSentence:
"Ho, ho, ho! Wesołych Świąt, mój przyjacielu. Powiedz mi, jak masz na imię?",
},
{
code: "pt",
name: "Portuguese",
firstSentence:
"Ho, ho, ho! Feliz Natal, meu amigo. Diga-me, qual é o seu nome?",
},
{
code: "ro",
name: "Romanian",
firstSentence:
"Ho, ho, ho! Crăciun fericit, prietenul meu. Spune-mi, cum te cheamă?",
},
{
code: "ru",
name: "Russian",
firstSentence:
"Хо, хо, хо! С Рождеством, мой друг. Скажи мне, как тебя зовут?",
},
{
code: "sk",
name: "Slovak",
firstSentence:
"Ho, ho, ho! Veselé Vianoce, priateľ môj. Povedz mi, ako sa voláš?",
},
{
code: "es",
name: "Spanish",
firstSentence:
"¡Jo, jo, jo! Feliz Navidad, mi amigo. Dime, ¿cómo te llamas?",
},
{
code: "sv",
name: "Swedish",
firstSentence: "Ho, ho, ho! God jul, min vän. Säg mig, vad heter du?",
},
{
code: "ta",
name: "Tamil",
firstSentence:
"ஹோ, ஹோ, ஹோ! கிறிஸ்துமஸ் வாழ்த்துக்கள், என் நண்பரே. சொல்லுங்கள், உங்கள் பெயர் என்ன?",
},
{
code: "tr",
name: "Turkish",
firstSentence: "Ho, ho, ho! Mutlu Noeller, dostum. Söyle bakalım, adın ne?",
},
{
code: "uk",
name: "Ukrainian",
firstSentence:
"Хо, хо, хо! З Різдвом, мій друже. Скажи мені, як тебе звати?",
},
{
code: "vi",
name: "Vietnamese",
firstSentence:
"Ho, ho, ho! Giáng sinh vui vẻ, bạn của tôi. Hãy cho tôi biết, tên bạn là gì?",
},
];

export default function Page() {
const conversation = useConversation();
const router = useRouter();
Expand All @@ -26,6 +208,35 @@ export default function Page() {
const [hasAudioAccess, setHasAudioAccess] = useState(false);
const [hasVideoAccess, setHasVideoAccess] = useState(false);
const [isVideoEnabled, setIsVideoEnabled] = useState(false);
const [language, setLanguage] = useState<string | null>(null);

useEffect(() => {
try {
const stored = localStorage.getItem("preferredLanguage");
if (stored && LANGUAGES.find(l => l.code === stored)) {
setLanguage(stored);
return;
}

console.log("navigator.language", navigator.language);
if (navigator.language) {
const browserLang = navigator.language.split("-")[0];
const matchingLang = LANGUAGES.find(l => l.code === browserLang);
if (matchingLang) {
setLanguage(matchingLang.code);
return;
}
}
} catch (error) {
console.warn("Language detection failed:", error);
}
}, []);

useEffect(() => {
if (language) {
localStorage.setItem("preferredLanguage", language);
}
}, [language]);

// session state
const [conversationId, setConversationId] = useState<string | null>(null);
Expand Down Expand Up @@ -181,6 +392,14 @@ export default function Page() {
}
conversation.startSession({
signedUrl,
overrides: {
agent: {
language: language ?? ("en" as any),
firstMessage:
LANGUAGES.find(l => l.code === language)?.firstSentence ??
LANGUAGES[0].firstSentence,
},
},
onConnect: ({ conversationId }) => {
setConversationId(conversationId);
startRecordingVideo();
Expand Down Expand Up @@ -306,6 +525,9 @@ export default function Page() {
requestMediaPermissions={requestAudioPermissions}
isVideoEnabled={isVideoEnabled}
toggleVideoEnabled={toggleVideoEnabled}
language={language}
setLanguage={setLanguage}
languages={LANGUAGES}
/>
)}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import { Switch } from "@/components/ui/switch";
import { Loader2 } from "lucide-react";
import Image from "next/image";
import { useState } from "react";
import { LanguageDropdown } from "./language-dropdown";
import { LANGUAGES } from "@/app/(main)/(santa)/page";

interface CallButtonProps {
status: "disconnected" | "connecting" | "connected" | "disconnecting";
Expand All @@ -15,6 +17,9 @@ interface CallButtonProps {
requestMediaPermissions: () => void;
isVideoEnabled: boolean;
toggleVideoEnabled: (value: boolean) => void;
language: string | null;
setLanguage: (value: string) => void;
languages: typeof LANGUAGES;
}

const RINGING_PHONE_AUDIO_DURATION = 6000;
Expand All @@ -26,6 +31,9 @@ export function CallButton({
requestMediaPermissions,
isVideoEnabled,
toggleVideoEnabled,
language,
setLanguage,
languages,
}: CallButtonProps) {
const [isCalling, setIsCalling] = useState(false);
const [ringingPhoneAudio] = useState(() => {
Expand Down Expand Up @@ -90,6 +98,15 @@ export function CallButton({
</>
)}
</Button>
{!isCalling && (
<div className={"flex items-center gap-2 text-sm mt-2"}>
<LanguageDropdown
language={language}
setLanguage={setLanguage}
languages={languages}
/>
</div>
)}
<div className="flex items-center space-x-2 pt-3">
<Switch
id="airplane-mode"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
"use client";

import { LANGUAGES } from "@/app/(main)/(santa)/page";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select";

interface LanguageDropdownProps {
setLanguage: (language: string) => void;
language: string | null;
languages: typeof LANGUAGES;
}

export function LanguageDropdown({
setLanguage,
language,
languages,
}: LanguageDropdownProps) {
const currentLanguage = languages.find(lang => lang.code === language)?.name;

return (
<div className="h-10 opacity-0 transition-opacity duration-300 ease-in-out"
style={{ opacity: language ? 1 : 0 }}>
{language && (
<Select value={language} onValueChange={setLanguage}>
<SelectTrigger className="w-[180px] transition-colors">
<SelectValue placeholder="Select Language">
{currentLanguage}
</SelectValue>
</SelectTrigger>
<SelectContent>
{languages.map(lang => (
<SelectItem
key={lang.code}
value={lang.code}
className="hover:bg-red-100 focus:bg-red-100 cursor-pointer"
>
{lang.name}
</SelectItem>
))}
</SelectContent>
</Select>
)}
</div>
);
}
Loading

0 comments on commit f9e2d7c

Please sign in to comment.