add translate

This commit is contained in:
2026-01-16 12:40:01 +09:00
parent 7d7130b23c
commit e2fdf135ea
17 changed files with 947 additions and 11 deletions

View File

@@ -114,6 +114,7 @@ async function listRecordsFromApi(did: string, collection: string, pdsUrl: strin
title: r.value.title as string || 'Untitled',
content: r.value.content as string || '',
createdAt: r.value.createdAt as string || new Date().toISOString(),
translations: r.value.translations as BlogPost['translations'] || undefined,
})).sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime())
}
@@ -394,6 +395,31 @@ function generateTabsHtml(activeTab: 'blog' | 'browser', handle: string): string
`
}
function generateLangSelectorHtml(): string {
const langIcon = `<svg viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" stroke-width="2">
<circle cx="12" cy="12" r="10"/>
<path d="M2 12h20M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/>
</svg>`
return `
<div class="lang-selector" id="lang-selector">
<button type="button" class="lang-btn" id="lang-btn" title="Language">
${langIcon}
</button>
<div class="lang-dropdown" id="lang-dropdown">
<div class="lang-option" data-lang="ja">
<span class="lang-name">日本語</span>
<span class="lang-check">✓</span>
</div>
<div class="lang-option selected" data-lang="en">
<span class="lang-name">English</span>
<span class="lang-check">✓</span>
</div>
</div>
</div>
`
}
function generatePostListHtml(posts: BlogPost[]): string {
if (posts.length === 0) {
return '<p class="no-posts">No posts yet</p>'
@@ -409,7 +435,10 @@ function generatePostListHtml(posts: BlogPost[]): string {
</li>
`
}).join('')
return `<ul class="post-list">${items}</ul>`
return `
<div class="content-header">${generateLangSelectorHtml()}</div>
<ul class="post-list">${items}</ul>
`
}
// Map network to app URL for discussion links
@@ -423,7 +452,15 @@ function getAppUrl(network: string): string {
function generatePostDetailHtml(post: BlogPost, handle: string, collection: string, network: string, siteUrl?: string): string {
const rkey = post.uri.split('/').pop() || ''
const jsonUrl = `/at/${handle}/${collection}/${rkey}/`
const content = marked.parse(post.content) as string
const originalContent = marked.parse(post.content) as string
// Check for English translation
const hasTranslation = post.translations?.en?.content
const translatedContent = hasTranslation ? marked.parse(post.translations!.en.content) as string : ''
// Default to English if translation exists
const displayContent = hasTranslation ? translatedContent : originalContent
// Use siteUrl from config, or construct from handle
const baseSiteUrl = siteUrl || `https://${handle}`
const postUrl = `${baseSiteUrl}/post/${rkey}/`
@@ -439,8 +476,14 @@ function generatePostDetailHtml(post: BlogPost, handle: string, collection: stri
const searchQuery = basePath + rkeyPrefix
const searchUrl = `${appUrl}/search?q=${encodeURIComponent(searchQuery)}`
// Store original and translated content as data attributes for JS switching
const dataAttrs = hasTranslation
? ` data-original-content="${escapeHtml(originalContent)}" data-translated-content="${escapeHtml(translatedContent)}"`
: ''
return `
<article class="post-detail">
<div class="content-header">${generateLangSelectorHtml()}</div>
<article class="post-detail"${dataAttrs}>
<header class="post-header">
<h1 class="post-title">${escapeHtml(post.title)}</h1>
<div class="post-meta">
@@ -448,7 +491,7 @@ function generatePostDetailHtml(post: BlogPost, handle: string, collection: stri
<a href="${jsonUrl}" class="json-btn">json</a>
</div>
</header>
<div class="post-content">${content}</div>
<div class="post-content">${displayContent}</div>
</article>
<div class="discussion-section">
<a href="${searchUrl}" target="_blank" rel="noopener" class="discuss-link">