**Overview** - Integrates next-intl (App Router, no i18n routing) with cookie-based locale and Accept-Language fallback. - Adds message bundles and regional variants; sets en-US as the default. **Key changes** - i18n foundation - Adds request-scoped config to load messages per locale and injects NextIntlClientProvider in [layout.tsx] - Adds/updates messages for: en-US, en-GB, zh-TW, zh-HK, zh-CN, ja, ko, fr-FR, fr-CA, de. Centralizes LOCALES, LOCALE_LABELS, and DEFAULT_LOCALE in [locales.ts] - Adds LocaleSwitcher (cookie-based) and [LocaleBootstrap] - Pages and components - Localizes Sidebar, Home (including metadata/manifest), Settings, Discover, Library. - Localizes common components: MessageInput, Attach, Focus, Optimization, MessageBox, MessageSources, SearchImages, SearchVideos, EmptyChat, NewsArticleWidget, WeatherWidget. - APIs - Weather API returns localized condition strings server-side. - UX and quality - Converts all remaining <img> to Next Image. - Updates browserslist/caniuse DB to silence warnings. - Security: Settings API Key inputs are now password fields and placeholders were removed.
45 lines
1.5 KiB
TypeScript
45 lines
1.5 KiB
TypeScript
// Runtime loader for a Unicode-capable font (Noto Sans TC) for jsPDF, to fix CJK garbled text
|
|
// Note: Load fonts from local /public/fonts to avoid any external CDN dependency.
|
|
// License: Noto fonts are under SIL Open Font License 1.1
|
|
|
|
import jsPDF from 'jspdf';
|
|
|
|
let fontsLoaded = false;
|
|
|
|
// Files should be placed at public/fonts (see public/fonts/README.md)
|
|
const NOTO_TC_REGULAR = '/fonts/NotoSansTC-Regular.ttf';
|
|
const NOTO_TC_BOLD = '/fonts/NotoSansTC-Bold.ttf';
|
|
|
|
function arrayBufferToBinaryString(buffer: ArrayBuffer): string {
|
|
let binary = '';
|
|
const bytes = new Uint8Array(buffer);
|
|
const chunkSize = 0x8000; // avoid call stack overflow
|
|
for (let i = 0; i < bytes.length; i += chunkSize) {
|
|
const chunk = bytes.subarray(i, i + chunkSize);
|
|
binary += String.fromCharCode.apply(
|
|
null,
|
|
Array.from(chunk) as unknown as number[],
|
|
);
|
|
}
|
|
return binary;
|
|
}
|
|
|
|
export async function ensureNotoSansTC(doc: jsPDF): Promise<void> {
|
|
if (fontsLoaded) return;
|
|
const [regBuf, boldBuf] = await Promise.all([
|
|
fetch(NOTO_TC_REGULAR).then((r) => r.arrayBuffer()),
|
|
fetch(NOTO_TC_BOLD).then((r) => r.arrayBuffer()),
|
|
]);
|
|
|
|
const regBin = arrayBufferToBinaryString(regBuf);
|
|
const boldBin = arrayBufferToBinaryString(boldBuf);
|
|
|
|
// Register into VFS and add fonts
|
|
doc.addFileToVFS('NotoSansTC-Regular.ttf', regBin);
|
|
doc.addFont('NotoSansTC-Regular.ttf', 'NotoSansTC', 'normal');
|
|
|
|
doc.addFileToVFS('NotoSansTC-Bold.ttf', boldBin);
|
|
doc.addFont('NotoSansTC-Bold.ttf', 'NotoSansTC', 'bold');
|
|
|
|
fontsLoaded = true;
|
|
}
|