From 7b7eb07cd8a84cf9c6ff595f1a8cfe83b51df504 Mon Sep 17 00:00:00 2001 From: h7x4 Date: Tue, 21 Mar 2023 21:16:19 +0100 Subject: [PATCH] Generate booklets --- 2page-booklet-wrapper.tex | 15 ++++++ flake.nix | 54 +++++++++++-------- template.tex | 44 +++++++++++++--- testContent.tex | 23 ++++++--- yokutango2tex.hs | 106 ++++++++++++++++++++++++++++++-------- 5 files changed, 184 insertions(+), 58 deletions(-) create mode 100644 2page-booklet-wrapper.tex diff --git a/2page-booklet-wrapper.tex b/2page-booklet-wrapper.tex new file mode 100644 index 0000000..e0544e6 --- /dev/null +++ b/2page-booklet-wrapper.tex @@ -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} diff --git a/flake.nix b/flake.nix index e3ea9a9..9f8b8c2 100644 --- a/flake.nix +++ b/flake.nix @@ -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"; }; }; }; } diff --git a/template.tex b/template.tex index 95b445d..3d86853 100644 --- a/template.tex +++ b/template.tex @@ -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} diff --git a/testContent.tex b/testContent.tex index 79fb5bb..65df668 100644 --- a/testContent.tex +++ b/testContent.tex @@ -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} diff --git a/yokutango2tex.hs b/yokutango2tex.hs index 26c24b9..6b35083 100644 --- a/yokutango2tex.hs +++ b/yokutango2tex.hs @@ -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