'多语言'

This commit is contained in:
eric
2026-03-08 04:30:57 -05:00
parent 51eeea3be3
commit def36bf3aa
30 changed files with 6058 additions and 323 deletions

43
app/lib/ebook.ts Normal file
View File

@@ -0,0 +1,43 @@
import { marked } from "marked";
export interface EbookChunk {
html: string;
estimatedHeight: number;
}
export interface EbookData {
chunks: EbookChunk[];
headers: string[];
}
export function parseEbookMarkdown(source: string): EbookData {
const html = marked.parse(source, { breaks: true, gfm: true }) as string;
const lazyHtml = html.replace(/<img /g, '<img loading="lazy" decoding="async" ');
let rawChunks = lazyHtml.split(/(?=<h1[\s>])/i).filter((c) => c.trim());
if (rawChunks.length <= 1) {
rawChunks = lazyHtml.split(/(?=<h2[\s>])/i).filter((c) => c.trim());
}
const headers: string[] = [];
const headerRegex = /<h1[^>]*>(.*?)<\/h1>/gi;
let m;
while ((m = headerRegex.exec(lazyHtml)) !== null) {
headers.push(m[1].replace(/<[^>]+>/g, ""));
}
if (headers.length === 0) {
const h2Regex = /<h2[^>]*>(.*?)<\/h2>/gi;
while ((m = h2Regex.exec(lazyHtml)) !== null) {
headers.push(m[1].replace(/<[^>]+>/g, ""));
}
}
const chunks: EbookChunk[] = rawChunks.map((chunkHtml) => {
const imgCount = (chunkHtml.match(/<img /g) || []).length;
const textLen = chunkHtml.replace(/<[^>]+>/g, "").length;
const estimatedHeight = Math.max(300, Math.round(textLen * 0.6 + imgCount * 350));
return { html: chunkHtml, estimatedHeight };
});
return { chunks, headers };
}

22
app/lib/locale-link.tsx Normal file
View File

@@ -0,0 +1,22 @@
"use client";
import NextLink from "next/link";
import { usePathname as useNextPathname } from "next/navigation";
import { useLocale } from "../context/LocaleContext";
type LocaleLinkProps = React.ComponentProps<typeof NextLink>;
export function LocaleLink({ href, ...props }: LocaleLinkProps) {
const locale = useLocale();
const hrefStr = typeof href === "string" ? href : href.pathname ?? "/";
const localeHref = hrefStr.startsWith("/")
? `/${locale}${hrefStr === "/" ? "" : hrefStr}`
: hrefStr;
return <NextLink href={localeHref} {...props} />;
}
export function usePathname() {
const path = useNextPathname();
const match = path?.match(/^\/(zh|en)(\/.*)?$/);
return match ? (match[2] ?? "/") : path ?? "/";
}