PubliraGitHub

可獨立使用的函式庫

全部採用 Apache-2.0 授權,都在 Publira 中實際使用,使用其中任何一個都不必引入整個平台。

@publira/comic-viewer

Publira 章節閱讀畫面所用的 React 漫畫閱讀器,已獨立出來,UI 和資料管線完全由你掌控。

  • Headless UI 架構:組合彼此獨立、支援 tree-shaking 的元件,樣式全部由你自己定義。
  • 響應式跨頁,依容器寬度在單頁和雙頁之間切換。
  • 採用虛擬化,即使載入大量高解析度頁面,行動瀏覽器也不會崩潰。
  • 可插拔的資料管線:透過 definePlugin() 注入擷取、解密或分析處理。
  • 日式漫畫預設由右向左閱讀,歐美漫畫可設為由左向右,內建滑動、點擊和鍵盤翻頁。
  • 透過 resolvePage() 延遲載入頁面中繼資料,適用於長文件和會過期的簽章 URL。

尚未發布 1.0:在 0.x 系列中,修補版本會盡量保持相容,次要版本則可能變更公開 API。升級前請閱讀變更記錄。

閱讀文件
安裝
npm install @publira/comic-viewer
app/reader.tsx
import * as ComicViewer from "@publira/comic-viewer";
import "@publira/comic-viewer/core.css";

export function Reader({ pages }: ReaderProps) {
  return (
    <ComicViewer.Root
      initialReadingDirection="rtl"
      pages={pages}
    >
      <ComicViewer.Viewport />
      <ComicViewer.Toolbar />
      <ComicViewer.PageNavigation />
    </ComicViewer.Root>
  );
}

publira/epub

用於解碼、編碼與驗證 EPUB 3 的 Go 函式庫,專為不在磁碟上讀寫檔案的伺服器設計。

  • 不依賴檔案系統:Decode 只需要一個 io.ReaderAt 和封存檔大小。
  • 快速失敗:遇到結構錯誤時立即傳回 DecodeError。
  • 記憶體使用效率高,可透過 Asset.Open 依需求以串流方式讀取。
  • 嚴格驗證 EBPAJ 和 KADOKAWA 風格的命名與目錄規則。
  • 固定版面的圖片頁面以 SVG 包裹,在任何閱讀系統中都能讓頁面維持符合畫面的大小。
  • 為封面、目錄、正文、索引和詞彙表等 landmark 賦予結構語意。

產生的出版品可以透過儲存庫附帶的指令碼,以 W3C 官方的 EPUBCheck 檢查,該工具會快取在 .tools/ 下。

閱讀文件
安裝
go get github.com/publira/epub
main.go
f, err := os.Open("book.epub")
if err != nil {
	log.Fatal(err)
}
defer f.Close()

st, err := f.Stat()
if err != nil {
	log.Fatal(err)
}

opt := epub.WithCompliance(epub.LevelEBPAJ)
doc, err := epub.Decode(f, st.Size(), opt)
if err != nil {
	log.Fatal(err)
}

if err := epub.Encode(out, doc); err != nil {
	log.Fatal(err)
}

publira/messageformat-dart

符合 LDML 48.2 的 Unicode MessageFormat 2.0 純 Dart 實作,用於格式化行動用戶端的訊息。

  • 純 Dart 實作,不依賴 Flutter,在伺服器、命令列和 Flutter 應用程式中都能執行。
  • 通過 MessageFormat 工作小組一致性測試套件 (LDML48.2) 的全部 461 個案例,沒有略過任何一個,並在 CI 中隨每次變更執行。
  • 支援規範中標為 Stable 的所有函式 (:string, :number, :integer, :offset, :currency, :percent),可依所有 CLDR 地區設定格式化數字。
  • 處於 Draft 階段的日期和時間函式放在 messageformat_datetime 中,不格式化日期的應用程式不必打包其 CLDR 資料。
  • formatToParts 傳回 sealed 類別階層的片段,可用於產生帶樣式的文字等輸出。
  • 格式化出錯時不會擲出例外,而是將錯誤回報給回呼並使用備用值;除了預設函式,也可以註冊自訂函式。

尚未發布 1.0。遵循 LDML 48.2 (UTS #35 Part 9, tr35-78) 與 Unicode CLDR 48.2 資料,升級到更新版本的規範時會作為單獨的版本發布。

閱讀文件
安裝
dart pub add messageformat
main.dart
import 'package:messageformat/messageformat.dart';

final mf = MessageFormat(
  'en',
  r'''
.input {$count :number}
.match $count
0   {{No episodes}}
one {{{$count} episode}}
*   {{{$count} episodes}}
''',
  options: const MessageFormatOptions(
    bidiIsolation: BidiIsolation.none,
  ),
);

mf.format({'count': 0}); // 'No episodes'
mf.format({'count': 1}); // '1 episode'
mf.format({'count': 1000}); // '1,000 episodes'