Generate booklets

main
Oystein Kristoffer Tveit 2023-03-21 21:16:19 +01:00
parent 9429ea82ad
commit 7b7eb07cd8
Signed by: oysteikt
GPG Key ID: 9F2F7D8250F35146
5 changed files with 184 additions and 58 deletions

15
2page-booklet-wrapper.tex Normal file
View File

@ -0,0 +1,15 @@
\documentclass[a4paper]{article}
\usepackage[final]{pdfpages}
\newcommand*{\numberofpages}[1]{%
\the\XeTeXpdfpagecount"#1" %
}
\newcounter{numberofsignaturepages}%
\begin{document}
\setcounter{numberofsignaturepages}{\numberofpages{yokutango.pdf}}%
\addtocounter{numberofsignaturepages}{4}%
\includepdf[pages=-,nup=1x2,landscape,signature=\thenumberofsignaturepages]{yokutango.pdf}
\end{document}

View File

@ -28,13 +28,37 @@
self.packages.${system}.noto-sans-cjk-jp
];
};
mkYokutango-pdf = { paper ? "a4paper" }: let
template = lib.fileContents ./template.tex;
y2t-output-d = pkgs.runCommand "yokutango2tex-output" {} ''
${self.packages.${system}.yokutango2tex}/bin/yokutango2tex ${self.packages.${system}.yokutango-json} > $out
'';
y2t-output = lib.fileContents y2t-output-d;
combined = pkgs.writeText ''yokutango.tex'' (builtins.replaceStrings [
"% --- %"
"$paper$"
] [
y2t-output
paper
] template);
in pkgs.runCommand "yokutango-pdf" { inherit nativeBuildInputs FONTCONFIG_FILE; } ''
mkdir $out
ln -s ${combined} yokutango.tex
ln -s ${combined} $out/yokutango.tex
xelatex yokutango.tex
xelatex yokutango.tex
ln -s ${./2page-booklet-wrapper.tex} yokutango-book.tex
xelatex yokutango-book.tex
mv yokutango.pdf yokutango-book.pdf $out
'';
in {
devshells.default = {
devShells.${system}.default = pkgs.mkShell {
inherit nativeBuildInputs FONTCONFIG_FILE;
};
packages.${system} = {
default = self.packages.${system}.yokutango-pdf;
default = self.packages.${system}.yokutango-pdf-a5;
noto-sans-cjk-jp = pkgs.runCommandLocal "noto-sans-cjk-jp" {} ''
mkdir -p $out/share/fonts/opentype/noto-cjk
@ -45,25 +69,6 @@
ln -s ${yokutango}/json $out
'';
yokutango2tex = pkgs.writers.writeHaskellBin "yokutango2tex" {
libraries = with pkgs.haskellPackages; [ aeson bytestring ];
} (lib.fileContents ./yokutango2tex.hs);
yokutango-pdf = let
template = lib.fileContents ./template.tex;
y2t-output-d = pkgs.runCommand "yokutango2tex-output" {} ''
${self.packages.${system}.yokutango2tex}/bin/yokutango2tex ${self.packages.${system}.yokutango-json} > $out
'';
y2t-output = lib.fileContents y2t-output-d;
combined = pkgs.writeText ''yokutango.tex'' (builtins.replaceStrings ["% --- %"] [y2t-output] template);
in pkgs.runCommand "yokutango-pdf" { inherit nativeBuildInputs FONTCONFIG_FILE; } ''
mkdir $out
ln -s ${combined} yokutango.tex
ln -s ${combined} $out/yokutango.tex
xelatex yokutango.tex
mv yokutango.pdf $out
'';
yokutango-test = let
template = lib.fileContents ./template.tex;
body = lib.fileContents ./testContent.tex;
@ -73,9 +78,16 @@
ln -s ${combined} yokutango-test.tex
ln -s ${combined} $out/yokutango-test.tex
xelatex yokutango-test.tex
xelatex yokutango-test.tex
mv yokutango-test.pdf $out
'';
yokutango2tex = pkgs.writers.writeHaskellBin "yokutango2tex" {
libraries = with pkgs.haskellPackages; [ aeson bytestring ];
} (lib.fileContents ./yokutango2tex.hs);
yokutango-pdf-a5 = mkYokutango-pdf { paper = "a5paper"; };
yokutango-pdf-a4 = mkYokutango-pdf { paper = "a4paper"; };
};
};
}

View File

