type MessageKey = | "colIndex" | "colTitle" | "colChannel" | "colDuration" | "colViews" | "colPublished" | "colCategory" | "colAddedBy" | "colVotes" | "filterTitle" | "filterChannel" | "filterAddedBy" | "filterCategory" | "badgeLive" | "headerVideos" | "headerLoading" | "fetchViews" | "fetchViewsProgress" | "fetchViewsDone" | "colSettings" | "colSettingsReset" | "statsDuration" | "statsChannels" | "statsPlayable" | "statsTotalViews" | "statsDetail" | "statsDetailChannelRank" | "statsDetailAddedByRank" | "statsDetailCategoryBreak" | "statsDetailDurationAvg" | "statsDetailDurationMedian" | "statsDetailVideos"; const messages: Record> = { ja: { colIndex: "#", colTitle: "タイトル", colChannel: "チャンネル", colDuration: "長さ", colViews: "再生数", colPublished: "公開日", colCategory: "カテゴリ", colAddedBy: "追加者", colVotes: "投票", filterTitle: "タイトル検索...", filterChannel: "チャンネル...", filterAddedBy: "追加者...", filterCategory: "カテゴリ...", badgeLive: "ライブ", headerVideos: "本の動画", headerLoading: "読み込み中…", fetchViews: "全件詳細を取得", fetchViewsProgress: "取得中…", fetchViewsDone: "取得完了", colSettings: "表示", colSettingsReset: "リセット", statsDuration: "合計時間", statsChannels: "チャンネル", statsPlayable: "再生可能", statsTotalViews: "総再生数", statsDetail: "詳細", statsDetailChannelRank: "チャンネル別", statsDetailAddedByRank: "追加者別", statsDetailCategoryBreak: "カテゴリ別", statsDetailDurationAvg: "平均再生時間", statsDetailDurationMedian: "中央値", statsDetailVideos: "本", }, en: { colIndex: "#", colTitle: "Title", colChannel: "Channel", colDuration: "Duration", colViews: "Views", colPublished: "Published", colCategory: "Category", colAddedBy: "Added by", colVotes: "Votes", filterTitle: "Search title...", filterChannel: "Channel...", filterAddedBy: "Added by...", filterCategory: "Category...", badgeLive: "LIVE", headerVideos: "videos", headerLoading: "loading…", fetchViews: "Fetch all details", fetchViewsProgress: "Fetching…", fetchViewsDone: "Done", colSettings: "View", colSettingsReset: "Reset", statsDuration: "Total", statsChannels: "Channels", statsPlayable: "Playable", statsTotalViews: "Total views", statsDetail: "Details", statsDetailChannelRank: "By channel", statsDetailAddedByRank: "By contributor", statsDetailCategoryBreak: "By category", statsDetailDurationAvg: "Avg. duration", statsDetailDurationMedian: "Median", statsDetailVideos: "videos", }, }; function detectLang(): string { const htmlLang = document.documentElement.lang; if (htmlLang?.startsWith("ja")) return "ja"; return "en"; } export function t(key: MessageKey): string { const lang = detectLang(); return (messages[lang] ?? messages.en)[key]; }