친한 사람의 부탁을 받아 개인적인 웹사이트를 하나 만들고 있는게 있다.(리액트 js vite 환경에서!)
이 웹사이트는 영어 소통이 잘 되지 않는 외국인에게 안내를 해주는 목적을 가지고 있기에
자동 번역 이 필수적이었다.
이에 번역 api를 여러개 찾아보게 되었고, 구글 번역 api가 적합하다고 판단해 이를 사용하게 되었다.
페이지 자체를 번역해주는 것이다! 이런 버튼을 눌러서 언어를 선택하고 페이지를 번역할 수 있다. 물론... 여기서 제공해주는 ui가 너무 구려서 ..... 따로 디자인이 필요했다. 그래서 여러 벨로그를 참고해 수정하게 되었다.

상태 관리
const [chooseCountry, setChooseCountry] = useState({
code: "ko",
name: "한국어",
flag: "kr",
});
const [isHovered, setIsHovered] = useState(false);
언어 선택 버튼에 마우스가 올라갔는지 여부와 현재 선택된 언어 정보의 상태를 관리한다.
Google 번역 스크립트 추가 (useEffect)
useEffect(() => {
const savedLanguage = localStorage.getItem("selectedLanguage");
if (!document.querySelector('script[src*="translate_a"]')) {
const addGoogleTranslateScript = document.createElement("script");
addGoogleTranslateScript.src =
"https://translate.google.com/translate_a/element.js?cb=googleTranslateElementInit";
addGoogleTranslateScript.async = true;
addGoogleTranslateScript.onload = () => {
window.googleTranslateElementInit = () => {
new window.google.translate.TranslateElement(
{ pageLanguage: "ko", autoDisplay: true },
"google_translate_element"
);
setTimeout(() => {
if (savedLanguage) {
const lang = languages.find((l) => l.code === savedLanguage);
if (lang) {
const gtCombo = document.querySelector(".goog-te-combo");
if (gtCombo) {
gtCombo.value = lang.code;
gtCombo.dispatchEvent(new Event("change"));
setChooseCountry(lang);
}
}
}
}, 1000); // 1초 후 실행 (API 로드 대기)
};
window.googleTranslateElementInit();
};
document.body.appendChild(addGoogleTranslateScript);
}
}, []);
언어 변경 함수
const handleLanguageChange = (lang) => {
const value = lang.code;
const gtCombo = document.querySelector(".goog-te-combo");
if (gtCombo) {
gtCombo.value = value;
gtCombo.dispatchEvent(new Event("change"));
}
setChooseCountry(lang);
localStorage.setItem("selectedLanguage", lang.code);
};
이벤트 전파를 차단
const handleWheel = (e) => {
e.stopPropagation();
};
마우스 휠 이벤트가 부모 요소로 전파되지 않도록 막는 역할을 한다. 즉, 언어 목록 내부에서만 스크롤 가능하게 제한한다.
ui
<>
<div id="google_translate_element" style={{ display: "none" }}></div>
<ButtonContainer
onMouseEnter={() => setIsHovered(true)}
onMouseLeave={() => setIsHovered(false)}
$isMobile={isMobile}
>
<Flag code={chooseCountry.flag} />
{chooseCountry.name}
{isHovered && (
<LanguageList onWheel={handleWheel}>
{languages.map((lang) => (
<LanguageItem
key={lang.code}
onClick={() => handleLanguageChange(lang)}
>
<Flag code={lang.flag} />
{lang.name}
</LanguageItem>
))}
</LanguageList>
)}
</ButtonContainer>
</>
이때 깃발의 사진은 하나하나 찾으면 당연히 어렵고 귀찮기에 웹사이트를 이용한다.
background-image: ${(props) =>
`url(https://cdn.weglot.com/flags/square/${props.code}.svg)`};
이런식으로! 전체 스타일 코드는 다음과 같다.
const ButtonContainer = styled.li`
display: flex;
align-items: center;
gap: 5px;
padding: 5px 5px;
width: 95px;
height: 45px;
cursor: pointer;
background-color: #ffffff;
outline: none;
border: none;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.4);
border-radius: 5px;
font-size: 14px;
position: fixed;
z-index: 999;
right: ${(props) => (props.$isMobile ? "1rem" : "3rem")};
bottom: 2rem;
`;
const LanguageList = styled.ul`
position: absolute;
top: -80vh;
left: 0;
background-color: white;
border: 1px solid #ccc;
list-style: none;
padding: 10px;
margin: 0;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
width: 100px;
height: 80vh;
overflow-y: auto;
overflow-x: hidden;
border-radius: 8px;
z-index: 1000;
`;
const LanguageItem = styled.li`
cursor: pointer;
padding: 10px 0px;
&:hover {
background-color: #f0f0f0;
}
font-size: 14px;
border-bottom: 1px solid #b7b7b7;
`;
const Flag = styled.div`
width: 30px;
height: 25px;
background-image: ${(props) =>
`url(https://cdn.weglot.com/flags/square/${props.code}.svg)`};
background-repeat: no-repeat;
background-position: center;
background-size: cover;
`;
export const languages = [
{ code: "ko", name: "한국어", flag: "kr" }, // 한국어
{ code: "en", name: "English", flag: "us" }, // 영어
{ code: "my", name: "မြန်မာ", flag: "mm" }, // 미얀마어
{ code: "km", name: "ភាសាខ្មែរ", flag: "kh" }, // 크메르어 (캄보디아)
{ code: "uz", name: "Oʻzbekcha", flag: "uz" }, // 우즈베크어
{ code: "id", name: "Bahasa Indonesia", flag: "id" }, // 인도네시아어
{ code: "ne", name: "नेपाली", flag: "np" }, // 네팔어
{ code: "th", name: "ไทย", flag: "th" }, // 태국어
{ code: "si", name: "සිංහල", flag: "lk" }, // 싱할라어 (스리랑카)
{ code: "vi", name: "Tiếng Việt", flag: "vn" }, // 베트남어
{ code: "lo", name: "ລາວ", flag: "la" }, // 라오스어
{ code: "tl", name: "Tagalog", flag: "ph" }, // 타갈로그어 (필리핀)
];