@ -2,28 +2,58 @@
\usepackage{fontspec}
\usepackage{xeCJK}
\usepackage{ruby}
\usepackage{longtable}
\usepackage{parskip}
\usepackage{booktabs}
\usepackage[portrait,paper=a4paper,total={6in,8in}]{geometry}
\usepackage[twoside,paper=$paper$]{geometry}
\usepackage[dvipsnames, table]{xcolor}
\definecolor{rowColor}{RGB}{64, 120, 20}
\usepackage{mathtools}
\usepackage{multicol}
\setmainfont{Noto Sans}
\setCJKmainfont{Noto Sans CJK JP}
\definecolor{rowColor}{RGB}{149, 184, 230}
\definecolor{headerColor}{gray}{1}
\rowcolors{1}{}{rowColor!30!white}
\setlength{\parindent}{0pt}
\setlength{\parskip}{\baselineskip}
\renewcommand{\rubysep}{1mm}
\setlength{\columnsep}{1.5cm}
\setlength{\columnseprule}{0.2pt}
\setcounter{secnumdepth}{0}
\newcommand{\ruby}[2]{$\stackrel{\text{#2}}{\text{#1}}$}
\renewcommand\arraystretch{1.5}
\setlength\extrarowheight{5pt}
\begin{document}
\thispagestyle{empty}
\topskip0pt
\vspace*{\fill}
\begin{center}
{
\fontsize{30pt}{36pt}\normalfont
よく単語
}
\vspace*{1cm}
March 2023
\end{center}
\vspace*{\fill}
\newpage
\begin{multicols}{2}
\tableofcontents
\end{multicols}
\newpage
% --- %
\end{document}

View File

@ -1,10 +1,17 @@
\def\arraystretch{1.5}
\begin{longtable}[]{@{}ll@{}}
\toprule
日本語 & Norsk \\
\midrule
\endhead
\ruby{言葉}{ことば} & ord \\
\ruby{}{ぶん} & setning \\
\bottomrule
\setlength\extrarowheight{5pt}
\begin{longtable}[]{|l|c@{}|l@{}|l|}
Status & 日本語 & Norsk & Notes \\
\endhead
& \ruby{統合失調症}{とうごうしっちょうしょう} & schizofrenia & \\
& \ruby{点火する}{てんかする} & å sette fyr & \\
& \ruby{石英}{せきえい} & kvarts & \\
& \ruby{}{ふさ} & en bunke & \\
& \ruby{新来者}{しんらいしゃ} & nykommer & \\
& \ruby{伝わる}{つたわる} & å sende (et signal) & \\
& \ruby{伝わる}{つたわる} & å sende $\begin{cases} \text{et signal} \\ \text{en melding} \\ \text{bølger} \\ \text{to transmit} \end{cases}$ & \\
& \ruby{伝わる}{つたわる} & \begin{tabular}{l@{}}
å sende (et signal) \\
å sende $\begin{pmatrix} \text{et signal} \\ \text{en melding} \\ \text{bølger} \\ \text{to transmit} \end{pmatrix}$ \\
\end{tabular} & \\
\end{longtable}

View File

@ -2,7 +2,6 @@
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE NamedFieldPuns #-}
import Data.Aeson
@ -12,7 +11,8 @@ import System.Directory
import System.Environment
import System.FilePath
import Data.Maybe
import Data.List (intersperse)
import Data.List (intersperse, sort)
import Control.Applicative ((<|>))
import qualified Data.Text.Lazy as T
import qualified Data.Text.Lazy.IO as T
@ -48,13 +48,33 @@ instance FromJSON Card
instance ToJSON Card where
toEncoding = genericToEncoding defaultOptions
data LaTeXRow = LaTeXRow { jw :: T.Text
, nw :: T.Text
}
(+?) :: Semigroup a => a -> Maybe a -> a
a +? b = case b of
Nothing -> a
Just b' -> a <> b'
flipAppend :: T.Text -> T.Text -> T.Text
flipAppend = flip T.append
wrap :: T.Text -> T.Text -> T.Text -> T.Text
wrap s e w = mconcat [s, w, e]
indent :: T.Text -> T.Text
indent = mconcat
. map (wrap "\t" "\n")
. T.splitOn "\n"
readJsonFile :: FilePath -> IO (Either String WordBlock)
readJsonFile path = do
fileContent <- BS.readFile path
return $ cardsToWordblock <$> eitherDecode fileContent
where
formatPath :: FilePath -> T.Text
formatPath = T.append " "
formatPath = T.append "単語 "
. fromMaybe "???"
. T.stripPrefix "yokutango_"
. fromString
@ -64,42 +84,84 @@ readJsonFile path = do
, cards = cards
}
cardToRow :: Card -> T.Text
cardToRow card = mconcat [ japanesePart card, " $\\longleftrightarrow$ ", norwegianPart card ]
cardToRow :: Card -> LaTeXRow
cardToRow card = LaTeXRow { jw = japanesePart card
, nw = norwegianPart card
}
where
ruby :: T.Text -> T.Text -> T.Text
ruby main top = mconcat [ "\\ruby{", main, "}{", top, "}" ]
subtable :: [T.Text] -> T.Text
subtable rows = mconcat [ "\\begin{tabular}{@{}l@{}}\n"
, mconcat $ map (\t -> mconcat ["\t", t, " \\\\\n"]) rows
, "\\end{tabular}"
]
hintsToPmatrix :: [T.Text] -> T.Text
hintsToPmatrix = wrap " $\\begin{pmatrix}" "\\end{pmatrix}$"
. mconcat
. intersperse " \\\\ "
. map (wrap "\\text{" "}")
jpWordToText :: JapaneseWord -> T.Text
jpWordToText JapaneseWord { word, romaji, hints } =
case (word, romaji, hints) of
(w, Just r, _) -> mconcat [ "\\ruby{", w, "}{", r, "}" ]
(w, Nothing, _) -> w
jpWordToText JapaneseWord { word, romaji, hints } =
case hints of
Nothing -> furiganaBlock
(Just [hint]) -> mconcat [ furiganaBlock, " (", hint, ")" ]
(Just hints) -> subtable [mconcat [furiganaBlock, hintsToPmatrix hints ]]
where
rubyStr = ruby word <$> romaji
furiganaBlock = fromMaybe word rubyStr
noWordToText :: NorwegianWord -> T.Text
noWordToText NorwegianWord { word, hints } = word
japanesePart (Card { japanese }) = mconcat $ intersperse ("\\\\\n" :: T.Text) $ map jpWordToText japanese
norwegianPart (Card { norwegian }) = mconcat $ intersperse ("\\\\\n" :: T.Text) $ map noWordToText norwegian
noWordToText NorwegianWord { word, hints } =
case hints of
Nothing -> word
Just [hint] -> mconcat [word, " (", hint, ")"]
Just hints -> subtable [mconcat [ word, hintsToPmatrix hints]]
japanesePart :: Card -> T.Text
japanesePart (Card { japanese = [jpWord] }) = jpWordToText jpWord
japanesePart (Card { japanese }) = subtable $ map jpWordToText japanese
norwegianPart :: Card -> T.Text
norwegianPart (Card { norwegian = [noWord] }) = noWordToText noWord
norwegianPart (Card { norwegian }) = subtable $ map noWordToText norwegian
wordblockToTable :: WordBlock -> T.Text
wordblockToTable block = mconcat tablePieces
where
rows = map ((\t -> T.append t "\\\\\n") . cardToRow) (cards block)
tablePieces = [ "\\section*{", title block, "}\n" ] ++ rows ++ ["\\newpage"]
rows :: [LaTeXRow]
rows = map cardToRow (cards block)
rowToText :: LaTeXRow -> T.Text
rowToText (LaTeXRow { jw, nw }) = indent $ mconcat [ " & ", jw, " & ", nw, " & \\\\\n" ]
tablePieces :: [T.Text]
tablePieces = [ "\\section{", title block, "}\n"
, "\\begin{longtable}{|l|l@{}|l@{}|l|}\n"
, "\\hline\n"
, "\\rowcolor{headerColor}\n"
, "Status & 日本語 & Norsk & Extra Notes \\\\\n"
, "\\hline\n"
, "\\endhead\n"
, "\\hline"
, "\\endfoot"
]
++ map rowToText rows
++ [ "\\end{longtable}\n"
, "\\newpage\n\n"
]
main :: IO ()
main = do
dir <- head <$> getArgs
filePaths <- map (\x -> joinPath [dir, x]) <$> listDirectory dir
filePaths <- sort . map (\x -> joinPath [dir, x]) <$> listDirectory dir
wordBlocks :: Either str [WordBlock] <- sequence <$> mapM readJsonFile filePaths
let output = case wordBlocks of
Right blocks -> mconcat $ map wordblockToTable blocks
Left err -> fromString err
BS.putStr $ T.encodeUtf8 $ output
-- case jsonFiles of
-- Right cards -> mapM_ print cards
-- Left err -> putStr err
BS.putStr $ T.encodeUtf8 output