コンポーネントの完全なソースコードは以下のリンクから確認できます:
google-translate-component.jsclass GoogleTranslate extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
}
connectedCallback() {
this.render();
this.initializeTranslation();
}
}
initializeTranslation() {
const userLang = navigator.language || navigator.userLanguage;
if (!userLang.startsWith('ja')) {
const script = document.createElement('script');
script.src = '//translate.google.com/translate_a/element.js?cb=googleTranslateElementInit';
script.async = true;
document.head.appendChild(script);
}
}
class GoogleTranslate extends HTMLElement {
handleTranslationError(error) {
console.error('Translation error:', error);
this.showErrorMessage();
document.body.style.visibility = 'visible';
}
showErrorMessage() {
const errorDiv = document.createElement('div');
errorDiv.className = 'translation-error';
errorDiv.textContent = '翻訳サービスが利用できません';
this.shadowRoot.appendChild(errorDiv);
setTimeout(() => errorDiv.remove(), 5000);
}
tryAutoTranslate() {
const maxAttempts = 5;
let attempts = 0;
const tryTranslate = setInterval(() => {
try {
const selectElement = document.querySelector('.goog-te-combo');
if (selectElement) {
const userLang = navigator.language.split('-')[0];
selectElement.value = userLang;
selectElement.dispatchEvent(new Event('change'));
clearInterval(tryTranslate);
this.onTranslationSuccess();
}
attempts++;
if (attempts >= maxAttempts) {
clearInterval(tryTranslate);
this.handleTranslationError(new Error('Max attempts reached'));
}
} catch (error) {
clearInterval(tryTranslate);
this.handleTranslationError(error);
}
}, 200);
}
}
:host {
display: block;
}
#google_translate_element {
position: fixed;
top: 20px;
right: 20px;
z-index: 1000;
background: rgba(255, 255, 255, 0.9);
padding: 10px;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
backdrop-filter: blur(10px);
}
/* タブレット向け */
@media (max-width: 1024px) {
#google_translate_element {
padding: 8px;
}
::slotted(.goog-te-combo) {
font-size: 14px;
padding: 6px 10px;
}
}
/* モバイル向け */
@media (max-width: 600px) {
#google_translate_element {
top: 10px;
right: 10px;
padding: 6px;
}
::slotted(.goog-te-combo) {
font-size: 12px;
padding: 4px 8px;
}
}
.translation-widget {
animation: slideIn 0.3s ease-out;
}
@keyframes slideIn {
from {
transform: translateY(-20px);
opacity: 0;
}
to {
transform: translateY(0);
opacity: 1;
}
}
.translation-error {
animation: fadeIn 0.3s ease-out;
}
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
// スクリプトの遅延読み込み
const script = document.createElement('script');
script.src = '//translate.google.com/translate_a/element.js?cb=googleTranslateElementInit';
script.async = true;
document.head.appendChild(script);
disconnectedCallback() {
// クリーンアップ処理
if (this.translationInterval) {
clearInterval(this.translationInterval);
}
// イベントリスナーの削除
this.removeEventListeners();
}
render() {
// パフォーマンス最適化のためのバッチ更新
requestAnimationFrame(() => {
this.shadowRoot.innerHTML = this.getTemplate();
this.setupEventListeners();
});
}
<!-- コンポーネントの読み込み -->
<script src="google-translate-component.js"></script>
<google-translate
languages="en,ja,zh,ko"
position="top-right"
theme="light"></google-translate>
属性名 | 説明 | デフォルト値 | 例 |
---|---|---|---|
languages | サポートする言語コード(カンマ区切り) | en,zh-CN,zh-TW,ko,fr,de,es | en,fr,de |
position | 表示位置 | top-right | bottom-right |
auto-translate | 自動翻訳の有効/無効 | true | false |