compat(epub): detect missing writing direction for some EPUBs (#2803)

This commit is contained in:
Huang Xin
2025-12-28 19:43:49 +01:00
committed by GitHub
parent 988fbc8c85
commit b76a2adf61
5 changed files with 42 additions and 5 deletions
@@ -132,7 +132,8 @@ const FoliateViewer: React.FC<{
const bookData = getBookData(bookKey);
if (viewSettings && detail.type === 'text/css')
return transformStylesheet(data, width, height, viewSettings.vertical);
if (viewSettings && bookData && detail.type === 'application/xhtml+xml') {
const isHtml = detail.type === 'application/xhtml+xml' || detail.type === 'text/html';
if (viewSettings && bookData && isHtml) {
const ctx: TransformContext = {
bookKey,
viewSettings,
@@ -1,4 +1,4 @@
import { detectLanguage, isSameLang, isValidLang } from '@/utils/lang';
import { detectLanguage, getLanguageInfo, isSameLang, isValidLang } from '@/utils/lang';
import type { Transformer } from './types';
export const languageTransformer: Transformer = {
@@ -21,12 +21,25 @@ export const languageTransformer: Transformer = {
isValidLang(primaryLanguage) && primaryLanguage !== 'en'
? primaryLanguage
: detectLanguage(mainContent);
const languageInfo = getLanguageInfo(lang || '');
const newLangAttr = ` lang="${lang}"`;
const newXmlLangAttr = ` xml:lang="${lang}"`;
attrs = langMatch ? attrs.replace(langRegex, newLangAttr) : attrs + newLangAttr;
attrs = xmlLangMatch ? attrs.replace(xmlLangRegex, newXmlLangAttr) : attrs + newXmlLangAttr;
const dirAttr = languageInfo?.direction === 'rtl' ? ' dir="rtl"' : '';
attrs = langMatch ? attrs.replace(langRegex, newLangAttr) : attrs + newLangAttr + dirAttr;
attrs = xmlLangMatch
? attrs.replace(xmlLangRegex, newXmlLangAttr)
: attrs + newXmlLangAttr + dirAttr;
result = result.replace(attrsMatch[0], `<html${attrs}>`);
}
} else {
const lang =
isValidLang(primaryLanguage) && primaryLanguage !== 'en'
? primaryLanguage
: detectLanguage(result.replace(/<[^>]+>/g, ' '));
const languageInfo = getLanguageInfo(lang || '');
const dirAttr = languageInfo?.direction === 'rtl' ? ' dir="rtl"' : '';
const newAttrs = ` lang="${lang}" xml:lang="${lang}" ${dirAttr}`;
result = result.replace(/<html>/i, `<html${newAttrs}>`);
}
return result;
},
+5
View File
@@ -4,3 +4,8 @@ export type Insets = {
left: number;
right: number;
};
export interface LocaleWithTextInfo extends Intl.Locale {
getTextInfo?: () => { direction: string };
textInfo?: { direction: string };
}
+4 -1
View File
@@ -2,6 +2,7 @@ import { BookDoc } from '@/libs/document';
import { BookNote, BookSearchConfig, BookSearchResult } from '@/types/book';
import { TTSGranularity } from '@/services/tts';
import { TTS } from 'foliate-js/tts.js';
import { LocaleWithTextInfo } from './misc';
export const NOTE_PREFIX = 'foliate-note:';
@@ -33,8 +34,10 @@ export interface FoliateView extends HTMLElement {
book: BookDoc;
tts: TTS | null;
language: {
locale?: string;
locale?: LocaleWithTextInfo;
isCJK?: boolean;
canonical?: string;
direction?: string;
};
history: {
canGoBack: boolean;
+15
View File
@@ -1,3 +1,4 @@
import { LocaleWithTextInfo } from '@/types/misc';
import { franc } from 'franc-min';
import { iso6392 } from 'iso-639-2';
import { iso6393To1 } from 'iso-639-3';
@@ -116,3 +117,17 @@ export const detectLanguage = (content: string): string => {
return 'en';
}
};
export const getLanguageInfo = (lang: string) => {
if (!lang) return {};
try {
const canonical = Intl.getCanonicalLocales(lang)[0]!;
const locale = new Intl.Locale(canonical) as LocaleWithTextInfo;
const isCJK = ['zh', 'ja', 'kr'].includes(locale.language);
const direction = (locale.getTextInfo?.() ?? locale.textInfo)?.direction;
return { canonical, locale, isCJK, direction };
} catch (e) {
console.warn(e);
return {};
}
};