Typstの日本語組版対応状況
Typst 0.15.1の日本語組版機能をW3C JLReqの要件と比較します。
はじめに
この文書では、W3C『日本語組版処理の要件(JLReq)』第2版の訂正版(2020年8月11日公開)の見出し構成に沿って、Typst 0.15.1の対応状況を示します。
評価は、PDF、SVG、PNGに共通するTypst本体のページ組版用公開APIで、JLReqが示す組版結果を再現できるかに基づきます。JLReqが文書内容に応じた処理を求める項目は、Typstが任意の内容にその処理を自動適用できることを条件とします。JLReqが著者による指定を前提とする設計項目は、Typstの既存の組版処理を関数やshowルールで設定または組み合わせて構成できれば対応に含めます。文字列解析、改行位置の決定、文字単位の配置など、JLReqが求める組版処理自体を利用者が再実装する方法は含めません。特定の内容に合わせて外観だけを再現する方法と、HTML要素やCSSを直接出力する方法も含めません。
項目内の処理をすべて再現できる場合は「対応」、一部だけ再現できる場合、または組方向や適用条件に制限がある場合は「一部対応」、どの処理も再現できない場合は「未対応」とします。処理要件を含まない説明、分類、利用例は「評価対象外」です。
この文書は日本語組版に必要な機能を網羅しておらず、W3CとTypst GmbHのいずれからも承認を受けていません。内容を参照する際はこれらの点に十分注意し、誤りや不足があればGitHub Issuesへお寄せください。
1. 序論
評価対象外 JLReq自体の目的と構成を説明する章であり、Typstの機能要件ではありません。
1.1 この文書の目的
評価対象外
1.2 この文書の作成方法
評価対象外
1.3 この文書の執筆方針
評価対象外
1.4 この文書の構成
評価対象外
1.5 用語の参照その他
評価対象外
2. 日本語組版の基本
一部対応 Typstは横組の本文とページ寸法・余白を設定できます。基本版面とは、本文の文字サイズ、字詰め数、行数、行間などから定まる基準領域です。縦組と、基本版面で定めた行位置を本文、見出し、図表へ自動的かつ一貫して適用する処理には対応していません。 縦組はRFC: Vertical Writing Mode(typst/typst#5908)で提案されています。
#set page(width: 120pt, height: 160pt, margin: 16pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 8pt)
#set par(justify: true, leading: 4pt)
Typstでは、横組の本文とページの寸法や余白を設定できます。文字は左から右へ並び、行は上から下へ進みます。
2.1 日本語組版に使用する文字と配置の原則
一部対応 Unicode文字とOpenTypeフォントを使って、漢字、仮名、約物、欧文を横組できます。縦組と縦組用字形には対応していません。
#set page(width: 300pt, height: 70pt, margin: 14pt)
#set text(
font: "Noto Serif CJK JP",
lang: "ja",
region: "JP",
size: 9pt,
)
漢字・ひらがな・カタカナ、123、Latin、Ελληνικά。
2.1.1 日本語組版に使用する文字
評価対象外 日本語組版で使用する文字を挙げ、組版処理で参照する文字クラスを説明する項目です。
2.1.2 漢字等,平仮名,片仮名
一部対応 JLReqは漢字、平仮名、片仮名を全角の文字枠へ配置し、小書き仮名を横組では左右中央かつ下寄り、縦組では上下中央かつ右寄りに配置することを前提としています。横組ではフォントのアドバンス幅と字面位置に従うため、全角幅と小書き仮名の位置はフォントに依存します。縦組と縦組用字形の選択には対応していません。 縦組の設計案はRFC: Vertical Writing Mode(typst/typst#5908)にまとめられています。
#set page(width: 150pt, height: 170pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 10pt)
#context {
let chars = ("漢", "あ", "ア", "ゃ")
table(
columns: 2,
[文字], [幅],
..chars.map(char => (char, [#measure(char).width])).flatten(),
)
}
2.1.3 漢字及び仮名の配置の原則
一部対応 全角字形はフォントのアドバンス幅に従って配置されます。同じスタイルで一つのテキスト範囲として整形される文字間では、text.trackingの正負値で字間を広げたり狭めたりできます。text.scriptを明示すれば、漢字、平仮名、片仮名の境界にも適用できます。text.trackingの既定値は0ptで、通常は一律の字間を加えません。指定幅のbox内を両端揃えにすれば、CJK文字列を均等割りにすることもできます。ただし、trackingは文字スタイルやboxなどの要素の境界には適用されません。JLReqの文字クラスに基づいて均等割りの対象外とする箇所を選ぶ処理と、字面に応じた詰め量の決定にも対応していません。 和文に対するtrackingの不具合はtracking is not processed correctly for Japanese(typst/typst#7976)で報告されています。字形の輪郭に基づく詰めはAutomatic optical kerning(typst/typst#8514)で提案されています。
#set page(width: 220pt, height: 150pt, margin: 14pt)
#set text(
font: "Noto Serif CJK JP",
lang: "ja",
size: 9pt,
kerning: false,
)
#let even(width, body) = box(width: width, stroke: .5pt)[
#set par(justify: true)
#body#linebreak(justify: true)
]
広げる:#text(tracking: .25em)[日本語組版]#linebreak()
狭める:#text(tracking: -.1em)[日本語組版]#linebreak()
書記体系をまたぐ:#text(script: "jpan", tracking: .25em)[漢字かなカナ]#linebreak()
均等割り:#even(8em)[漢字かなカナ]
2.2 日本語文書の基本となる組体裁
一部対応 page、text、parなどを組み合わせ、仕上りサイズ、綴じ側、基本版面に相当する本文領域、段数を設計できます。縦組と、基本版面の行位置をページ内の要素へ自動的かつ一貫して適用する処理には対応していません。
#set page(
width: 200pt,
height: 130pt,
margin: (inside: 16pt, outside: 12pt, y: 18pt),
binding: left,
columns: 2,
header: align(right)[章名],
footer: context align(center)[#counter(page).display("1")],
)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 7pt)
#set par(justify: true, leading: 3pt)
第1段の本文です。
#colbreak()
第2段の本文です。
2.2.1 組体裁の設計
評価対象外 基本となる組体裁を決め、それを基準として各ページを設計するという手順を説明する項目です。
2.2.2 基本となる組体裁
一部対応 本文、目次、索引などに異なる横組の体裁を適用できます。単段組と多段組にも対応していますが、縦組の体裁は構成できません。 縦組の設計案はRFC: Vertical Writing Mode(typst/typst#5908)にまとめられています。
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 7pt)
#set page(width: 120pt, height: 160pt, margin: 16pt)
*本文・単段組*
#par(justify: true)[日本語の本文を一つの段に配置します。]
#pagebreak()
#set page(width: 150pt, height: 120pt, margin: 12pt, columns: 2)
*索引・二段組*
あ項目\
い項目
#colbreak()
う項目\
え項目
2.2.3 基本となる組体裁の主な設計要素
一部対応 pageで仕上りサイズ、綴じ側、内外余白、段数、柱、ノンブルを指定し、余白によって基本版面に相当する本文領域を配置できます。bindingと内外余白はTypst 0.6.0以降で利用できます(Support for inside and outside margins(typst/typst#1308))。JLReqは基本版面をページ全体の文字格子とはせず、行の位置を基準として扱いますが、Typstにはその行位置へ見出しや図版の前後を自動的に戻す処理がありません。縦組にも対応していません。
#set page(
width: 200pt,
height: 130pt,
margin: (inside: 16pt, outside: 12pt, y: 18pt),
binding: left,
columns: 2,
header: align(right)[章名],
footer: context align(center)[#counter(page).display("1")],
)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 7pt)
#set par(justify: true, leading: 3pt)
第1段の本文です。
#colbreak()
第2段の本文です。
2.2.4 基本版面の設計要素
一部対応 横組では、フォント、文字サイズ、字詰め数、行数、行間、段数、段間から基本版面の寸法を計算し、本文領域として設定できます。text.top-edge、text.bottom-edge、par.leadingを明示すれば、文字サイズと行間から定まる一定の行送りも設定できます。縦組の基本版面は構成できません。
#let nominal-character-size = 8pt
#let characters = 12
#let lines = 8
#let nominal-line-gap = 4pt
#let column-count = 2
#let column-gap = 12pt
#let column-width = nominal-character-size * characters
#let hanmen-width = (
column-width * column-count + column-gap * (column-count - 1)
)
#let hanmen-height = (
nominal-character-size * lines + nominal-line-gap * (lines - 1)
)
#set page(
width: hanmen-width + 24pt,
height: hanmen-height + 24pt,
margin: 12pt,
)
#set text(
font: "Noto Serif CJK JP",
lang: "ja",
size: nominal-character-size,
top-edge: .5em,
bottom-edge: -.5em,
)
#set par(leading: nominal-line-gap)
#columns(column-count, gutter: column-gap)[
#block(width: column-width, height: hanmen-height, stroke: .5pt)[
1段目。字詰め数、行数、行間から公称寸法を計算します。
]
#colbreak()
#block(width: column-width, height: hanmen-height, stroke: .5pt)[2段目。]
]
2.2.5 基本版面と実際のページの設計例
一部対応 横組では、見出しを基本版面の整数行分の領域へ配置し、字下げ量を基本版面の文字サイズから計算できます。図版の幅を段幅または本文領域の幅に合わせ、天または地へ配置することもできます。目次には基本版面と異なる本文領域を設定できます。ただし、見出しや図版の後で本文を基本版面の行位置へ自動的に戻す処理と、縦組には対応していません。
#let text-size = 8pt
#let leading = 3pt
#let line-height = text-size + leading
#set page(
width: 250pt,
height: 170pt,
margin: 16pt,
columns: 2,
)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: text-size)
#set par(leading: leading)
#figure(
rect(width: 100%, height: 14pt, fill: luma(84%))[本文領域の幅],
placement: top,
scope: "parent",
)
#block(height: 3 * line-height - leading, width: 100%, stroke: .5pt)[
#align(horizon + left)[#h(4em)*3行取りの見出し*]
]
見出しの後に続く本文です。基本版面の行位置へ戻す処理はありません。
#figure(
rect(width: 100%, height: 14pt, fill: luma(88%))[段幅],
placement: bottom,
)
#pagebreak()
#set page(margin: 28pt, columns: 1)
*本文とは異なる領域を使う目次*
1. 第一章\
2. 第二章
2.3 組方向(縦組と横組)
一部対応 横組には対応していますが、縦組を指定する機能はありません。 縦組の設計案はRFC: Vertical Writing Mode(typst/typst#5908)にまとめられています。
#set page(width: 120pt, height: 160pt, margin: 16pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 8pt)
#set par(justify: true, leading: 4pt)
Typstでは、横組の本文とページの寸法や余白を設定できます。文字は左から右へ並び、行は上から下へ進みます。
2.3.1 日本語組版における組方向
評価対象外 日本語組版で使われる縦組と横組の種類と用途を説明する項目です。
2.3.2 縦組と横組の主な相違点
一部対応 横組では文字を左から右へ並べ、行を上から下へ送り、段を左から右へ配置します。bindingで綴じ側を指定できますが、ページの進行方向は文書設定として保持されません。図表は、横組用には上側を左へ向けて反時計回りに90度、縦組用には上側を右へ向けて時計回りに90度回転できます。ただし、縦組用字形、右から左への行送り、縦組における英数字の3種類の配置、縦中横には対応しておらず、回転した図表を縦組本文と連動して配置することもできません。横組の多段組で最終ページの各段の行数を自動的に揃える機能もありません。 最終ページの段の均等化はBalancing the contents of multiple columns to the same vertical space(typst/typst#466)で提案され、0.15.1より後にImplement column balancing(typst/typst#8207)で実装されました。縦組の設計案はRFC: Vertical Writing Mode(typst/typst#5908)にまとめられています。
#set page(width: 250pt, height: 110pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 8pt)
#let illustration = rect(
width: 3em,
height: 2em,
stroke: 0.5pt,
inset: 2pt,
)[上 図版]
#grid(
columns: (1fr, 1fr, 1fr),
gutter: 12pt,
[*横組* #linebreak()欧字],
[*横組の図版* #linebreak()#box(height: 3em)[#rotate(-90deg)[#illustration]]],
[*縦組の図版* #linebreak()#box(height: 3em)[#rotate(90deg)[#illustration]]],
)
#set page(
width: 200pt,
height: 130pt,
margin: (inside: 16pt, outside: 12pt, y: 18pt),
binding: left,
columns: 2,
header: align(right)[章名],
footer: context align(center)[#counter(page).display("1")],
)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 7pt)
#set par(justify: true, leading: 3pt)
第1段の本文です。
#colbreak()
第2段の本文です。
2.4 基本版面の設計
一部対応 横組では、文字サイズ、字詰め数、行数、行間から基本版面の寸法を計算し、ページ余白へ反映できます。高さとベースラインを固定した行内要素では、文字サイズが変わっても後続行の位置を保てます。ただし、見出しや図表の後を含む文書全体を基本版面の行位置へ自動的に戻す処理と、縦組の基本版面には対応していません。 基本版面で定めた行位置へ配置する機能はGrid typesetting support(typst/typst#1306)で提案されています。
#let nominal-character-size = 8pt
#let characters = 12
#let lines = 8
#let nominal-line-gap = 4pt
#let column-count = 2
#let column-gap = 12pt
#let column-width = nominal-character-size * characters
#let hanmen-width = (
column-width * column-count + column-gap * (column-count - 1)
)
#let hanmen-height = (
nominal-character-size * lines + nominal-line-gap * (lines - 1)
)
#set page(
width: hanmen-width + 24pt,
height: hanmen-height + 24pt,
margin: 12pt,
)
#set text(
font: "Noto Serif CJK JP",
lang: "ja",
size: nominal-character-size,
top-edge: .5em,
bottom-edge: -.5em,
)
#set par(leading: nominal-line-gap)
#columns(column-count, gutter: column-gap)[
#block(width: column-width, height: hanmen-height, stroke: .5pt)[
1段目。字詰め数、行数、行間から公称寸法を計算します。
]
#colbreak()
#block(width: column-width, height: hanmen-height, stroke: .5pt)[2段目。]
]
#set page(width: 300pt, height: 150pt, margin: 14pt)
#set text(
font: "Noto Serif CJK JP",
lang: "ja",
size: 8pt,
top-edge: .5em,
bottom-edge: -.5em,
)
#set par(leading: 5pt)
#let fixed-line(body) = context {
let size = measure(body)
box(
width: size.width,
height: 0pt,
baseline: bottom,
move(dy: -size.height / 2, body),
)
}
#grid(
columns: (1fr, 1fr),
gutter: 12pt,
[
*通常*
#block(
width: 15em,
)[1行目です。\ 通常#text(size: 14pt)[大きな文字]です。\ 3行目です。]
],
[
*行位置を保つ*
#block(
width: 15em,
)[1行目です。\ 通常#fixed-line(text(size: 14pt)[大きな文字])です。\ 3行目です。]
],
)
2.4.1 基本版面の設計手順
一部対応 横組では、文字サイズ、字詰め数、行数、行間、段数、段間から基本版面の寸法を計算し、その寸法に合わせてページ余白を設定できます。縦組では同じ手順を適用できません。 基本版面で定めた行位置へ配置する機能はGrid typesetting support(typst/typst#1306)で提案されています。
#let nominal-character-size = 8pt
#let characters = 12
#let lines = 8
#let nominal-line-gap = 4pt
#let column-count = 2
#let column-gap = 12pt
#let column-width = nominal-character-size * characters
#let hanmen-width = (
column-width * column-count + column-gap * (column-count - 1)
)
#let hanmen-height = (
nominal-character-size * lines + nominal-line-gap * (lines - 1)
)
#set page(
width: hanmen-width + 24pt,
height: hanmen-height + 24pt,
margin: 12pt,
)
#set text(
font: "Noto Serif CJK JP",
lang: "ja",
size: nominal-character-size,
top-edge: .5em,
bottom-edge: -.5em,
)
#set par(leading: nominal-line-gap)
#columns(column-count, gutter: column-gap)[
#block(width: column-width, height: hanmen-height, stroke: .5pt)[
1段目。字詰め数、行数、行間から公称寸法を計算します。
]
#colbreak()
#block(width: column-width, height: hanmen-height, stroke: .5pt)[2段目。]
]
#set page(width: 300pt, height: 150pt, margin: 14pt)
#set text(
font: "Noto Serif CJK JP",
lang: "ja",
size: 8pt,
top-edge: .5em,
bottom-edge: -.5em,
)
#set par(leading: 5pt)
#let fixed-line(body) = context {
let size = measure(body)
box(
width: size.width,
height: 0pt,
baseline: bottom,
move(dy: -size.height / 2, body),
)
}
#grid(
columns: (1fr, 1fr),
gutter: 12pt,
[
*通常*
#block(
width: 15em,
)[1行目です。\ 通常#text(size: 14pt)[大きな文字]です。\ 3行目です。]
],
[
*行位置を保つ*
#block(
width: 15em,
)[1行目です。\ 通常#fixed-line(text(size: 14pt)[大きな文字])です。\ 3行目です。]
],
)
2.4.2 基本版面の設計の注意点
一部対応 横組では、仕上りサイズと余白、文字サイズ、文字サイズの整数倍となる行長、一定の行間を指定できます。字詰め数、行数、段数、段間から基本版面の寸法を計算することもできます。本文のtext.top-edgeとtext.bottom-edgeを基線に対して対称にした上で、行間へはみ出す行内要素をmeasureで測り、高さ0のbox内でmoveを使って中心を本文行の中心へそろえれば、後続行の位置を変えずに配置できます。ただし、版面・段の端での配置方式の切替、文書全体を基本版面の行位置へ自動的に戻す処理には対応していません。縦組も構成できません。 基本版面で定めた行位置へ配置する機能はGrid typesetting support(typst/typst#1306)で提案されています。
#let nominal-character-size = 8pt
#let characters = 12
#let lines = 8
#let nominal-line-gap = 4pt
#let column-count = 2
#let column-gap = 12pt
#let column-width = nominal-character-size * characters
#let hanmen-width = (
column-width * column-count + column-gap * (column-count - 1)
)
#let hanmen-height = (
nominal-character-size * lines + nominal-line-gap * (lines - 1)
)
#set page(
width: hanmen-width + 24pt,
height: hanmen-height + 24pt,
margin: 12pt,
)
#set text(
font: "Noto Serif CJK JP",
lang: "ja",
size: nominal-character-size,
top-edge: .5em,
bottom-edge: -.5em,
)
#set par(leading: nominal-line-gap)
#columns(column-count, gutter: column-gap)[
#block(width: column-width, height: hanmen-height, stroke: .5pt)[
1段目。字詰め数、行数、行間から公称寸法を計算します。
]
#colbreak()
#block(width: column-width, height: hanmen-height, stroke: .5pt)[2段目。]
]
#set page(width: 300pt, height: 150pt, margin: 14pt)
#set text(
font: "Noto Serif CJK JP",
lang: "ja",
size: 8pt,
top-edge: .5em,
bottom-edge: -.5em,
)
#set par(leading: 5pt)
#let fixed-line(body) = context {
let size = measure(body)
box(
width: size.width,
height: 0pt,
baseline: bottom,
move(dy: -size.height / 2, body),
)
}
#grid(
columns: (1fr, 1fr),
gutter: 12pt,
[
*通常*
#block(
width: 15em,
)[1行目です。\ 通常#text(size: 14pt)[大きな文字]です。\ 3行目です。]
],
[
*行位置を保つ*
#block(
width: 15em,
)[1行目です。\ 通常#fixed-line(text(size: 14pt)[大きな文字])です。\ 3行目です。]
],
)
2.5 基本版面の設計要素の各ページに対する適用
一部対応 要素の位置や余白はページごとに指定できます。ただし、基本版面で定めた行位置と行頭・行末を基準に、本文、注、見出し、図表を自動的かつ一貫して配置する機能はありません。
#set page(width: 140pt, height: 120pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 7pt)
#set par(leading: 4pt)
#block(width: 100%, height: 76pt, stroke: .5pt, inset: 6pt)[
#place(top + right, dx: 10pt, rect(
width: 24pt,
height: 18pt,
fill: luma(90%),
))
各要素の位置を指定します。
]
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 7pt)
#set page(width: 120pt, height: 160pt, margin: 16pt)
*本文・単段組*
#par(justify: true)[日本語の本文を一つの段に配置します。]
#pagebreak()
#set page(width: 150pt, height: 120pt, margin: 12pt, columns: 2)
*索引・二段組*
あ項目\
い項目
#colbreak()
う項目\
え項目
2.5.1 基本版面からはみ出す例
一部対応 下線、上付き・下付き文字、合印、図版・表・キャプションは配置できます。図版や表はplaceなどで本文領域の外へ配置できます。本文のtext.top-edgeとtext.bottom-edgeを基線に対して対称にした上で、行送り方向へはみ出す行内要素をmeasureで測り、高さ0のbox内でmoveを使って中心を本文行の中心へそろえれば、後続行の位置を変えずに配置できます。ただし、句読点のぶら下げ組、圏点、縦組の傍線、ページ・段の端での配置方式の切替には対応していません。 句読点を含むぶら下げ組の設定はMore configurable text overhang(typst/typst#261)とChinese punctuation overhang(typst/typst#6582)で、ルビはAdd support for ruby (CJK, e.g., furigana for Japanese)(typst/typst#1489)で提案されています。
#set page(width: 240pt, height: 145pt, margin: 16pt)
#set text(
font: "Noto Serif CJK JP",
lang: "ja",
size: 8pt,
)
#block(width: 22em, stroke: .5pt)[
#place(top + right, dx: 10pt, rect(
width: 18pt,
height: 14pt,
fill: luma(85%),
))
本文領域の外へ図版を配置します。#linebreak()
下線#underline[付き]、注#super[1]、CO#sub[2]も配置できます。
]
#place(bottom + right, dx: 10pt)[
#figure(
table(
columns: 2,
inset: 1pt,
[項目], [値],
[表], [1],
),
caption: [本文領域の外へ置いた表],
)
]
#set page(width: 300pt, height: 150pt, margin: 14pt)
#set text(
font: "Noto Serif CJK JP",
lang: "ja",
size: 8pt,
top-edge: .5em,
bottom-edge: -.5em,
)
#set par(leading: 5pt)
#let fixed-line(body) = context {
let size = measure(body)
box(
width: size.width,
height: 0pt,
baseline: bottom,
move(dy: -size.height / 2, body),
)
}
#grid(
columns: (1fr, 1fr),
gutter: 12pt,
[
*通常*
#block(
width: 15em,
)[1行目です。\ 通常#text(size: 14pt)[大きな文字]です。\ 3行目です。]
],
[
*行位置を保つ*
#block(
width: 15em,
)[1行目です。\ 通常#fixed-line(text(size: 14pt)[大きな文字])です。\ 3行目です。]
],
)
2.5.2 基本版面で設定した行位置の適用
一部対応 text.top-edge、text.bottom-edge、par.leadingを明示すれば、通常の本文行に一定の基線間隔を設定できます。本文より大きい文字や行送り方向へ移動した内容を、高さとベースラインを固定したboxへ入れ、moveで位置を指定すれば、後続行の位置も保てます。ただし、見出しや図表の後を含む本文全体をページ上の基準線へ自動的に戻す機能はありません。 行送りを基線間隔として指定する案はProposal: change leading option to line-height(typst/typst#4224)で、ページ上の基準線へ揃える組版はGrid typesetting support(typst/typst#1306)で提案されています。
#set page(width: 300pt, height: 150pt, margin: 14pt)
#set text(
font: "Noto Serif CJK JP",
lang: "ja",
size: 8pt,
top-edge: .5em,
bottom-edge: -.5em,
)
#set par(leading: 5pt)
#let fixed-line(body) = context {
let size = measure(body)
box(
width: size.width,
height: 0pt,
baseline: bottom,
move(dy: -size.height / 2, body),
)
}
#grid(
columns: (1fr, 1fr),
gutter: 12pt,
[
*通常*
#block(
width: 15em,
)[1行目です。\ 通常#text(size: 14pt)[大きな文字]です。\ 3行目です。]
],
[
*行位置を保つ*
#block(
width: 15em,
)[1行目です。\ 通常#fixed-line(text(size: 14pt)[大きな文字])です。\ 3行目です。]
],
)
2.5.3 基本版面で設定した文字位置の適用
一部対応 漢字や仮名はフォントの全角幅に従ってベタ組にできますが、基本版面で定めた文字位置を行内の格子として保持する機能はありません。プロポーショナルな欧字、異なる文字サイズ、行頭括弧、連続する約物などが入ると、後続の文字はその幅に応じて移動します。par.justifyで行末を揃え、Typst 0.14.0以降はpar.justification-limitsで単語間と文字間の伸縮量を指定できます(Support for character-level justification(typst/typst#6161))が、JLReqが示す文字種ごとの調整対象と優先順位には一致しません。 ページ上の基準線・文字位置へ揃える組版はGrid typesetting support(typst/typst#1306)で、CJK文字間の空きを調整して公称の行長へ合わせる処理はStrict grid for CJK, hopefully via glue(typst/typst#4404)で提案されています。
#set page(width: 250pt, height: 135pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 10pt)
#let gauge(body) = box(width: 10em, height: 1.6em)[
#place(top + left)[
#grid(
columns: (1em,) * 10,
..range(10).map(_ => rect(
width: 1em,
height: 1.6em,
stroke: .25pt + luma(75%),
)),
)
]
#place(top + left, dy: .2em)[#body]
]
*全角文字だけのベタ組*
#gauge[天地玄黄宇宙洪荒日月]
*プロポーショナルな欧字を含む行*
#gauge[天地Typst宇宙洪荒]
2.6 柱とノンブル
一部対応 pageのheader、footer、numberingとページカウンターを使い、横組の柱とノンブルを基本版面から計算した位置へ配置できます。縦組の配置には対応していません。 縦組の柱とノンブルに必要な縦組モードはRFC: Vertical Writing Mode(typst/typst#5908)で提案されています。
#set page(
width: 130pt,
height: 160pt,
margin: 20pt,
header: align(right)[章名],
footer: context align(center)[#counter(page).display("1")],
)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 8pt)
柱とノンブルを指定した横組のページです。
2.6.1 柱及びノンブルの位置
一部対応 header-ascent、footer-descent、配置関数を使い、横組の柱とノンブルを基本版面から文字サイズよりやや大きく空けて配置できます。左ページでは左端、右ページでは右端にそろえ、1字内側へ寄せることもできます。同じ行に置く場合は、ノンブルを小口側にして柱との間を1.5字または2字空けられます。縦組の配置には対応していません。 縦組の柱とノンブルに必要な縦組モードはRFC: Vertical Writing Mode(typst/typst#5908)で提案されています。
#set page(
width: 200pt,
height: 160pt,
margin: 24pt,
header-ascent: 10pt,
header: context {
let page-number = counter(page).get().first()
let content = if calc.even(page-number) {
[#page-number#h(1.5em)章名]
} else {
[章名#h(1.5em)#page-number]
}
pad(x: 1em, align(
if calc.even(page-number) { left } else { right },
content,
))
},
)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 8pt)
右ページではノンブルを小口側の右端から1字内側へ置きます。
#pagebreak()
左ページではノンブルを小口側の左端から1字内側へ置きます。
2.6.2 柱及びノンブルの配置の原則
一部対応 page.headerとpage.footerで柱とノンブルを余白内へ配置できます。本文と目次で本文領域が異なる場合も、ページ余白を共通にして本文領域だけを個別に狭めれば、柱とノンブルの位置を保てます。奇偶ページで位置を変える場合は、ページ番号に応じた条件分岐を使えます。縦組の配置には対応していません。 縦組の柱とノンブルに必要な縦組モードはRFC: Vertical Writing Mode(typst/typst#5908)で提案されています。
#set page(
width: 130pt,
height: 160pt,
margin: 20pt,
header: align(right)[章名],
footer: context align(center)[#counter(page).display("1")],
)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 8pt)
#block(width: 100%)[本文の版面です。]
#pagebreak()
#pad(x: 10pt)[
#block(width: 100%)[目次の本文領域です。左右を10ptずつ狭めています。]
]
#let folio-style = state("folio-style", "i")
#let section-start = state("section-start", 1)
#let blank-pages = state("blank-pages", ())
#let headerless-pages = state("headerless-pages", ())
#let uncounted-pages = state("uncounted-pages", ())
#let logical-page(physical) = {
let skipped = uncounted-pages.final().filter(page => page <= physical).len()
physical - skipped
}
#let omit-header() = context {
let physical = here().page()
headerless-pages.update(pages => pages + (physical,))
}
#let omit-count() = context {
let physical = here().page()
uncounted-pages.update(pages => pages + (physical,))
}
#let parity-break(to) = {
context {
let current = here().page()
if (
(to == "odd" and calc.odd(current))
or (to == "even" and calc.even(current))
) {
blank-pages.update(pages => pages + (current + 1,))
}
}
pagebreak(to: to)
}
#set page(
width: 180pt,
height: 130pt,
margin: 20pt,
header: context {
let physical = here().page()
let number = counter(page).get().first()
let headings = query(selector(heading).before(here()))
if (
not blank-pages.final().contains(physical)
and not headerless-pages.final().contains(physical)
and not uncounted-pages.final().contains(physical)
and headings.len() > 0
) {
if calc.odd(number) {
align(right, headings.last().body)
} else {
align(left)[文書名(略称)]
}
}
},
footer: context {
let physical = here().page()
let number = logical-page(physical)
let last = logical-page(counter(page).final().first())
let style = folio-style.get()
if (
not blank-pages.final().contains(physical)
and not uncounted-pages.final().contains(physical)
) {
align(center)[
#numbering(style, number)
#if (
style == "1"
) [ 章別 #numbering("1", number - section-start.get() + 1)]
逆 #numbering("1", last - number + 1)
]
}
},
)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 8pt)
まえがき
見出しのない先頭ページでは柱を省き、ローマ数字のノンブルを使います。
#parity-break("odd")
#context {
folio-style.update("1")
section-start.update(logical-page(here().page()))
}
= 第一章
文書最初の見出しより前には参照できる見出しがないため、柱はありません。
== 第一節
#pagebreak()
#omit-header()
このページでは柱を明示的に省きます。
#parity-break("even")
#omit-count()
*口絵*(ページ数から除外)
直前に自動挿入された白ページは、柱とノンブルを省きますがページ数には含めます。
#pagebreak()
奇数ページでは直前の見出しを右に置きます。前の口絵を数えないため、物理7ページ目のノンブルは6になります。
#pagebreak()
偶数ページでは文書名の略称を左に置きます。
2.6.3 柱及びノンブルの配置方式
一部対応 ページ番号と取得した見出しを条件分岐すれば、横組の片柱・両柱、奇偶ページごとの内容、明示したページでの柱の省略を構成できます。柱用に用意した短い見出しも使用できます。page.numberingとページカウンターによって、通し番号、章ごとの番号、前付のローマ数字なども構成できます。文書区分に応じた体系の切替、複数のノンブル、逆ノンブルには、カウンターの更新と条件分岐を組み合わせます。奇数・偶数ページへの改ページを関数で包み、改ページ前の物理ページ番号から挿入される白ページをstateに記録すれば、そのページの柱とノンブルを省けます。別紙などの数えないページを別のstateに記録し、表示するページ番号から除外することもできます。縦組の配置と、縦組の見出しに含まれる数字や欧字を柱向けの表記へ自動変換する処理には対応していません。 奇数・偶数ページへの改ページで自動挿入される空白ページから柱とノンブルを省く機能はSkip headers and footers for skipped pages(typst/typst#2722)で提案されています。縦組の柱とノンブルに必要な縦組モードはRFC: Vertical Writing Mode(typst/typst#5908)で提案されています。
#let folio-style = state("folio-style", "i")
#let section-start = state("section-start", 1)
#let blank-pages = state("blank-pages", ())
#let headerless-pages = state("headerless-pages", ())
#let uncounted-pages = state("uncounted-pages", ())
#let logical-page(physical) = {
let skipped = uncounted-pages.final().filter(page => page <= physical).len()
physical - skipped
}
#let omit-header() = context {
let physical = here().page()
headerless-pages.update(pages => pages + (physical,))
}
#let omit-count() = context {
let physical = here().page()
uncounted-pages.update(pages => pages + (physical,))
}
#let parity-break(to) = {
context {
let current = here().page()
if (
(to == "odd" and calc.odd(current))
or (to == "even" and calc.even(current))
) {
blank-pages.update(pages => pages + (current + 1,))
}
}
pagebreak(to: to)
}
#set page(
width: 180pt,
height: 130pt,
margin: 20pt,
header: context {
let physical = here().page()
let number = counter(page).get().first()
let headings = query(selector(heading).before(here()))
if (
not blank-pages.final().contains(physical)
and not headerless-pages.final().contains(physical)
and not uncounted-pages.final().contains(physical)
and headings.len() > 0
) {
if calc.odd(number) {
align(right, headings.last().body)
} else {
align(left)[文書名(略称)]
}
}
},
footer: context {
let physical = here().page()
let number = logical-page(physical)
let last = logical-page(counter(page).final().first())
let style = folio-style.get()
if (
not blank-pages.final().contains(physical)
and not uncounted-pages.final().contains(physical)
) {
align(center)[
#numbering(style, number)
#if (
style == "1"
) [ 章別 #numbering("1", number - section-start.get() + 1)]
逆 #numbering("1", last - number + 1)
]
}
},
)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 8pt)
まえがき
見出しのない先頭ページでは柱を省き、ローマ数字のノンブルを使います。
#parity-break("odd")
#context {
folio-style.update("1")
section-start.update(logical-page(here().page()))
}
= 第一章
文書最初の見出しより前には参照できる見出しがないため、柱はありません。
== 第一節
#pagebreak()
#omit-header()
このページでは柱を明示的に省きます。
#parity-break("even")
#omit-count()
*口絵*(ページ数から除外)
直前に自動挿入された白ページは、柱とノンブルを省きますがページ数には含めます。
#pagebreak()
奇数ページでは直前の見出しを右に置きます。前の口絵を数えないため、物理7ページ目のノンブルは6になります。
#pagebreak()
偶数ページでは文書名の略称を左に置きます。
3. 行の組版処理
一部対応 横組ではCJK改行、約物間隔、和欧文間隔、段落整形の一部が働き、基本的なルビと割注を構成できます。縦中横と圏点の組版処理には対応していません。ルビと割注は横組の基本的な配置に限られます。
#set page(width: 150pt, height: 100pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 8pt)
#set par(justify: true)
#block(
width: 12em,
)[「括弧(本文)。」約物を含む文章を狭い行幅で両端揃えにします。]
#set page(width: 150pt, height: 90pt, margin: 14pt)
#set text(
font: (
(name: "Libertinus Serif", covers: "latin-in-cjk"),
"Noto Serif CJK JP",
),
lang: "ja",
size: 8pt,
)
日本語Latin日本語123
#set page(width: 360pt, height: 400pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 12pt)
#let ruby-gap = 3pt
#let simple-ruby(
base,
annotation,
side: top,
annotation-size: 0.5em,
third: false,
distribute: false,
) = context {
let annotation = text(size: annotation-size, annotation)
let annotation = if third {
scale(x: 66.667%, reflow: true, annotation)
} else {
annotation
}
let base-width = measure(base).width
let annotation-width = measure(annotation).width
let annotation-height = measure(annotation).height
let width = calc.max(base-width, annotation-width)
let fit(body, body-width) = if distribute and body-width < width {
box(width: width)[
#set par(justify: true)
#body#linebreak(justify: true)
]
} else {
body
}
let base = fit(base, base-width)
let annotation = fit(annotation, annotation-width)
let rows = if side == top {
(annotation, base)
} else {
(base, annotation)
}
box(
baseline: (
at: bottom,
shift: if side == top {
0pt
} else {
annotation-height + ruby-gap
},
),
grid(
columns: (width,),
rows: (auto, auto),
align: center,
row-gutter: ruby-gap,
..rows,
),
)
}
#let both-ruby(base, above, below) = context {
let above = text(size: 0.5em, above)
let below = text(size: 0.5em, below)
box(
baseline: (at: bottom, shift: measure(below).height + ruby-gap),
grid(
columns: (auto,),
rows: (auto, auto, auto),
align: center,
row-gutter: ruby-gap,
above,
base,
below,
),
)
}
上側:本文中の#simple-ruby([漢], [かん])です。
下側:本文中の#simple-ruby([語], [ご], side: bottom)です。
両側:本文中の#both-ruby([型], [かた], [type])です。
グループ(同じ長さ):#simple-ruby([市場], [しじょう], distribute: true)です。
グループ(ルビが短い):#simple-ruby([今日], [きょう], distribute: true)です。
グループ(ルビが長い):#simple-ruby([市場], [マーケット], distribute: true)です。
掛けない方式:前#simple-ruby([漢], [かんじ])後。
三分:本文中の#simple-ruby([私], [わたし], third: true)です。
#text(size: 16pt, weight: "bold")[
大見出し:#simple-ruby([組], [くみ], annotation-size: 0.4em)
]
分割禁止:#block(width: 4em, stroke: 0.5pt)[前前前#simple-ruby([市場], [しじょう])後後]
#set page(width: 300pt, height: 145pt, margin: 14pt)
#set text(
font: "Noto Serif CJK JP",
lang: "ja",
size: 12pt,
top-edge: .5em,
bottom-edge: -.5em,
)
#let warichu(upper, lower, size: 6pt, delimiters: true, gap: 0.5em) = box(
baseline: horizon,
grid(
columns: (auto, auto, auto),
align: horizon,
if delimiters { text(size: size * 2, lang: "ja", [(]) } else { h(gap) },
grid(
columns: (auto,),
rows: (auto, auto),
row-gutter: 0pt,
text(size: size, lang: "ja", upper),
text(size: size, lang: "ja", lower),
),
if delimiters { text(size: size * 2, lang: "ja", [)]) } else { h(gap) },
),
)
括弧付き:本文中に#warichu([用語(上段)], [説明、下段。])割注を配置します。
括弧なし:本文中に#warichu([用語について], [説明を加える], delimiters: false)割注を配置します。
3.1 約物などの組版処理
一部対応 日本語をlang: "ja"に設定すると、組み込みのCJK改行規則と日本語の約物調整が働きます。CJK約物の自動調整はTypst 0.4.0で導入され(Implement sophisticated CJK punctuation adjustment(typst/typst#954))、日本語約物の幅調整は0.11.0で修正されました(Fix JIS style punctuation(typst/typst#3543))。ただし、配置方式の選択肢と行調整の対象・優先順位はJLReqの規則をすべて満たしていません。 CJK約物処理全体はBetter CJK support(typst/typst#276)で追跡されています。
#set page(width: 150pt, height: 100pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 8pt)
#set par(justify: true)
#block(
width: 12em,
)[「括弧(本文)。」約物を含む文章を狭い行幅で両端揃えにします。]
3.1.1 縦組と横組で異なる約物など
一部対応 横組の約物は組版できますが、縦組に対応していないため、組方向に応じた字形と配置の切替はできません。 縦組はRFC: Vertical Writing Mode(typst/typst#5908)で提案されています。
#set page(width: 150pt, height: 100pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 8pt)
#set par(justify: true)
#block(
width: 12em,
)[「括弧(本文)。」約物を含む文章を狭い行幅で両端揃えにします。]
3.1.2 句読点や,括弧類などの基本的な配置方法
一部対応 lang: "ja"を指定した横組では、フォントと組み込み規則に基づいて句読点と括弧を配置します。ただし、配置方式は選択できず、JLReqが詰める調整の対象外とする行中の句点後の二分アキも縮小される場合があります。 約物の配置方式を選ぶ機能はOption to have raw, unchanged, surpriseless, uniform CJK full-width punctuation width(typst/typst#7643)で提案されています。
#set page(width: 150pt, height: 100pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 8pt)
#set par(justify: true)
#block(
width: 12em,
)[「括弧(本文)。」約物を含む文章を狭い行幅で両端揃えにします。]
3.1.3 読点及び中点の例外的な配置方法
未対応 横組の単位記号、連数字、数式・化学式と、縦組の漢数字を文脈として認識し、読点・中点を例外的にベタ組する機能はありません。
3.1.4 始め括弧類,終わり括弧類,読点類,句点類及び中点類が連続する場合の配置方法
一部対応 lang: "ja"を指定すると、連続するCJK約物の空きは日本語の規則で自動調整されます。ただし、組合せごとの詰め方は選べず、showルールで置換した約物との境界では連続約物の圧縮が働きません。 showルールを適用した約物の圧縮はPunctuation compression does not work with #show(typst/typst#5474)で追跡されています。
#set page(width: 150pt, height: 100pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 8pt)
通常:)。次
#show "。": "."
置換:)。次
3.1.5 行頭の始め括弧類の配置方法
一部対応 lang: "ja"を指定すると行頭の括弧は自動調整されますが、段落字下げを指定した場合はJLReq 3.1.5の配置になりません。天付き・二分下がりなどの方式も選択できません。 段落先頭の括弧配置はCJK brackets at the beginning of paragraph(typst/typst#4011)とCJK punctuation at the start of paragraphs are not adjusted sometimes(typst/typst#2348)で追跡されています。
#set page(width: 180pt, height: 150pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 8pt)
*指定なし*
#block(width: 18em)[「同じ文章を配置します。」]
*1字下げ*
#block(width: 18em)[
#set par(first-line-indent: (amount: 1em, all: true))
「同じ文章を配置します。」
]
3.1.6 区切り約物及びハイフン類の配置方法
一部対応 疑問符・感嘆符とハイフン類の分割可否にはUnicodeの改行規則が適用されます。字幅はフォントに従い、JLReqが定めるハイフン類の字幅を独立に保証しません。文末・文中・行末の疑問符・感嘆符の空きと、ハイフン後の始め括弧・中点との空きを文字クラスに応じて切り替える機能もありません。
#set page(width: 260pt, height: 235pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 8pt)
空白なし:疑問符?後続 感嘆符!後続
明示あり:疑問符? 後続 感嘆符! 後続
ハイフン後:‐( ‐・
*狭い行での分割*
#grid(
columns: (1fr, 1fr),
gutter: 12pt,
[
疑問符
#block(width: 4em, stroke: .5pt)[前文?後続文]
],
[
ハイフン
#block(width: 4em, stroke: .5pt)[あいう‐えおか]
],
)
#context table(
columns: (auto, auto, auto),
align: center,
[文字], [JLReq], [Typst(8pt時)],
[‐], [四分], [#measure("‐").width],
[–], [半角], [#measure("–").width],
[゠], [半角], [#measure("゠").width],
[〜], [全角], [#measure("〜").width],
)
3.1.7 行頭禁則
一部対応 日本語として指定した一般的な閉じ括弧、句読点、小書き仮名などにはCJK改行規則が適用されますが、禁則の強度や対象は変更できません。
#set page(width: 120pt, height: 100pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 8pt)
#block(width: 6em)[日日日日日日)次]
#block(width: 6em)[日日日日日日ゃ次]
3.1.8 行末禁則
一部対応 日本語として指定した一般的な始め括弧などにはCJK改行規則が適用されますが、禁則の強度や対象は変更できません。
#set page(width: 120pt, height: 100pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 8pt)
#block(width: 5.5em)[日日日日日(次)]
3.1.9 行末に配置する終わり括弧類,句点類,読点類及び中点類の配置方法
一部対応 lang: "ja"を指定すると行末約物は日本語の改行と行調整の対象になりますが、JLReqが示す行末での半角取り、全角取り、ぶら下げの各方式を選択して適用できません。
#set page(width: 120pt, height: 90pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 8pt)
#set par(justify: true)
#block(width: 5.5em)[日日日日日。次]
3.1.10 分割禁止
一部対応 Unicodeの改行規則により、数字列、欧文単語、連続するダッシュなどの途中では分割を避けます。親文字と添え字、合印、グループルビ、振分けをそれぞれboxにまとめれば、横組では各まとまりの内部を分割不可にできます。既定のfootnoteではCJK文字と合印の間で改行される場合がありますが、親文字とfootnoteを一つのboxにまとめる関数で防げます。ただし、表2が定める文字群を文脈に応じて認識する処理、割注始め括弧の直後と割注終わり括弧の直前だけを分割禁止にする処理、熟語ルビについて親文字1字と対応するルビ文字列を一体に保ちながら、その単位間だけを分割可能にする処理には対応していません。 CJK文字と、専用字形へ置換されない上付き文字または脚注合印の間で改行される問題はWrong linebreak opportunitity before non-typographic superscript(typst/typst#3129)で報告されています。
#set page(width: 270pt, height: 210pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 8pt)
#grid(
columns: (1fr, 1fr),
gutter: 14pt,
row-gutter: 6pt,
[*数字列* #block(width: 6em, stroke: .5pt)[前 1234567890 後]],
[*欧文単語* #block(width: 6em, stroke: .5pt)[前 ABCDEFGH 後]],
[*連続ダッシュ* #block(width: 4em, stroke: .5pt)[前前 ―― 後後]],
[*添え字* #block(width: 6em, stroke: .5pt)[日日日日日親#super[注]次]],
[*脚注合印* #block(width: 6em, stroke: .5pt)[日日日日日親#footnote[脚注です。]次]],
)
#set page(width: 360pt, height: 400pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 12pt)
#let ruby-gap = 3pt
#let simple-ruby(
base,
annotation,
side: top,
annotation-size: 0.5em,
third: false,
distribute: false,
) = context {
let annotation = text(size: annotation-size, annotation)
let annotation = if third {
scale(x: 66.667%, reflow: true, annotation)
} else {
annotation
}
let base-width = measure(base).width
let annotation-width = measure(annotation).width
let annotation-height = measure(annotation).height
let width = calc.max(base-width, annotation-width)
let fit(body, body-width) = if distribute and body-width < width {
box(width: width)[
#set par(justify: true)
#body#linebreak(justify: true)
]
} else {
body
}
let base = fit(base, base-width)
let annotation = fit(annotation, annotation-width)
let rows = if side == top {
(annotation, base)
} else {
(base, annotation)
}
box(
baseline: (
at: bottom,
shift: if side == top {
0pt
} else {
annotation-height + ruby-gap
},
),
grid(
columns: (width,),
rows: (auto, auto),
align: center,
row-gutter: ruby-gap,
..rows,
),
)
}
#let both-ruby(base, above, below) = context {
let above = text(size: 0.5em, above)
let below = text(size: 0.5em, below)
box(
baseline: (at: bottom, shift: measure(below).height + ruby-gap),
grid(
columns: (auto,),
rows: (auto, auto, auto),
align: center,
row-gutter: ruby-gap,
above,
base,
below,
),
)
}
上側:本文中の#simple-ruby([漢], [かん])です。
下側:本文中の#simple-ruby([語], [ご], side: bottom)です。
両側:本文中の#both-ruby([型], [かた], [type])です。
グループ(同じ長さ):#simple-ruby([市場], [しじょう], distribute: true)です。
グループ(ルビが短い):#simple-ruby([今日], [きょう], distribute: true)です。
グループ(ルビが長い):#simple-ruby([市場], [マーケット], distribute: true)です。
掛けない方式:前#simple-ruby([漢], [かんじ])後。
三分:本文中の#simple-ruby([私], [わたし], third: true)です。
#text(size: 16pt, weight: "bold")[
大見出し:#simple-ruby([組], [くみ], annotation-size: 0.4em)
]
分割禁止:#block(width: 4em, stroke: 0.5pt)[前前前#simple-ruby([市場], [しじょう])後後]
#set page(width: 220pt, height: 125pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 8pt)
#let attached(base, script) = box[#base#script]
#grid(
columns: (1fr, 1fr),
gutter: 14pt,
[
*通常*
#block(width: 6em, stroke: .5pt)[日日日日日親#super[注]次]
],
[
*box*
#block(width: 6em, stroke: .5pt)[日日日日日#attached([親], super[注])次]
],
)
下付き:#attached([CO], sub[2])
数式:$x^2 + a_1$
#set page(width: 210pt, height: 500pt, margin: 14pt)
#set text(
font: "Noto Serif CJK JP",
lang: "ja",
size: 10pt,
top-edge: .5em,
bottom-edge: -.5em,
)
#let furiwake(width, upper, lower, row-gap: 2pt) = box(
baseline: horizon,
grid(
columns: (width,),
rows: (auto, auto),
align: left,
row-gutter: row-gap,
{
set par(leading: 0pt)
upper
},
{
set par(leading: 0pt)
lower
},
),
)
自動幅:
#furiwake(auto)[短い上段][長い下段]
指定幅での自動折返し:
#furiwake(7em)[短い上段][長い下段を折り返します]
明示改行:
#furiwake(7em)[上段の1行目\ 上段の2行目][下段]
文字・書体・振分け行間:
#text(font: "Noto Sans CJK JP", size: 8pt)[
#furiwake(auto, row-gap: 5pt)[小さい上段][小さい下段]
]
振分けを含む段落の行間:
#[
#set par(leading: 10pt)
前の行です。\
本文中の#furiwake(auto)[上段][下段]です。\
後ろの行です。
]
分割禁止:
#block(width: 4em, stroke: 0.5pt)[前前#furiwake(auto)[上段][下段]後後]
#set page(width: 240pt, height: 250pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 9pt)
#let noted(base, note) = box[#base#footnote(note)]
#let interlinear-note(base, note) = box[
#place(top + right, dy: -0.4em, footnote(note))
#base
]
既定の合印#footnote[既定の脚注です。]
#[
#set footnote(numbering: "①")
#set super(typographic: false, size: 0.6em, baseline: 0.5em)
#show footnote: set text(fill: maroon)
変更した合印#footnote[合印だけに色が付きます。]
]
#block(width: 6.6em, stroke: 0.5pt, inset: 2pt)[
日日日日日親#footnote[合印が親文字と分かれる場合があります。]次
]
#block(width: 6.6em, stroke: 0.5pt, inset: 2pt)[
日日日日日#noted([親], [親文字と合印を一体にします。])次
]
行間に置く合印:#interlinear-note([対象語], [対象語の上側に置いた合印です。])
#grid(
columns: (1fr, 1fr),
gutter: 10pt,
[
*合印なし*
#set par(leading: 6pt)
1行目です。\
2行目です。
],
[
*上付き合印*
#set par(leading: 6pt)
1行目#super[1]です。\
2行目です。
],
)
3.1.11 行の調整処理で字間を空ける処理に使用しない箇所
一部対応 boxの内部は外側の行調整から独立するため、親文字と添え字など、明示したまとまりの内部では字間を広げないようにできます。ただし、JLReqが定める空け禁止箇所を文字群と文脈に応じて選び、その箇所だけを行調整から除外する処理には対応していません。
#set page(width: 220pt, height: 180pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 8pt)
#let attached(base, script) = box[#base#script]
*ベタ組*
#block(width: 8em, stroke: .5pt)[始「中」終]
*両端揃え*
#block(width: 8em, stroke: .5pt)[
#set par(justify: true)
始「中」終#linebreak(justify: true)
]
#grid(
columns: (1fr, 1fr),
gutter: 12pt,
[
*通常*
#block(width: 8em, stroke: .5pt)[
#set par(justify: true)
始親#super[注]終#linebreak(justify: true)
]
],
[
*box*
#block(width: 8em, stroke: .5pt)[
#set par(justify: true)
始#attached([親], super[注])終#linebreak(justify: true)
]
],
)
#set page(width: 360pt, height: 400pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 12pt)
#let ruby-gap = 3pt
#let simple-ruby(
base,
annotation,
side: top,
annotation-size: 0.5em,
third: false,
distribute: false,
) = context {
let annotation = text(size: annotation-size, annotation)
let annotation = if third {
scale(x: 66.667%, reflow: true, annotation)
} else {
annotation
}
let base-width = measure(base).width
let annotation-width = measure(annotation).width
let annotation-height = measure(annotation).height
let width = calc.max(base-width, annotation-width)
let fit(body, body-width) = if distribute and body-width < width {
box(width: width)[
#set par(justify: true)
#body#linebreak(justify: true)
]
} else {
body
}
let base = fit(base, base-width)
let annotation = fit(annotation, annotation-width)
let rows = if side == top {
(annotation, base)
} else {
(base, annotation)
}
box(
baseline: (
at: bottom,
shift: if side == top {
0pt
} else {
annotation-height + ruby-gap
},
),
grid(
columns: (width,),
rows: (auto, auto),
align: center,
row-gutter: ruby-gap,
..rows,
),
)
}
#let both-ruby(base, above, below) = context {
let above = text(size: 0.5em, above)
let below = text(size: 0.5em, below)
box(
baseline: (at: bottom, shift: measure(below).height + ruby-gap),
grid(
columns: (auto,),
rows: (auto, auto, auto),
align: center,
row-gutter: ruby-gap,
above,
base,
below,
),
)
}
上側:本文中の#simple-ruby([漢], [かん])です。
下側:本文中の#simple-ruby([語], [ご], side: bottom)です。
両側:本文中の#both-ruby([型], [かた], [type])です。
グループ(同じ長さ):#simple-ruby([市場], [しじょう], distribute: true)です。
グループ(ルビが短い):#simple-ruby([今日], [きょう], distribute: true)です。
グループ(ルビが長い):#simple-ruby([市場], [マーケット], distribute: true)です。
掛けない方式:前#simple-ruby([漢], [かんじ])後。
三分:本文中の#simple-ruby([私], [わたし], third: true)です。
#text(size: 16pt, weight: "bold")[
大見出し:#simple-ruby([組], [くみ], annotation-size: 0.4em)
]
分割禁止:#block(width: 4em, stroke: 0.5pt)[前前前#simple-ruby([市場], [しじょう])後後]
#set page(width: 300pt, height: 145pt, margin: 14pt)
#set text(
font: "Noto Serif CJK JP",
lang: "ja",
size: 12pt,
top-edge: .5em,
bottom-edge: -.5em,
)
#let warichu(upper, lower, size: 6pt, delimiters: true, gap: 0.5em) = box(
baseline: horizon,
grid(
columns: (auto, auto, auto),
align: horizon,
if delimiters { text(size: size * 2, lang: "ja", [(]) } else { h(gap) },
grid(
columns: (auto,),
rows: (auto, auto),
row-gutter: 0pt,
text(size: size, lang: "ja", upper),
text(size: size, lang: "ja", lower),
),
if delimiters { text(size: size * 2, lang: "ja", [)]) } else { h(gap) },
),
)
括弧付き:本文中に#warichu([用語(上段)], [説明、下段。])割注を配置します。
括弧なし:本文中に#warichu([用語について], [説明を加える], delimiters: false)割注を配置します。
#set page(width: 220pt, height: 125pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 8pt)
#let attached(base, script) = box[#base#script]
#grid(
columns: (1fr, 1fr),
gutter: 14pt,
[
*通常*
#block(width: 6em, stroke: .5pt)[日日日日日親#super[注]次]
],
[
*box*
#block(width: 6em, stroke: .5pt)[日日日日日#attached([親], super[注])次]
],
)
下付き:#attached([CO], sub[2])
数式:$x^2 + a_1$
#set page(width: 210pt, height: 500pt, margin: 14pt)
#set text(
font: "Noto Serif CJK JP",
lang: "ja",
size: 10pt,
top-edge: .5em,
bottom-edge: -.5em,
)
#let furiwake(width, upper, lower, row-gap: 2pt) = box(
baseline: horizon,
grid(
columns: (width,),
rows: (auto, auto),
align: left,
row-gutter: row-gap,
{
set par(leading: 0pt)
upper
},
{
set par(leading: 0pt)
lower
},
),
)
自動幅:
#furiwake(auto)[短い上段][長い下段]
指定幅での自動折返し:
#furiwake(7em)[短い上段][長い下段を折り返します]
明示改行:
#furiwake(7em)[上段の1行目\ 上段の2行目][下段]
文字・書体・振分け行間:
#text(font: "Noto Sans CJK JP", size: 8pt)[
#furiwake(auto, row-gap: 5pt)[小さい上段][小さい下段]
]
振分けを含む段落の行間:
#[
#set par(leading: 10pt)
前の行です。\
本文中の#furiwake(auto)[上段][下段]です。\
後ろの行です。
]
分割禁止:
#block(width: 4em, stroke: 0.5pt)[前前#furiwake(auto)[上段][下段]後後]
#set page(width: 240pt, height: 250pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 9pt)
#let noted(base, note) = box[#base#footnote(note)]
#let interlinear-note(base, note) = box[
#place(top + right, dy: -0.4em, footnote(note))
#base
]
既定の合印#footnote[既定の脚注です。]
#[
#set footnote(numbering: "①")
#set super(typographic: false, size: 0.6em, baseline: 0.5em)
#show footnote: set text(fill: maroon)
変更した合印#footnote[合印だけに色が付きます。]
]
#block(width: 6.6em, stroke: 0.5pt, inset: 2pt)[
日日日日日親#footnote[合印が親文字と分かれる場合があります。]次
]
#block(width: 6.6em, stroke: 0.5pt, inset: 2pt)[
日日日日日#noted([親], [親文字と合印を一体にします。])次
]
行間に置く合印:#interlinear-note([対象語], [対象語の上側に置いた合印です。])
#grid(
columns: (1fr, 1fr),
gutter: 10pt,
[
*合印なし*
#set par(leading: 6pt)
1行目です。\
2行目です。
],
[
*上付き合印*
#set par(leading: 6pt)
1行目#super[1]です。\
2行目です。
],
)
3.1.12 行の調整処理例
一部対応 par(justify: true)で行長を揃えられますが、JLReqの優先順位どおりに調整する保証や設定はありません。
#set page(width: 250pt, height: 145pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 10pt)
#let phrase = [約物、漢字、かな、Latin textを含む文章を同じ幅で組みます。]
#grid(
columns: (1fr, 1fr),
gutter: 18pt,
[
*左揃え*
#block(width: 8em, stroke: .5pt, inset: 2pt)[
#set par(justify: false)
#phrase
]
],
[
*両端揃え*
#block(width: 8em, stroke: .5pt, inset: 2pt)[
#set par(justify: true)
#phrase
]
],
)
3.2 和欧文混植処理(縦中横処理を含む)
一部対応 横組の和欧文混植と和欧文間隔には対応していますが、縦組と縦中横には対応していません。
#set page(width: 150pt, height: 90pt, margin: 14pt)
#set text(
font: (
(name: "Libertinus Serif", covers: "latin-in-cjk"),
"Noto Serif CJK JP",
),
lang: "ja",
size: 8pt,
)
日本語Latin日本語123
3.2.1 和文と欧文との混植
評価対象外 日本語の文章に欧字、欧文、アラビア数字を混植する場面を説明する項目です。
3.2.2 横組の和欧文混植に用いる文字
一部対応 横組ではプロポーショナルな欧字と数字を混植でき、欧文単語間の空きも指定できます。通常の行頭・行末では空白が除かれます。Typst 0.13.0以降は、text.fontのcoversで和文と欧文のフォントを分けられます(Support for defining which charset should be covered by a font(typst/typst#5305))。ただし、"latin-in-cjk"はU+2018、U+2019、U+201C、U+201Dを欧文フォントの対象外とするため、欧文中の引用符も後続のCJKフォントから選ばれます。周囲の和文・欧文に応じて引用符のフォントを選ぶ処理と、割注の行頭・行末に固有の欧文間隔には対応していません。 和文用・欧文用フォントを分けた場合の引用符の選択はTypst 0.13 covers: "latin-in-cjk" doesn’t cover apostrophes and quotation marks(typst/typst#5858)で追跡されています。
#set page(width: 230pt, height: 100pt, margin: 14pt)
#set text(
font: (
(name: "Libertinus Serif", covers: "latin-in-cjk"),
"Noto Serif CJK JP",
),
lang: "ja",
size: 8pt,
spacing: 1em / 3,
)
和文とLatin textを混植します。
#block(width: 22em, stroke: .5pt)[ word space ]
#set page(width: 190pt, height: 150pt, margin: 14pt)
#set text(size: 9pt)
*既定*
#text(size: 20pt)[‘A’ “B” 'C' "D"]
#set text(font: (
(name: "Libertinus Serif", covers: "latin-in-cjk"),
"Noto Sans CJK JP",
))
*指定後*
#text(size: 20pt)[‘A’ “B” 'C' "D"]
3.2.3 縦組の和欧文混植に用いる文字
未対応 縦組モードがないため、欧字の向きや縦組用字形を含む混植はできません。 縦組はRFC: Vertical Writing Mode(typst/typst#5908)で提案されています。
3.2.4 全角のモノスペースの欧字及び全角のモノスペースのアラビア数字の配置方法
未対応 縦組モードがないため、全角欧字・数字を正常な向きで1字ずつ配置し、周囲の空きを規則に従って処理できません。 縦組はRFC: Vertical Writing Mode(typst/typst#5908)で提案されています。
3.2.5 縦中横の処理
未対応 縦組と縦中横のための要素や文字回転規則はありません。 縦組はRFC: Vertical Writing Mode(typst/typst#5908)で提案されています。
3.2.6 プロポーショナルな欧字を用いた和欧文混植処理
一部対応 横組では欧文単語内の分割を避け、Typst 0.9.0以降は和文と欧字・アラビア数字の境界に四分アキ相当の空きを自動挿入します(Automatically add spacing between CJK and Latin characters(typst/typst#2334))。ただし、縦組で欧文を90度回転して配置する処理はなく、行調整の優先順位や約物に接する場合の例外をJLReqの文字クラスに沿って指定することもできません。 和文と非CJK文字の間隔を調整して公称の行長へ合わせる処理はStrict grid for CJK, hopefully via glue(typst/typst#4404)で、縦組はRFC: Vertical Writing Mode(typst/typst#5908)で提案されています。
#set page(width: 210pt, height: 180pt, margin: 14pt)
#set text(
font: (
(name: "Libertinus Serif", covers: "latin-in-cjk"),
"Noto Serif CJK JP",
),
lang: "ja",
size: 14pt,
)
#set text(cjk-latin-spacing: auto)
自動:漢字Latin漢字
#set text(cjk-latin-spacing: none)
なし:漢字Latin漢字
*欧文単語内では分割しない*
#block(width: 4em, stroke: .5pt)[漢字Latin漢字]
3.3 ルビと圏点処理
一部対応 gridとboxを使う関数に親文字とルビ文字列を渡し、横組の基本的なモノルビとグループルビを分割不能な行内要素として構成できます。ただし、複数の親文字について熟語ルビに必要な親文字ごとの対応を維持する処理、文字クラスに応じた隣接文字への掛かり、改行位置の決定、行調整への参加には対応していません。圏点にも対応していません。 ルビはAdd support for ruby (CJK, e.g., furigana for Japanese)(typst/typst#1489)で提案されています。
#set page(width: 360pt, height: 400pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 12pt)
#let ruby-gap = 3pt
#let simple-ruby(
base,
annotation,
side: top,
annotation-size: 0.5em,
third: false,
distribute: false,
) = context {
let annotation = text(size: annotation-size, annotation)
let annotation = if third {
scale(x: 66.667%, reflow: true, annotation)
} else {
annotation
}
let base-width = measure(base).width
let annotation-width = measure(annotation).width
let annotation-height = measure(annotation).height
let width = calc.max(base-width, annotation-width)
let fit(body, body-width) = if distribute and body-width < width {
box(width: width)[
#set par(justify: true)
#body#linebreak(justify: true)
]
} else {
body
}
let base = fit(base, base-width)
let annotation = fit(annotation, annotation-width)
let rows = if side == top {
(annotation, base)
} else {
(base, annotation)
}
box(
baseline: (
at: bottom,
shift: if side == top {
0pt
} else {
annotation-height + ruby-gap
},
),
grid(
columns: (width,),
rows: (auto, auto),
align: center,
row-gutter: ruby-gap,
..rows,
),
)
}
#let both-ruby(base, above, below) = context {
let above = text(size: 0.5em, above)
let below = text(size: 0.5em, below)
box(
baseline: (at: bottom, shift: measure(below).height + ruby-gap),
grid(
columns: (auto,),
rows: (auto, auto, auto),
align: center,
row-gutter: ruby-gap,
above,
base,
below,
),
)
}
上側:本文中の#simple-ruby([漢], [かん])です。
下側:本文中の#simple-ruby([語], [ご], side: bottom)です。
両側:本文中の#both-ruby([型], [かた], [type])です。
グループ(同じ長さ):#simple-ruby([市場], [しじょう], distribute: true)です。
グループ(ルビが短い):#simple-ruby([今日], [きょう], distribute: true)です。
グループ(ルビが長い):#simple-ruby([市場], [マーケット], distribute: true)です。
掛けない方式:前#simple-ruby([漢], [かんじ])後。
三分:本文中の#simple-ruby([私], [わたし], third: true)です。
#text(size: 16pt, weight: "bold")[
大見出し:#simple-ruby([組], [くみ], annotation-size: 0.4em)
]
分割禁止:#block(width: 4em, stroke: 0.5pt)[前前前#simple-ruby([市場], [しじょう])後後]
3.3.1 ルビの使用
一部対応 明示した親文字とルビ文字列を関数へ渡し、横組のモノルビとグループルビを分割不能な行内要素として構成できます。ただし、複数の親文字について熟語ルビに必要な親文字ごとの対応を維持する処理、行分割、行調整への参加には対応していません。親文字またはルビ文字列が欧文単語であることに応じて、字間を空けず固有の幅のまま配置する方式を自動で選ぶこともできません。 ルビはAdd support for ruby (CJK, e.g., furigana for Japanese)(typst/typst#1489)で提案されています。
#set page(width: 360pt, height: 400pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 12pt)
#let ruby-gap = 3pt
#let simple-ruby(
base,
annotation,
side: top,
annotation-size: 0.5em,
third: false,
distribute: false,
) = context {
let annotation = text(size: annotation-size, annotation)
let annotation = if third {
scale(x: 66.667%, reflow: true, annotation)
} else {
annotation
}
let base-width = measure(base).width
let annotation-width = measure(annotation).width
let annotation-height = measure(annotation).height
let width = calc.max(base-width, annotation-width)
let fit(body, body-width) = if distribute and body-width < width {
box(width: width)[
#set par(justify: true)
#body#linebreak(justify: true)
]
} else {
body
}
let base = fit(base, base-width)
let annotation = fit(annotation, annotation-width)
let rows = if side == top {
(annotation, base)
} else {
(base, annotation)
}
box(
baseline: (
at: bottom,
shift: if side == top {
0pt
} else {
annotation-height + ruby-gap
},
),
grid(
columns: (width,),
rows: (auto, auto),
align: center,
row-gutter: ruby-gap,
..rows,
),
)
}
#let both-ruby(base, above, below) = context {
let above = text(size: 0.5em, above)
let below = text(size: 0.5em, below)
box(
baseline: (at: bottom, shift: measure(below).height + ruby-gap),
grid(
columns: (auto,),
rows: (auto, auto, auto),
align: center,
row-gutter: ruby-gap,
above,
base,
below,
),
)
}
上側:本文中の#simple-ruby([漢], [かん])です。
下側:本文中の#simple-ruby([語], [ご], side: bottom)です。
両側:本文中の#both-ruby([型], [かた], [type])です。
グループ(同じ長さ):#simple-ruby([市場], [しじょう], distribute: true)です。
グループ(ルビが短い):#simple-ruby([今日], [きょう], distribute: true)です。
グループ(ルビが長い):#simple-ruby([市場], [マーケット], distribute: true)です。
掛けない方式:前#simple-ruby([漢], [かんじ])後。
三分:本文中の#simple-ruby([私], [わたし], third: true)です。
#text(size: 16pt, weight: "bold")[
大見出し:#simple-ruby([組], [くみ], annotation-size: 0.4em)
]
分割禁止:#block(width: 4em, stroke: 0.5pt)[前前前#simple-ruby([市場], [しじょう])後後]
3.3.2 ルビの付け方
評価対象外 すべての対象に付ける総ルビと一部だけに付けるパラルビ、初出とみなす範囲など、ルビを付ける対象の選び方を説明する項目です。
3.3.3 ルビの文字サイズ
一部対応 横組では、二分ルビを親文字の2分の1の文字サイズで配置できます。三分ルビは、2分の1の文字サイズを横方向へ3分の2に縮小し、高さを親文字の2分の1、幅を3分の1にできます。12ポイント以上の見出しなどでは、ルビを親文字の2分の1未満にする指定もできます。縦組の三分ルビには対応していません。 ルビはAdd support for ruby (CJK, e.g., furigana for Japanese)(typst/typst#1489)で提案されています。
#set page(width: 360pt, height: 400pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 12pt)
#let ruby-gap = 3pt
#let simple-ruby(
base,
annotation,
side: top,
annotation-size: 0.5em,
third: false,
distribute: false,
) = context {
let annotation = text(size: annotation-size, annotation)
let annotation = if third {
scale(x: 66.667%, reflow: true, annotation)
} else {
annotation
}
let base-width = measure(base).width
let annotation-width = measure(annotation).width
let annotation-height = measure(annotation).height
let width = calc.max(base-width, annotation-width)
let fit(body, body-width) = if distribute and body-width < width {
box(width: width)[
#set par(justify: true)
#body#linebreak(justify: true)
]
} else {
body
}
let base = fit(base, base-width)
let annotation = fit(annotation, annotation-width)
let rows = if side == top {
(annotation, base)
} else {
(base, annotation)
}
box(
baseline: (
at: bottom,
shift: if side == top {
0pt
} else {
annotation-height + ruby-gap
},
),
grid(
columns: (width,),
rows: (auto, auto),
align: center,
row-gutter: ruby-gap,
..rows,
),
)
}
#let both-ruby(base, above, below) = context {
let above = text(size: 0.5em, above)
let below = text(size: 0.5em, below)
box(
baseline: (at: bottom, shift: measure(below).height + ruby-gap),
grid(
columns: (auto,),
rows: (auto, auto, auto),
align: center,
row-gutter: ruby-gap,
above,
base,
below,
),
)
}
上側:本文中の#simple-ruby([漢], [かん])です。
下側:本文中の#simple-ruby([語], [ご], side: bottom)です。
両側:本文中の#both-ruby([型], [かた], [type])です。
グループ(同じ長さ):#simple-ruby([市場], [しじょう], distribute: true)です。
グループ(ルビが短い):#simple-ruby([今日], [きょう], distribute: true)です。
グループ(ルビが長い):#simple-ruby([市場], [マーケット], distribute: true)です。
掛けない方式:前#simple-ruby([漢], [かんじ])後。
三分:本文中の#simple-ruby([私], [わたし], third: true)です。
#text(size: 16pt, weight: "bold")[
大見出し:#simple-ruby([組], [くみ], annotation-size: 0.4em)
]
分割禁止:#block(width: 4em, stroke: 0.5pt)[前前前#simple-ruby([市場], [しじょう])後後]
3.3.4 親文字のどちら側にルビを付けるか
一部対応 gridの行順を切り替えれば、横組ではルビ文字列を親文字の上側または下側へ配置できます。上側ルビ、親文字、下側ルビを3行にすれば、読みと意味など、異なるルビ文字列を両側へ同時に配置することもできます。縦組の右側・左側への配置には対応していません。 ルビはAdd support for ruby (CJK, e.g., furigana for Japanese)(typst/typst#1489)で提案されています。
#set page(width: 360pt, height: 400pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 12pt)
#let ruby-gap = 3pt
#let simple-ruby(
base,
annotation,
side: top,
annotation-size: 0.5em,
third: false,
distribute: false,
) = context {
let annotation = text(size: annotation-size, annotation)
let annotation = if third {
scale(x: 66.667%, reflow: true, annotation)
} else {
annotation
}
let base-width = measure(base).width
let annotation-width = measure(annotation).width
let annotation-height = measure(annotation).height
let width = calc.max(base-width, annotation-width)
let fit(body, body-width) = if distribute and body-width < width {
box(width: width)[
#set par(justify: true)
#body#linebreak(justify: true)
]
} else {
body
}
let base = fit(base, base-width)
let annotation = fit(annotation, annotation-width)
let rows = if side == top {
(annotation, base)
} else {
(base, annotation)
}
box(
baseline: (
at: bottom,
shift: if side == top {
0pt
} else {
annotation-height + ruby-gap
},
),
grid(
columns: (width,),
rows: (auto, auto),
align: center,
row-gutter: ruby-gap,
..rows,
),
)
}
#let both-ruby(base, above, below) = context {
let above = text(size: 0.5em, above)
let below = text(size: 0.5em, below)
box(
baseline: (at: bottom, shift: measure(below).height + ruby-gap),
grid(
columns: (auto,),
rows: (auto, auto, auto),
align: center,
row-gutter: ruby-gap,
above,
base,
below,
),
)
}
上側:本文中の#simple-ruby([漢], [かん])です。
下側:本文中の#simple-ruby([語], [ご], side: bottom)です。
両側:本文中の#both-ruby([型], [かた], [type])です。
グループ(同じ長さ):#simple-ruby([市場], [しじょう], distribute: true)です。
グループ(ルビが短い):#simple-ruby([今日], [きょう], distribute: true)です。
グループ(ルビが長い):#simple-ruby([市場], [マーケット], distribute: true)です。
掛けない方式:前#simple-ruby([漢], [かんじ])後。
三分:本文中の#simple-ruby([私], [わたし], third: true)です。
#text(size: 16pt, weight: "bold")[
大見出し:#simple-ruby([組], [くみ], annotation-size: 0.4em)
]
分割禁止:#block(width: 4em, stroke: 0.5pt)[前前前#simple-ruby([市場], [しじょう])後後]
3.3.5 モノルビの親文字に対する配置位置
一部対応 横組では、ルビ文字列全体の中央を親文字の中央にそろえ、親文字と一体の分割不能な行内要素として配置できます。ただし、縦組の中付き・肩付き、肩付きを選んだ場合の3字以上のルビ文字列の配置、隣接文字への掛かり、空き量、改行位置の自動調整には対応していません。 ルビはAdd support for ruby (CJK, e.g., furigana for Japanese)(typst/typst#1489)で提案されています。
#set page(width: 360pt, height: 400pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 12pt)
#let ruby-gap = 3pt
#let simple-ruby(
base,
annotation,
side: top,
annotation-size: 0.5em,
third: false,
distribute: false,
) = context {
let annotation = text(size: annotation-size, annotation)
let annotation = if third {
scale(x: 66.667%, reflow: true, annotation)
} else {
annotation
}
let base-width = measure(base).width
let annotation-width = measure(annotation).width
let annotation-height = measure(annotation).height
let width = calc.max(base-width, annotation-width)
let fit(body, body-width) = if distribute and body-width < width {
box(width: width)[
#set par(justify: true)
#body#linebreak(justify: true)
]
} else {
body
}
let base = fit(base, base-width)
let annotation = fit(annotation, annotation-width)
let rows = if side == top {
(annotation, base)
} else {
(base, annotation)
}
box(
baseline: (
at: bottom,
shift: if side == top {
0pt
} else {
annotation-height + ruby-gap
},
),
grid(
columns: (width,),
rows: (auto, auto),
align: center,
row-gutter: ruby-gap,
..rows,
),
)
}
#let both-ruby(base, above, below) = context {
let above = text(size: 0.5em, above)
let below = text(size: 0.5em, below)
box(
baseline: (at: bottom, shift: measure(below).height + ruby-gap),
grid(
columns: (auto,),
rows: (auto, auto, auto),
align: center,
row-gutter: ruby-gap,
above,
base,
below,
),
)
}
上側:本文中の#simple-ruby([漢], [かん])です。
下側:本文中の#simple-ruby([語], [ご], side: bottom)です。
両側:本文中の#both-ruby([型], [かた], [type])です。
グループ(同じ長さ):#simple-ruby([市場], [しじょう], distribute: true)です。
グループ(ルビが短い):#simple-ruby([今日], [きょう], distribute: true)です。
グループ(ルビが長い):#simple-ruby([市場], [マーケット], distribute: true)です。
掛けない方式:前#simple-ruby([漢], [かんじ])後。
三分:本文中の#simple-ruby([私], [わたし], third: true)です。
#text(size: 16pt, weight: "bold")[
大見出し:#simple-ruby([組], [くみ], annotation-size: 0.4em)
]
分割禁止:#block(width: 4em, stroke: 0.5pt)[前前前#simple-ruby([市場], [しじょう])後後]
3.3.6 グループルビの親文字に対する配置位置
一部対応 横組では、親文字列とルビ文字列の組版上の長さが等しい場合に、両者をベタ組にして中央をそろえ、一つの分割不能な行内要素として配置できます。長さが異なり、短い側が2字以上の漢字・仮名など、Typstが行調整の対象とするCJK文字列の場合は、measureで求めた長い側の幅に合わせ、短い側だけを強制両端揃えにする方式も構成できます。ただし、短い側が1字の場合、短い側が欧文単語の場合に内容を自動判別して字間を空けず固有の字幅のまま位置を調整する処理、字間と前後の空きを2対1にする方式、空き量の上限、隣接文字への掛かり、縦組は処理できません。 ルビはAdd support for ruby (CJK, e.g., furigana for Japanese)(typst/typst#1489)で提案されています。
#set page(width: 360pt, height: 400pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 12pt)
#let ruby-gap = 3pt
#let simple-ruby(
base,
annotation,
side: top,
annotation-size: 0.5em,
third: false,
distribute: false,
) = context {
let annotation = text(size: annotation-size, annotation)
let annotation = if third {
scale(x: 66.667%, reflow: true, annotation)
} else {
annotation
}
let base-width = measure(base).width
let annotation-width = measure(annotation).width
let annotation-height = measure(annotation).height
let width = calc.max(base-width, annotation-width)
let fit(body, body-width) = if distribute and body-width < width {
box(width: width)[
#set par(justify: true)
#body#linebreak(justify: true)
]
} else {
body
}
let base = fit(base, base-width)
let annotation = fit(annotation, annotation-width)
let rows = if side == top {
(annotation, base)
} else {
(base, annotation)
}
box(
baseline: (
at: bottom,
shift: if side == top {
0pt
} else {
annotation-height + ruby-gap
},
),
grid(
columns: (width,),
rows: (auto, auto),
align: center,
row-gutter: ruby-gap,
..rows,
),
)
}
#let both-ruby(base, above, below) = context {
let above = text(size: 0.5em, above)
let below = text(size: 0.5em, below)
box(
baseline: (at: bottom, shift: measure(below).height + ruby-gap),
grid(
columns: (auto,),
rows: (auto, auto, auto),
align: center,
row-gutter: ruby-gap,
above,
base,
below,
),
)
}
上側:本文中の#simple-ruby([漢], [かん])です。
下側:本文中の#simple-ruby([語], [ご], side: bottom)です。
両側:本文中の#both-ruby([型], [かた], [type])です。
グループ(同じ長さ):#simple-ruby([市場], [しじょう], distribute: true)です。
グループ(ルビが短い):#simple-ruby([今日], [きょう], distribute: true)です。
グループ(ルビが長い):#simple-ruby([市場], [マーケット], distribute: true)です。
掛けない方式:前#simple-ruby([漢], [かんじ])後。
三分:本文中の#simple-ruby([私], [わたし], third: true)です。
#text(size: 16pt, weight: "bold")[
大見出し:#simple-ruby([組], [くみ], annotation-size: 0.4em)
]
分割禁止:#block(width: 4em, stroke: 0.5pt)[前前前#simple-ruby([市場], [しじょう])後後]
3.3.7 熟語ルビの親文字に対する配置位置
未対応 熟語単位と文字単位の対応を保ちながら、熟語内と前後の文字へのルビの掛かり、親文字の字間、改行位置をまとめて調整する処理はありません。 ルビはAdd support for ruby (CJK, e.g., furigana for Japanese)(typst/typst#1489)で提案されています。
3.3.8 ルビが親文字よりはみ出した場合の処理
一部対応 横組では、ルビが親文字より短い場合に親文字の前後をベタ組にできます。ルビが長い場合は、ルビ幅を行内に確保したboxに親文字を中央配置し、隣接する漢字、平仮名、片仮名のいずれにもルビを掛けない方式を構成できます。ただし、文字クラスごとの掛かり量、隣接するルビとの衝突、約物の空きとの連動、行頭・行末に応じた配置方式の切替、熟語ルビの親文字単位での分割と再配置には対応していません。 ルビはAdd support for ruby (CJK, e.g., furigana for Japanese)(typst/typst#1489)で提案されています。
#set page(width: 360pt, height: 400pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 12pt)
#let ruby-gap = 3pt
#let simple-ruby(
base,
annotation,
side: top,
annotation-size: 0.5em,
third: false,
distribute: false,
) = context {
let annotation = text(size: annotation-size, annotation)
let annotation = if third {
scale(x: 66.667%, reflow: true, annotation)
} else {
annotation
}
let base-width = measure(base).width
let annotation-width = measure(annotation).width
let annotation-height = measure(annotation).height
let width = calc.max(base-width, annotation-width)
let fit(body, body-width) = if distribute and body-width < width {
box(width: width)[
#set par(justify: true)
#body#linebreak(justify: true)
]
} else {
body
}
let base = fit(base, base-width)
let annotation = fit(annotation, annotation-width)
let rows = if side == top {
(annotation, base)
} else {
(base, annotation)
}
box(
baseline: (
at: bottom,
shift: if side == top {
0pt
} else {
annotation-height + ruby-gap
},
),
grid(
columns: (width,),
rows: (auto, auto),
align: center,
row-gutter: ruby-gap,
..rows,
),
)
}
#let both-ruby(base, above, below) = context {
let above = text(size: 0.5em, above)
let below = text(size: 0.5em, below)
box(
baseline: (at: bottom, shift: measure(below).height + ruby-gap),
grid(
columns: (auto,),
rows: (auto, auto, auto),
align: center,
row-gutter: ruby-gap,
above,
base,
below,
),
)
}
上側:本文中の#simple-ruby([漢], [かん])です。
下側:本文中の#simple-ruby([語], [ご], side: bottom)です。
両側:本文中の#both-ruby([型], [かた], [type])です。
グループ(同じ長さ):#simple-ruby([市場], [しじょう], distribute: true)です。
グループ(ルビが短い):#simple-ruby([今日], [きょう], distribute: true)です。
グループ(ルビが長い):#simple-ruby([市場], [マーケット], distribute: true)です。
掛けない方式:前#simple-ruby([漢], [かんじ])後。
三分:本文中の#simple-ruby([私], [わたし], third: true)です。
#text(size: 16pt, weight: "bold")[
大見出し:#simple-ruby([組], [くみ], annotation-size: 0.4em)
]
分割禁止:#block(width: 4em, stroke: 0.5pt)[前前前#simple-ruby([市場], [しじょう])後後]
3.3.9 圏点の処理
未対応 圏点を各親文字に対応付け、句読点や括弧を除外し、段落の改行後も対応を保って配置する機能はありません。 ルビはAdd support for ruby (CJK, e.g., furigana for Japanese)(typst/typst#1489)で提案されています。
3.4 割注処理
一部対応 横組では、割注文字のサイズと、その2倍の括弧、二つの割注行の行間0を指定し、全体を分割不能な行内要素として配置できます。本文のtext.top-edgeとtext.bottom-edgeを基線に対して対称にした上で、box.baselineにより割注全体の中心を本文行の中心へそろえることもできます。ただし、内容から分割位置を決めて二行の長さをそろえる処理、本文の複数行にまたがる分割・再配置、縦組には対応していません。 割注はAdvanced East-Asian layout features(typst/typst#193)で追跡されています。
#set page(width: 300pt, height: 145pt, margin: 14pt)
#set text(
font: "Noto Serif CJK JP",
lang: "ja",
size: 12pt,
top-edge: .5em,
bottom-edge: -.5em,
)
#let warichu(upper, lower, size: 6pt, delimiters: true, gap: 0.5em) = box(
baseline: horizon,
grid(
columns: (auto, auto, auto),
align: horizon,
if delimiters { text(size: size * 2, lang: "ja", [(]) } else { h(gap) },
grid(
columns: (auto,),
rows: (auto, auto),
row-gutter: 0pt,
text(size: size, lang: "ja", upper),
text(size: size, lang: "ja", lower),
),
if delimiters { text(size: size * 2, lang: "ja", [)]) } else { h(gap) },
),
)
括弧付き:本文中に#warichu([用語(上段)], [説明、下段。])割注を配置します。
括弧なし:本文中に#warichu([用語について], [説明を加える], delimiters: false)割注を配置します。
3.4.1 割注の利用
評価対象外 割注を使用する場面を説明する項目であり、組版処理の要件は含みません。
3.4.2 割注の文字サイズと行間など
一部対応 横組では、割注文字のサイズを指定し、その2倍の括弧で囲み、あらかじめ分けた二つの割注行を行間0で配置できます。括弧を使わず、前後に指定量の空きを置く形式も構成できます。割注内の約物には本文と同じ組み込み規則を適用でき、本文のtext.top-edgeとtext.bottom-edgeを基線に対して対称にした上で、box.baselineにより割注全体の中心を本文行の中心へそろえられます。ただし、分割可能位置のうち全体の中央に最も近い位置を選ぶ処理、二行目を一行目以下の長さにする保証、欧文、比例幅文字、禁則を含む内容の均衡、縦組には対応していません。 割注はAdvanced East-Asian layout features(typst/typst#193)で追跡されています。
#set page(width: 300pt, height: 145pt, margin: 14pt)
#set text(
font: "Noto Serif CJK JP",
lang: "ja",
size: 12pt,
top-edge: .5em,
bottom-edge: -.5em,
)
#let warichu(upper, lower, size: 6pt, delimiters: true, gap: 0.5em) = box(
baseline: horizon,
grid(
columns: (auto, auto, auto),
align: horizon,
if delimiters { text(size: size * 2, lang: "ja", [(]) } else { h(gap) },
grid(
columns: (auto,),
rows: (auto, auto),
row-gutter: 0pt,
text(size: size, lang: "ja", upper),
text(size: size, lang: "ja", lower),
),
if delimiters { text(size: size * 2, lang: "ja", [)]) } else { h(gap) },
),
)
括弧付き:本文中に#warichu([用語(上段)], [説明、下段。])割注を配置します。
括弧なし:本文中に#warichu([用語について], [説明を加える], delimiters: false)割注を配置します。
3.4.3 割注を本文の2行以上にわたって配置する処理
未対応 割注を本文の改行に合わせて分割・再配置する機能はありません。 割注はAdvanced East-Asian layout features(typst/typst#193)で追跡されています。
3.5 段落整形,そろえ及び段落末尾処理
一部対応 parとalignで字下げと、行頭・中央・行末へのそろえを指定できます。指定幅のbox内を両端揃えにすれば、CJK文字列の均等割りも構成できます。ただし、JLReqの文字クラスに基づいて空ける箇所を選ぶ処理には対応していません。
#set page(width: 260pt, height: 155pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 8pt)
#grid(
columns: (1fr, 1fr),
gutter: 14pt,
[
#set par(first-line-indent: (amount: 1em, all: false), spacing: 4pt)
#block[*all: false*]
見出し直後の段落です。
連続する段落です。
],
[
#set par(first-line-indent: (amount: 1em, all: true), spacing: 4pt)
#block[*all: true*]
見出し直後の段落です。
連続する段落です。
],
)
*2行目以下の字下げ*
#pad(left: 2em)[
#block(width: 20em, stroke: .5pt)[
#par(
hanging-indent: 2em,
)[Q 段落が2行以上になる場合は、2行目以下の行頭を字下げします。]
]
]
#set page(width: 150pt, height: 100pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 8pt)
#block(
width: 12em,
inset: (left: 1em, right: 2em),
stroke: .5pt,
)[行頭側を一字、行末側を二字分だけ狭めます。]
#set page(width: 260pt, height: 175pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 8pt)
#let even(width, body) = box(width: width, stroke: .5pt)[
#set par(justify: true)
#body#linebreak(justify: true)
]
#grid(
columns: (1fr, 1fr),
gutter: 18pt,
row-gutter: 12pt,
[
*行頭*
#block(width: 9em, stroke: .5pt, align(left)[文字])
],
[
*中央*
#block(width: 9em, stroke: .5pt, align(center)[文字])
],
[
*行末*
#block(width: 9em, stroke: .5pt, align(right)[文字])
],
[
*均等割り*
#even(9em)[漢字かなカナ]
],
)
3.5.1 段落先頭行の字下げ
一部対応 par.first-line-indentで字下げ量を指定できます。Typst 0.13.0以降は、allで先頭・見出し直後を含む全段落か、連続する段落だけかを選べます(Support first-line-indent for every paragraph(typst/typst#5768))。par.hanging-indentを使えば、箇条書きや問答形式で2行目以下を字下げできます。ただし、会話や別行数式を受ける段落だけを自動判別して天付きにする処理はありません。全角字下げした段落が始め括弧類で始まる場合の配置もJLReq 3.1.5に一致しません。 段落字下げと行頭括弧の組合せはCJK brackets at the beginning of paragraph(typst/typst#4011)で追跡されています。
#set page(width: 260pt, height: 155pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 8pt)
#grid(
columns: (1fr, 1fr),
gutter: 14pt,
[
#set par(first-line-indent: (amount: 1em, all: false), spacing: 4pt)
#block[*all: false*]
見出し直後の段落です。
連続する段落です。
],
[
#set par(first-line-indent: (amount: 1em, all: true), spacing: 4pt)
#block[*all: true*]
見出し直後の段落です。
連続する段落です。
],
)
*2行目以下の字下げ*
#pad(left: 2em)[
#block(width: 20em, stroke: .5pt)[
#par(
hanging-indent: 2em,
)[Q 段落が2行以上になる場合は、2行目以下の行頭を字下げします。]
]
]
3.5.2 字下げと字上げ
一部対応 横組ではpadやブロックの幅を使い、引用などの全行を行頭側・行末側から固定量だけ狭められます。縦組では同じ処理を構成できません。
#set page(width: 150pt, height: 100pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 8pt)
#block(
width: 12em,
inset: (left: 1em, right: 2em),
stroke: .5pt,
)[行頭側を一字、行末側を二字分だけ狭めます。]
3.5.3 そろえの処理
一部対応 alignで行頭、中央、行末へ揃えられます。指定幅のbox内を両端揃えにすれば、CJK文字列の字間を均等に広げて両端をそろえることもできます。ただし、JLReqの文字クラスに基づく空け禁止箇所を除外して配分する機能はありません。
#set page(width: 260pt, height: 175pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 8pt)
#let even(width, body) = box(width: width, stroke: .5pt)[
#set par(justify: true)
#body#linebreak(justify: true)
]
#grid(
columns: (1fr, 1fr),
gutter: 18pt,
row-gutter: 12pt,
[
*行頭*
#block(width: 9em, stroke: .5pt, align(left)[文字])
],
[
*中央*
#block(width: 9em, stroke: .5pt, align(center)[文字])
],
[
*行末*
#block(width: 9em, stroke: .5pt, align(right)[文字])
],
[
*均等割り*
#even(9em)[漢字かなカナ]
],
)
3.5.4 段落末尾処理
一部対応 最適化改行では、段落末尾の行が分割できない一つのまとまりだけになる候補にペナルティーが付きます。この処理はTypst 0.8.0で導入され(Penalize runts(typst/typst#1858))、0.12.0以降はtext.costs.runtでペナルティーの大きさを指定できます(Various text layout config improvements(typst/typst#3787))。日本語では1字だけの末尾行も対象になります。ただし、末尾行の最小文字数を指定する機能ではなく、改ページ直前のページに残る文字数も個別には判定しません。 日本語の段落末尾を1字にしない処理はTypst wish list for a Japanese user(Typst Forum)でも議論されています。
#set page(width: 230pt, height: 125pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 9pt)
#set par(justify: true)
#grid(
columns: (1fr, 1fr),
gutter: 18pt,
[
*runt: 0%*
#set text(costs: (runt: 0%))
#block(width: 7em, stroke: .5pt)[あいうえおかきくけこさしすせそ]
],
[
*runt: 1000%*
#set text(costs: (runt: 1000%))
#block(width: 7em, stroke: .5pt)[あいうえおかきくけこさしすせそ]
],
)
3.6 タブ処理
一部対応 あらかじめ定めた位置へ各欄の内容を配置する関数を定義できます。ただし、通常の段落内にあるタブ記号を検出し、後続の文字列へタブ位置とタブ種を順番に適用する処理はありません。 タブストップはHow to implement tab stops?(Typst Forum)でも議論されています。
#set page(width: 190pt, height: 80pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 8pt)
#let tab-line(fields) = grid(
columns: (5em, 5em, 5em),
align: (left, center, right),
stroke: 0.25pt + luma(80%),
inset: 2pt,
..fields,
)
#tab-line(([左揃え], [中央揃え], [右揃え]))
3.6.1 タブ処理の利用
一部対応 あらかじめ定めた位置へ各欄の内容を配置する関数を定義できます。ただし、通常の段落内にあるタブ記号と直後の文字列を順番に対応させる処理はありません。 タブストップはHow to implement tab stops?(Typst Forum)でも議論されています。
#set page(width: 190pt, height: 80pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 8pt)
#let tab-line(fields) = grid(
columns: (5em, 5em, 5em),
align: (left, center, right),
stroke: 0.25pt + luma(80%),
inset: 2pt,
..fields,
)
#tab-line(([左揃え], [中央揃え], [右揃え]))
3.6.2 タブ処理で指定する配置位置にそろえる形式
一部対応 alignを組み合わせれば、固定した位置を基準に左揃え、右揃え、中央揃えで配置できます。内容中の指定文字を検出し、その位置をタブ位置へ揃える処理はありません。 タブストップはHow to implement tab stops?(Typst Forum)で、小数点位置に揃える表の関数はYou should level up your data tables!(Typst Forum)で扱われています。
#set page(width: 190pt, height: 80pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 8pt)
#let tab-line(fields) = grid(
columns: (5em, 5em, 5em),
align: (left, center, right),
stroke: 0.25pt + luma(80%),
inset: 2pt,
..fields,
)
#tab-line(([左揃え], [中央揃え], [右揃え]))
3.6.3 タブ処理を行う対象の文字列の配置方法
一部対応 各欄が指定幅に収まる場合は、固定した位置へ順番に配置できます。文字列が次のタブ位置を越えた場合に後続文字列をさらに次の位置へ送る処理、前の文字列と重なる場合にその直後へ置く処理、対応する位置がない場合に次行へ送る処理には対応していません。 タブストップはHow to implement tab stops?(Typst Forum)でも議論されています。
#set page(width: 190pt, height: 80pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 8pt)
#let tab-line(fields) = grid(
columns: (5em, 5em, 5em),
align: (left, center, right),
stroke: 0.25pt + luma(80%),
inset: 2pt,
..fields,
)
#tab-line(([左揃え], [中央揃え], [右揃え]))
3.7 その他の行組版処理
一部対応 横組の添え字、振分け、字取り、別行数式の中央配置には対応しています。親文字と添え字はboxで一体の行内要素にでき、等号類と演算記号も全角幅の中央へ配置できます。ただし、字取りの空きの配分規則、記号周囲の空きの自動選択、JLReqの優先順位に従う数式の分割には対応していません。
#set page(width: 220pt, height: 125pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 8pt)
#let attached(base, script) = box[#base#script]
#grid(
columns: (1fr, 1fr),
gutter: 14pt,
[
*通常*
#block(width: 6em, stroke: .5pt)[日日日日日親#super[注]次]
],
[
*box*
#block(width: 6em, stroke: .5pt)[日日日日日#attached([親], super[注])次]
],
)
下付き:#attached([CO], sub[2])
数式:$x^2 + a_1$
#set page(width: 210pt, height: 500pt, margin: 14pt)
#set text(
font: "Noto Serif CJK JP",
lang: "ja",
size: 10pt,
top-edge: .5em,
bottom-edge: -.5em,
)
#let furiwake(width, upper, lower, row-gap: 2pt) = box(
baseline: horizon,
grid(
columns: (width,),
rows: (auto, auto),
align: left,
row-gutter: row-gap,
{
set par(leading: 0pt)
upper
},
{
set par(leading: 0pt)
lower
},
),
)
自動幅:
#furiwake(auto)[短い上段][長い下段]
指定幅での自動折返し:
#furiwake(7em)[短い上段][長い下段を折り返します]
明示改行:
#furiwake(7em)[上段の1行目\ 上段の2行目][下段]
文字・書体・振分け行間:
#text(font: "Noto Sans CJK JP", size: 8pt)[
#furiwake(auto, row-gap: 5pt)[小さい上段][小さい下段]
]
振分けを含む段落の行間:
#[
#set par(leading: 10pt)
前の行です。\
本文中の#furiwake(auto)[上段][下段]です。\
後ろの行です。
]
分割禁止:
#block(width: 4em, stroke: 0.5pt)[前前#furiwake(auto)[上段][下段]後後]
#set page(width: 210pt, height: 150pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 12pt)
#let jidori(width, body) = box(width: width, stroke: .5pt)[
#set par(justify: true)
#body#linebreak(justify: true)
]
*6字取り*
#grid(
columns: (auto, auto),
gutter: 10pt,
row-gutter: 5pt,
[1字], jidori(6em)[章],
[3字], jidori(6em)[第一章],
[6字], jidori(6em)[第一編第一章],
)
#set page(width: 330pt, height: 145pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 14pt)
#let fullwidth(body) = box(width: 1em, stroke: 0.5pt, align(center, body))
*本文* 漢字=漢字 漢字+漢字 漢字−漢字
*全角幅* 漢字#fullwidth[=]漢字 漢字#fullwidth[+]漢字 漢字#fullwidth[−]漢字
*別行数式*
$ A + B = C $
3.7.1 添え字処理
一部対応 super、subと数式モードで横組の上付き・下付き文字を配置できます。親文字と添え字をboxにまとめれば、その内部での改行と、外側の行調整による字間の拡大を防げます。ただし、隣接する文字クラスに応じて、まとまりの外側の空きを自動調整する処理と、縦組での回転・縦中横には対応していません。
#set page(width: 220pt, height: 125pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 8pt)
#let attached(base, script) = box[#base#script]
#grid(
columns: (1fr, 1fr),
gutter: 14pt,
[
*通常*
#block(width: 6em, stroke: .5pt)[日日日日日親#super[注]次]
],
[
*box*
#block(width: 6em, stroke: .5pt)[日日日日日#attached([親], super[注])次]
],
)
下付き:#attached([CO], sub[2])
数式:$x^2 + a_1$
#set page(width: 220pt, height: 180pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 8pt)
#let attached(base, script) = box[#base#script]
*ベタ組*
#block(width: 8em, stroke: .5pt)[始「中」終]
*両端揃え*
#block(width: 8em, stroke: .5pt)[
#set par(justify: true)
始「中」終#linebreak(justify: true)
]
#grid(
columns: (1fr, 1fr),
gutter: 12pt,
[
*通常*
#block(width: 8em, stroke: .5pt)[
#set par(justify: true)
始親#super[注]終#linebreak(justify: true)
]
],
[
*box*
#block(width: 8em, stroke: .5pt)[
#set par(justify: true)
始#attached([親], super[注])終#linebreak(justify: true)
]
],
)
3.7.2 振分け処理
一部対応 gridとboxを使い、上下二段の行頭をそろえ、長い側に全体の幅を合わせ、一体として行内へ配置できます。振分けの文字サイズと書体、異なる振分け行の間隔、振分けを含む段落の行間も指定できます。幅を指定すれば、各段の内容を行間0で折り返し、明示した改行も保てます。本文のtext.top-edgeとtext.bottom-edgeを基線に対して対称にした上で、box.baselineにより振分け全体の中心を本文行の中心へそろえることもできます。ただし、利用可能な行長に応じた幅の決定、括弧の高さの調整、版面外へのはみ出しの回避には対応していません。
#set page(width: 210pt, height: 500pt, margin: 14pt)
#set text(
font: "Noto Serif CJK JP",
lang: "ja",
size: 10pt,
top-edge: .5em,
bottom-edge: -.5em,
)
#let furiwake(width, upper, lower, row-gap: 2pt) = box(
baseline: horizon,
grid(
columns: (width,),
rows: (auto, auto),
align: left,
row-gutter: row-gap,
{
set par(leading: 0pt)
upper
},
{
set par(leading: 0pt)
lower
},
),
)
自動幅:
#furiwake(auto)[短い上段][長い下段]
指定幅での自動折返し:
#furiwake(7em)[短い上段][長い下段を折り返します]
明示改行:
#furiwake(7em)[上段の1行目\ 上段の2行目][下段]
文字・書体・振分け行間:
#text(font: "Noto Sans CJK JP", size: 8pt)[
#furiwake(auto, row-gap: 5pt)[小さい上段][小さい下段]
]
振分けを含む段落の行間:
#[
#set par(leading: 10pt)
前の行です。\
本文中の#furiwake(auto)[上段][下段]です。\
後ろの行です。
]
分割禁止:
#block(width: 4em, stroke: 0.5pt)[前前#furiwake(auto)[上段][下段]後後]
3.7.3 字取り処理
一部対応 指定した字数に相当する幅のbox内を両端揃えにすれば、行中の文字列へ文字間の空きを配分できます。1字だけの場合は行頭に配置されます。ただし、欧文間隔・和字間隔の前後を一つの配分箇所として数える規則には対応していません。括弧を含む場合に、すべての字間へ配分する方式、始め括弧の前と終わり括弧の後だけを配分対象とする方式、括弧の前後をすべて除外する方式を選ぶこともできません。JLReqの文字クラスに基づいて分割禁止箇所を配分対象から除く処理にも対応していません。
#set page(width: 210pt, height: 150pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 12pt)
#let jidori(width, body) = box(width: width, stroke: .5pt)[
#set par(justify: true)
#body#linebreak(justify: true)
]
*6字取り*
#grid(
columns: (auto, auto),
gutter: 10pt,
row-gutter: 5pt,
[1字], jidori(6em)[章],
[3字], jidori(6em)[第一章],
[6字], jidori(6em)[第一編第一章],
)
3.7.4 等号類と演算記号の処理
一部対応 横組では、別行数式を版面または段の左右中央へ配置できます。等号類と演算記号は、boxを使って全角幅の中央へ配置できます。ただし、対象となる記号を自動判別し、周囲の文字クラスと行内・別行の別に応じてベタ組または四分アキを選ぶ処理と、JLReqの優先順位に従う分割位置には対応していません。 インライン数式との境界に和欧文間隔が入らない問題はCJK-Latin-spacing not working with inline equation(typst/typst#2703)で報告されています。
#set page(width: 330pt, height: 145pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 14pt)
#let fullwidth(body) = box(width: 1em, stroke: 0.5pt, align(center, body))
*本文* 漢字=漢字 漢字+漢字 漢字−漢字
*全角幅* 漢字#fullwidth[=]漢字 漢字#fullwidth[+]漢字 漢字#fullwidth[−]漢字
*別行数式*
$ A + B = C $
3.8 行の調整処理
一部対応 両端揃えと組み込みのCJK間隔調整があります。Typst 0.14.0以降はpar.justification-limitsで最初の調整に使う単語間・文字間の伸縮量を指定できます(Support for character-level justification(typst/typst#6161))。この調整だけで行末がそろわない場合は、欧文間隔やCJK文字間の調整可能な箇所に残りの空きを加えます。JLReqが定める上限と優先順位は再現できません。 文字種に応じた改行と約物調整はBetter CJK support(typst/typst#276)で追跡されています。CJK文字間の空きを調整して公称の行長へ合わせる処理はStrict grid for CJK, hopefully via glue(typst/typst#4404)で提案されています。
#set page(width: 250pt, height: 145pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 10pt)
#let phrase = [約物、漢字、かな、Latin textを含む文章を同じ幅で組みます。]
#grid(
columns: (1fr, 1fr),
gutter: 18pt,
[
*左揃え*
#block(width: 8em, stroke: .5pt, inset: 2pt)[
#set par(justify: false)
#phrase
]
],
[
*両端揃え*
#block(width: 8em, stroke: .5pt, inset: 2pt)[
#set par(justify: true)
#phrase
]
],
)
#set page(width: 250pt, height: 125pt, margin: 14pt)
#set text(
font: "Noto Serif CJK JP",
lang: "ja",
size: 12pt,
spacing: 600%,
)
#set par(
justify: true,
justification-limits: (
spacing: (min: 1%, max: 100%),
tracking: (min: 0pt, max: 0pt),
),
)
#let phrase = [AAAA~BBBB~CCCC]
*調整前*
#box(stroke: .5pt)[#phrase]
*欧文間隔を縮小*
#block(width: 9em, stroke: .5pt)[#phrase#linebreak(justify: true)]
#set page(width: 230pt, height: 125pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 10pt)
#let phrase = [漢字とかな]
#grid(
columns: (1fr, 1fr),
gutter: 18pt,
[
#align(left)[*自然幅*]
#box(stroke: .5pt, inset: 2pt)[#phrase]
],
[
#align(left)[*広い行*]
#set par(justify: true)
#set par(justification-limits: (
tracking: (min: 0pt, max: .2em),
))
#block(width: 9em, stroke: .5pt, inset: 2pt)[
#phrase#linebreak(justify: true)
]
],
)
3.8.1 行の調整処理の必要性
一部対応 両端揃えでは段落末尾以外の行頭と行末を揃え、末尾行は行頭側へ揃えられます。ただし、行長の過不足を調整する箇所と空き量はJLReqに一致しません。
#set page(width: 250pt, height: 145pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 10pt)
#let phrase = [約物、漢字、かな、Latin textを含む文章を同じ幅で組みます。]
#grid(
columns: (1fr, 1fr),
gutter: 18pt,
[
*左揃え*
#block(width: 8em, stroke: .5pt, inset: 2pt)[
#set par(justify: false)
#phrase
]
],
[
*両端揃え*
#block(width: 8em, stroke: .5pt, inset: 2pt)[
#set par(justify: true)
#phrase
]
],
)
#set page(width: 250pt, height: 125pt, margin: 14pt)
#set text(
font: "Noto Serif CJK JP",
lang: "ja",
size: 12pt,
spacing: 600%,
)
#set par(
justify: true,
justification-limits: (
spacing: (min: 1%, max: 100%),
tracking: (min: 0pt, max: 0pt),
),
)
#let phrase = [AAAA~BBBB~CCCC]
*調整前*
#box(stroke: .5pt)[#phrase]
*欧文間隔を縮小*
#block(width: 9em, stroke: .5pt)[#phrase#linebreak(justify: true)]
#set page(width: 230pt, height: 125pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 10pt)
#let phrase = [漢字とかな]
#grid(
columns: (1fr, 1fr),
gutter: 18pt,
[
#align(left)[*自然幅*]
#box(stroke: .5pt, inset: 2pt)[#phrase]
],
[
#align(left)[*広い行*]
#set par(justify: true)
#set par(justification-limits: (
tracking: (min: 0pt, max: .2em),
))
#block(width: 9em, stroke: .5pt, inset: 2pt)[
#phrase#linebreak(justify: true)
]
],
)
3.8.2 詰める処理と空ける処理
一部対応 約物間隔と単語間・文字間の空きを調整しますが、対象箇所と調整量はJLReqの附属書B、D、Eに一致せず、句読点のぶら下げ組も選べません。
#set page(width: 250pt, height: 125pt, margin: 14pt)
#set text(
font: "Noto Serif CJK JP",
lang: "ja",
size: 12pt,
spacing: 600%,
)
#set par(
justify: true,
justification-limits: (
spacing: (min: 1%, max: 100%),
tracking: (min: 0pt, max: 0pt),
),
)
#let phrase = [AAAA~BBBB~CCCC]
*調整前*
#box(stroke: .5pt)[#phrase]
*欧文間隔を縮小*
#block(width: 9em, stroke: .5pt)[#phrase#linebreak(justify: true)]
#set page(width: 230pt, height: 125pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 10pt)
#let phrase = [漢字とかな]
#grid(
columns: (1fr, 1fr),
gutter: 18pt,
[
#align(left)[*自然幅*]
#box(stroke: .5pt, inset: 2pt)[#phrase]
],
[
#align(left)[*広い行*]
#set par(justify: true)
#set par(justification-limits: (
tracking: (min: 0pt, max: .2em),
))
#block(width: 9em, stroke: .5pt, inset: 2pt)[
#phrase#linebreak(justify: true)
]
],
)
#set page(width: 220pt, height: 175pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 12pt)
#set par(justify: true)
#let comparison(label, text) = grid(
columns: (3em, auto, 5.4em),
gutter: .6em,
align: horizon,
[#label],
box(stroke: .5pt, inset: 2pt)[#text],
block(width: 5.4em, stroke: .5pt, inset: 2pt)[
#text#linebreak(justify: true)
],
)
#grid(
columns: (3em, auto, 5.4em),
gutter: .6em,
[*組合せ*], [*自然幅*], [*狭い行*],
)
#comparison([中点], [漢字・・漢字])
#comparison([句点], [漢字。・漢字])
#comparison([読点], [漢字、・漢字])
3.8.3 詰める処理の優先順位
一部対応 行長に応じて欧文間隔と約物の空きは圧縮されますが、JLReqが定める対象箇所、縮小量、段階的な優先順位には一致しません。
#set page(width: 250pt, height: 125pt, margin: 14pt)
#set text(
font: "Noto Serif CJK JP",
lang: "ja",
size: 12pt,
spacing: 600%,
)
#set par(
justify: true,
justification-limits: (
spacing: (min: 1%, max: 100%),
tracking: (min: 0pt, max: 0pt),
),
)
#let phrase = [AAAA~BBBB~CCCC]
*調整前*
#box(stroke: .5pt)[#phrase]
*欧文間隔を縮小*
#block(width: 9em, stroke: .5pt)[#phrase#linebreak(justify: true)]
#set page(width: 220pt, height: 175pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 12pt)
#set par(justify: true)
#let comparison(label, text) = grid(
columns: (3em, auto, 5.4em),
gutter: .6em,
align: horizon,
[#label],
box(stroke: .5pt, inset: 2pt)[#text],
block(width: 5.4em, stroke: .5pt, inset: 2pt)[
#text#linebreak(justify: true)
],
)
#grid(
columns: (3em, auto, 5.4em),
gutter: .6em,
[*組合せ*], [*自然幅*], [*狭い行*],
)
#comparison([中点], [漢字・・漢字])
#comparison([句点], [漢字。・漢字])
#comparison([読点], [漢字、・漢字])
3.8.4 空ける処理の優先順位
一部対応 行長に応じて文字間を拡大して両端を揃えられますが、JLReqが定める対象箇所、拡大量、段階的な優先順位には一致しません。
#set page(width: 230pt, height: 125pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 10pt)
#let phrase = [漢字とかな]
#grid(
columns: (1fr, 1fr),
gutter: 18pt,
[
#align(left)[*自然幅*]
#box(stroke: .5pt, inset: 2pt)[#phrase]
],
[
#align(left)[*広い行*]
#set par(justify: true)
#set par(justification-limits: (
tracking: (min: 0pt, max: .2em),
))
#block(width: 9em, stroke: .5pt, inset: 2pt)[
#phrase#linebreak(justify: true)
]
],
)
3.9 文字クラスについて
評価対象外 文字幅、行頭・行末への配置、文字間の空き、分割可否、行調整の可否が文字種ごとに異なることと、それらを文字クラスとして扱う考え方を説明する項目です。
3.9.1 文字・記号により振る舞い方は異なる
評価対象外 文字幅、行頭・行末への配置、文字間の空き、分割可否、行調整の可否が文字種によって異なることを説明する項目です。
3.9.2 文字・記号を振る舞い方により分ける
評価対象外 共通する振る舞いごとに文字をまとめ、文字クラスとして管理する方法を説明する項目です。
3.9.3 各文字クラスの配置方法
一部対応 TypstはUnicode属性と組み込み規則に基づいて文字を配置します。一般的なCJK約物の空きと禁則は処理されますが、JLReqの全クラスについて、空き、分割可否、行調整の対象と優先順位を再現できません。 文字種に応じた改行と約物調整はBetter CJK support(typst/typst#276)で追跡されています。
#set page(width: 160pt, height: 100pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 8pt)
#set par(justify: true)
*約物と和欧文間隔*
#block(
width: 8em,
stroke: .5pt,
)[「括弧」、かなABCの間隔と改行位置を確認します。]
4. 見出し・注・図版・表・段落の配置処理
一部対応 見出し、脚注、図、表、段落の基本要素があり、横組では基本版面の文字サイズや行数、本文幅に基づく配置を構成できます。ただし、縦組と、見開きを一つの領域として扱う配置には対応しておらず、基本版面に応じた配置方式を自動で選ぶこともできません。 縦組に依存する配置はRFC: Vertical Writing Mode(typst/typst#5908)で提案されています。
#set page(width: 160pt, height: 140pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 7pt)
= 見出し
本文#footnote[脚注です。]
#figure(rect(width: 40pt, height: 18pt), caption: [図])
#table(
columns: 2,
[項目], [値],
[A], [1],
)
4.1 見出し処理(改ページ処理も含む)
一部対応 heading、pagebreak、colbreakで基本的な見出しと改ページを構成できます。横組の行取りは、指定した行数に相当する高さを持つblockで構成できます。基本版面の基準線への自動配置と窓見出しには対応していません。
#set page(width: 160pt, height: 135pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 8pt)
#set heading(numbering: "1.")
#show heading.where(level: 3): it => strong(it.body + [。])
#let title-page(kind, body, blank-after: false) = {
pagebreak(to: "odd", weak: true)
align(center + horizon)[#kind:#body]
pagebreak()
if blank-after { pagebreak() }
}
#title-page([中扉], [第一部], blank-after: true)
#title-page([半扉], [第一章])
= 大見出し
== 中見出し
=== 同行見出し
本文を改行せずに続けます。
#set page(
width: 140pt,
height: 110pt,
margin: (inside: 18pt, outside: 10pt, y: 14pt),
binding: right,
columns: 2,
)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 7pt)
第1段の前文です。
== 前文に続く見出し
#colbreak()
第2段
#pagebreak(to: "even")
偶数ページ
#pagebreak(to: "odd")
奇数ページ
#set page(width: 260pt, height: 210pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 8pt)
#set par(leading: 4pt)
#let pitch = 12pt
#let gyodori(lines, body, position: horizon + left) = block(
height: pitch * lines - 4pt,
breakable: false,
sticky: true,
align(position, body),
)
#grid(
columns: (1fr, 1fr),
gutter: 14pt,
[
*中央配置*
#gyodori(3)[#strong[3行取りの見出し]]
],
[
*前1行アキ・下寄せ*
#v(pitch)
#gyodori(3, position: bottom + left)[#strong[指定位置の見出し]]
],
)
#pagebreak()
#grid(
columns: (1fr, 1fr),
gutter: 14pt,
[
*副題を含む見出し*
#gyodori(4)[
#strong[主見出し]
#v(4pt)
#text(size: 5.33pt)[主見出しと分割しない副題]
]
],
[
*折返し見出し*
#gyodori(4)[
#set par(leading: 2pt, hanging-indent: 8pt)
折り返した見出しの2行目を字下げします
]
],
)
*連続する見出し*
#gyodori(3)[#strong[上位見出しは3行取り]]
#gyodori(2)[下位見出しは2行取り]
4.1.1 見出しの種類
一部対応 中扉は奇数ページに置き、続く偶数ページを空白にできます。半扉は奇数ページに置き、次の偶数ページから本文を始められます。別行見出しと同行見出しにも対応しています。ただし、見出しの後ろへ本文を2行または3行回り込ませる窓見出しと、文字クラスに応じて見出し中の約物間隔を切り替える処理には対応していません。
#set page(width: 160pt, height: 135pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 8pt)
#set heading(numbering: "1.")
#show heading.where(level: 3): it => strong(it.body + [。])
#let title-page(kind, body, blank-after: false) = {
pagebreak(to: "odd", weak: true)
align(center + horizon)[#kind:#body]
pagebreak()
if blank-after { pagebreak() }
}
#title-page([中扉], [第一部], blank-after: true)
#title-page([半扉], [第一章])
= 大見出し
== 中見出し
=== 同行見出し
本文を改行せずに続けます。
4.1.2 別行見出しの構成
対応 heading.numbering、見出し本文、showルール、blockを使い、ラベル名、番号、見出し文字列、副題を一つの別行見出しとして構成できます。前後の記号、前後の罫線、囲み罫も指定できます。
#set page(width: 230pt, height: 190pt, margin: 12pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 8pt)
#set heading(numbering: "1")
#let sample(title, subtitle, stroke: none, symbol: none) = {
show heading: it => block(
inset: 4pt,
above: 3pt,
below: 3pt,
stroke: stroke,
)[
#if symbol != none [#symbol ]
第#context counter(heading).display(it.numbering)章 #it.body
#if symbol != none [ #symbol]
#linebreak()
#text(size: 0.8em, weight: "regular")[#subtitle]
]
heading(level: 1)[#title]
}
#sample([囲み罫の見出し], [副題], stroke: .5pt)
#sample(
[前後に罫線を置く見出し],
[副題],
stroke: (top: .5pt, bottom: .5pt),
)
#sample([記号を添える見出し], [副題], symbol: [◆])
4.1.3 見出しにアクセントを付ける
一部対応 書体、文字サイズ、ウェイト、そろえは見出しの階層ごとに指定できます。字下げは基本版面の文字サイズの整数倍で設定でき、2字・3字の短い見出しは指定幅内でアキ組にできます。見出しの前後に罫線や記号を配置し、開始位置を奇数・偶数ページ、次ページ、次段から選ぶこともできます。横組では、指定した行数に相当する高さを持つblockに見出しを配置できます。ただし、基本版面の基準線への配置は自動化されません。縦組の見出しにも対応していません。 基本版面の基準線へ揃える組版はGrid typesetting support(typst/typst#1306)で提案されています。
#set page(width: 230pt, height: 190pt, margin: 12pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 8pt)
#set heading(numbering: "1")
#let sample(title, subtitle, stroke: none, symbol: none) = {
show heading: it => block(
inset: 4pt,
above: 3pt,
below: 3pt,
stroke: stroke,
)[
#if symbol != none [#symbol ]
第#context counter(heading).display(it.numbering)章 #it.body
#if symbol != none [ #symbol]
#linebreak()
#text(size: 0.8em, weight: "regular")[#subtitle]
]
heading(level: 1)[#title]
}
#sample([囲み罫の見出し], [副題], stroke: .5pt)
#sample(
[前後に罫線を置く見出し],
[副題],
stroke: (top: .5pt, bottom: .5pt),
)
#sample([記号を添える見出し], [副題], symbol: [◆])
#set page(width: 280pt, height: 130pt, margin: 14pt)
#let basic-size = 8pt
#set text(font: "Noto Serif CJK JP", lang: "ja", size: basic-size)
#show heading.where(level: 1): set text(
font: "Noto Sans CJK JP",
size: 14pt,
weight: "bold",
)
#show heading.where(level: 1): set align(center)
#show heading.where(level: 2): it => block[
#h(4 * basic-size)#it.body
]
#let akigumi(width, body) = box(width: width, stroke: .5pt)[
#set par(justify: true)
#body#linebreak(justify: true)
]
= 書体と文字サイズを変えた見出し
== 基本版面の文字サイズで4字下げ
短い見出しのアキ組:#akigumi(6em)[序章]
#set page(
width: 140pt,
height: 110pt,
margin: (inside: 18pt, outside: 10pt, y: 14pt),
binding: right,
columns: 2,
)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 7pt)
第1段の前文です。
== 前文に続く見出し
#colbreak()
第2段
#pagebreak(to: "even")
偶数ページ
#pagebreak(to: "odd")
奇数ページ
#set page(width: 260pt, height: 210pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 8pt)
#set par(leading: 4pt)
#let pitch = 12pt
#let gyodori(lines, body, position: horizon + left) = block(
height: pitch * lines - 4pt,
breakable: false,
sticky: true,
align(position, body),
)
#grid(
columns: (1fr, 1fr),
gutter: 14pt,
[
*中央配置*
#gyodori(3)[#strong[3行取りの見出し]]
],
[
*前1行アキ・下寄せ*
#v(pitch)
#gyodori(3, position: bottom + left)[#strong[指定位置の見出し]]
],
)
#pagebreak()
#grid(
columns: (1fr, 1fr),
gutter: 14pt,
[
*副題を含む見出し*
#gyodori(4)[
#strong[主見出し]
#v(4pt)
#text(size: 5.33pt)[主見出しと分割しない副題]
]
],
[
*折返し見出し*
#gyodori(4)[
#set par(leading: 2pt, hanging-indent: 8pt)
折り返した見出しの2行目を字下げします
]
],
)
*連続する見出し*
#gyodori(3)[#strong[上位見出しは3行取り]]
#gyodori(2)[下位見出しは2行取り]
4.1.4 改丁・改ページ・改段処理
一部対応 通常のheadingは前の文章に続けて配置できます。Typst 0.6.0以降は奇数・偶数ページへの送り、改ページ、改段を指定でき、page.bindingで左右綴じと内側・外側の余白を設定できます(Support for inside and outside margins(typst/typst#1308))。ただし、縦組本文のページ・段方向には対応していません。 縦組のページ・段方向はRFC: Vertical Writing Mode(typst/typst#5908)で提案されています。
#set page(
width: 140pt,
height: 110pt,
margin: (inside: 18pt, outside: 10pt, y: 14pt),
binding: right,
columns: 2,
)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 7pt)
第1段の前文です。
== 前文に続く見出し
#colbreak()
第2段
#pagebreak(to: "even")
偶数ページ
#pagebreak(to: "odd")
奇数ページ
4.1.5 改ページ等の直前ページの処理
一部対応 単段組では、見出し前で改ページし、直前ページの残りを空白にできます。多段組では、colbreakにより直前の段の残りを空白にして、見出しを次段から始められます。Typst 0.15.1には、横組の多段組で各段の行数を自動的に揃える機能がありません。縦組の段末調整にも対応していません。 横組の多段組における段均等化はImplement column balancing(typst/typst#8207)で実装されましたが、0.15.1には含まれていません。関連する要望はBalancing the contents of multiple columns to the same vertical space(typst/typst#466)で追跡されています。縦組の段方向はRFC: Vertical Writing Mode(typst/typst#5908)で提案されています。
#set page(width: 170pt, height: 100pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 8pt)
改ページ前の本文です。
#pagebreak()
= 次の見出し
直前ページの残りは空白になります。
#pagebreak()
#set page(columns: 2)
改段前の本文です。
#colbreak()
= 次段の見出し
直前の段の残りは空白になります。
4.1.6 行取りの処理例
一部対応 横組では、本文の文字サイズ、行間、指定した行数から求めた高さをblockに設定し、見出しを基本版面の整数行分の領域へ収められます。領域内の中央または指定位置へ置く方式と、前後を行数単位で空ける方式を構成できます。連続する見出しは階層ごとに行取りを変えられます。副題は主見出しの3分の2程度の文字サイズと二分程度の間隔で、折返し見出しは狭い行間と2行目以下の字下げを指定し、どちらも見出し全体を分割不可かつstickyにできます。ただし、基本版面の基準線へ自動で揃える処理はなく、縦組の行取りにも対応していません。 基本版面の基準線へ揃える組版はGrid typesetting support(typst/typst#1306)で提案されています。
#set page(width: 260pt, height: 210pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 8pt)
#set par(leading: 4pt)
#let pitch = 12pt
#let gyodori(lines, body, position: horizon + left) = block(
height: pitch * lines - 4pt,
breakable: false,
sticky: true,
align(position, body),
)
#grid(
columns: (1fr, 1fr),
gutter: 14pt,
[
*中央配置*
#gyodori(3)[#strong[3行取りの見出し]]
],
[
*前1行アキ・下寄せ*
#v(pitch)
#gyodori(3, position: bottom + left)[#strong[指定位置の見出し]]
],
)
#pagebreak()
#grid(
columns: (1fr, 1fr),
gutter: 14pt,
[
*副題を含む見出し*
#gyodori(4)[
#strong[主見出し]
#v(4pt)
#text(size: 5.33pt)[主見出しと分割しない副題]
]
],
[
*折返し見出し*
#gyodori(4)[
#set par(leading: 2pt, hanging-indent: 8pt)
折り返した見出しの2行目を字下げします
]
],
)
*連続する見出し*
#gyodori(3)[#strong[上位見出しは3行取り]]
#gyodori(2)[下位見出しは2行取り]
4.1.7 行取り処理した見出しがページ末にきた場合の処理
一部対応 固定した高さのblockを分割不可かつstickyにすれば、行取り領域がページ末に収まらない場合に、見出しと直後の本文を次ページへ送れます。ただし、直後の本文に脚注がある場合は見出しだけが前ページに残ることがあります。縦組で偶数ページの末尾だけに適用する処理にも対応していません。 後続本文に脚注がある場合の見出しの孤立はFootnote in text after heading can cause orphan(typst/typst#3582)で報告され、0.15.1より後にPrevent footnote in a non-sticky frame causing preceding sticky frames to become orphaned(typst/typst#8592)で修正されました。基本版面の基準線へ揃える組版はGrid typesetting support(typst/typst#1306)で提案されています。
#set page(width: 130pt, height: 90pt, margin: 12pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 8pt)
#set par(leading: 4pt)
#let gyodori(lines, body) = block(
height: 8pt * lines + 4pt * (lines - 1),
breakable: false,
sticky: true,
align(horizon + left, strong(body)),
)
#show heading: it => gyodori(3, it.body)
前の本文です。#v(18pt)
= 3行取りの見出し
後続する本文です。#footnote[脚注です。]
4.1.8 小見出しの前を1行アキにした場合の処理
一部対応 vを使うと、ページや段の先頭へ移った見出し前の空きを保持できます。weak: trueを指定すると、その空きを先頭で削除できます。ただし、前ページの末尾に空きがあるかを判定して二つの処理を自動で切り替える機能はありません。
#set page(width: 190pt, height: 90pt, margin: 12pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 8pt)
#v(1em)
== 通常の空きを置いた見出し
ページ先頭でも通常の空きは残ります。
#pagebreak()
#v(1em, weak: true)
== 弱い空きを置いた見出し
ページ先頭では弱い空きが消えます。
4.1.9 同行見出しの処理
一部対応 headingをインライン内容へ変換するshowルールを定義し、横組では見出しの書体と文字サイズを指定し、後続する本文との間に基本版面の文字サイズによる全角アキを置けます。縦組の同行見出しには対応していません。 見出しと本文の間に空行を置いても同行見出しにできる仕組みはMechanism to allow blank lines after header syntax without introducing paragraph breaks(typst/typst#8811)で提案されています。字下げと空白の調整はHow to control whitespace before and after run-in headings(Typst Forum)でも議論されています。
#set page(width: 150pt, height: 115pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 8pt)
#show heading.where(level: 3): it => (
text(
size: 0.9em,
weight: "bold",
it.body + [。],
)
+ h(1em)
)
#heading(level: 3)[同行見出し]本文を同じ段落へ続けます。
4.1.10 窓見出しの処理
未対応 本文の先頭数行を見出しの横へ回り込ませ、その後を全幅へ戻す処理と行取り規則はありません。 本文の回り込みはHow to wrap text around an image?(typst/typst Discussion #1069)で議論されています。
4.1.11 段抜きの見出しの処理
一部対応 Typst 0.12.0以降、scope: "parent"のフロートは全段をまたいでページ上端または下端へ配置できます(New flow layout, with multi-column floats(typst/typst#5017))。ただし、見出しの出現位置に応じて本文を折り返し、ページ途中で任意の段数をまたぐ配置や開始段を決める処理はありません。 複数段をまたぐフロートはMulti-column Float Elements (Figures, Tables, Code Blocks, etc.)(typst/typst#553)で提案され、New flow layout, with multi-column floats(typst/typst#5017)で実装されました。
#set page(width: 160pt, height: 110pt, margin: 12pt, columns: 2)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 7pt)
#place(top, scope: "parent", float: true, heading(level: 2)[段抜き見出し])
#place(bottom, scope: "parent", float: true, heading(
level: 2,
)[地の段抜き見出し])
第1段の本文です。
#colbreak()
第2段の本文です。
4.2 注の処理
一部対応 footnoteで横組の脚注を配置できます。横組の後注は、stateを使う関数で合印と本文を対応付け、指定位置にまとめて配置できます。横組の傍注は参照位置と同じ高さへ配置できますが、複数の注の衝突は処理できません。頭注と縦組の注には対応していません。 後注や傍注などの注形式はMore Note Functions(typst/typst#1337)で提案されています。
#set page(width: 150pt, height: 110pt, margin: 16pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 8pt)
本文に脚注を付けます。#footnote[ページ下部へ置かれる脚注です。]
#let page-width = 180pt
#let page-margin = 14pt
#let body-size = 8pt
#let note-size = 7pt
#let note-width = 19 * note-size
#let note-indent = page-width - 2 * page-margin - note-width
#set page(width: page-width, height: 145pt, margin: page-margin)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: body-size)
#let notes = state("endnotes", ())
#let endnote(body) = context {
let number = notes.get().len() + 1
notes.update(items => items + ((number, body),))
super([#number])
}
#let show-endnotes() = context {
pad(left: note-indent)[
#block(width: note-width, above: 5pt, below: 5pt)[
#set text(size: note-size)
#set par(leading: 1pt)
#for (number, body) in notes.get() {
grid(
columns: (auto, 1fr),
column-gutter: note-size,
[#number.], body,
)
v(2pt)
}
]
]
}
*本文*
本文#endnote[第一の後注です。後注が複数行になる場合も、2行目以降の字下げを保ちます。]と、別の本文#endnote[第二の後注です。]です。
*後注*
#show-endnotes()
#set page(width: 300pt, height: 140pt, margin: (
left: 14pt,
right: 128pt,
rest: 14pt,
))
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 9pt)
#let sidenote(title, body, mark: none, indent: 0pt, left: 190pt) = context {
let position = here().position()
box(width: 0pt)[
#place(
dx: left - position.x,
dy: -10pt,
box(width: 96pt, stroke: 0.5pt, inset: 3pt)[
#set text(size: 6pt)
#set par(leading: 3pt, first-line-indent: indent)
#if mark != none { mark + h(3pt) }
#strong(title)#h(6pt)#body
],
)
]
}
番号なしの傍注#sidenote([用語], [番号を付けず、項目名を太字にしています。], indent: 6pt)から、本文を続けます。
#v(30pt)
記号付きの傍注#sidenote([補足], [注文字の15字分を行長にしています。], mark: [*])も配置できます。
4.2.1 注の種類
一部対応 横組の脚注を配置でき、関数を定義すれば横組の後注と傍注も構成できます。注本文には本文と同じ段落設定を適用できます。ただし、頭注、縦組の脚注と傍注、行間注には対応していません。
#set page(width: 150pt, height: 110pt, margin: 16pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 8pt)
本文に脚注を付けます。#footnote[ページ下部へ置かれる脚注です。]
#let page-width = 180pt
#let page-margin = 14pt
#let body-size = 8pt
#let note-size = 7pt
#let note-width = 19 * note-size
#let note-indent = page-width - 2 * page-margin - note-width
#set page(width: page-width, height: 145pt, margin: page-margin)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: body-size)
#let notes = state("endnotes", ())
#let endnote(body) = context {
let number = notes.get().len() + 1
notes.update(items => items + ((number, body),))
super([#number])
}
#let show-endnotes() = context {
pad(left: note-indent)[
#block(width: note-width, above: 5pt, below: 5pt)[
#set text(size: note-size)
#set par(leading: 1pt)
#for (number, body) in notes.get() {
grid(
columns: (auto, 1fr),
column-gutter: note-size,
[#number.], body,
)
v(2pt)
}
]
]
}
*本文*
本文#endnote[第一の後注です。後注が複数行になる場合も、2行目以降の字下げを保ちます。]と、別の本文#endnote[第二の後注です。]です。
*後注*
#show-endnotes()
#set page(width: 300pt, height: 140pt, margin: (
left: 14pt,
right: 128pt,
rest: 14pt,
))
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 9pt)
#let sidenote(title, body, mark: none, indent: 0pt, left: 190pt) = context {
let position = here().position()
box(width: 0pt)[
#place(
dx: left - position.x,
dy: -10pt,
box(width: 96pt, stroke: 0.5pt, inset: 3pt)[
#set text(size: 6pt)
#set par(leading: 3pt, first-line-indent: indent)
#if mark != none { mark + h(3pt) }
#strong(title)#h(6pt)#body
],
)
]
}
番号なしの傍注#sidenote([用語], [番号を付けず、項目名を太字にしています。], indent: 6pt)から、本文を続けます。
#v(30pt)
記号付きの傍注#sidenote([補足], [注文字の15字分を行長にしています。], mark: [*])も配置できます。
4.2.2 注の番号
一部対応 脚注番号は、footnote.numberingでアラビア数字、アステリスクの反復、*・†・‡・¶・§・‖・#の順、末尾に括弧を付ける形式などを構成できます。横組の傍注は番号を付けず、項目名を書体で区別する形式にもできます。ページ単位のリセットは、page.headerでcounter(footnote)を更新して構成できます。章単位では章頭でカウンターを更新でき、見開き単位ではページ番号の奇偶を判定して見開きの先頭でカウンターを更新できます。後注番号はstateを使う関数で生成できます。縦組におけるアラビア数字の縦中横、漢数字の平字配置、番号前後に括弧を付ける形式には対応していません。
#set page(
width: 210pt,
height: 160pt,
margin: 16pt,
header: context counter(footnote).update(()),
)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 8pt)
#set footnote(numbering: "a")
ページ単位、1ページ目#footnote[番号はaです。]
#pagebreak()
ページ単位、2ページ目#footnote[番号は再びaです。]
#pagebreak()
#set page(
header: context {
if calc.even(counter(page).get().first()) {
counter(footnote).update(())
}
},
)
#counter(footnote).update(())
見開き単位、3ページ目#footnote[ここから番号を数えます。]
#pagebreak()
4ページ目#footnote[見開きの最初なのでaです。]
#pagebreak()
5ページ目#footnote[同じ見開きなのでbです。]
#pagebreak()
6ページ目#footnote[次の見開きなのでaに戻ります。] 続く注#footnote[番号はbです。]
#pagebreak()
#set page(header: none)
#counter(footnote).update(())
= 新しい章
章頭で番号を戻します。#footnote[番号はaです。]
#pagebreak()
#counter(footnote).update(())
#set footnote(numbering: n => [#for _ in range(n) { [*] }])
アステリスクの反復#footnote[最初は1個です。]と次の注#footnote[次は2個です。]
#counter(footnote).update(())
#set footnote(numbering: n => ("*", "†", "‡", "¶", "§", "‖", "#").at(n - 1))
記号順の注#footnote[最初はアステリスクです。]と次の注#footnote[次はダガーです。]
#counter(footnote).update(())
#set footnote(numbering: n => [#n)])
末尾に括弧を付けた注#footnote[番号の後ろに括弧を付けます。]
#let page-width = 180pt
#let page-margin = 14pt
#let body-size = 8pt
#let note-size = 7pt
#let note-width = 19 * note-size
#let note-indent = page-width - 2 * page-margin - note-width
#set page(width: page-width, height: 145pt, margin: page-margin)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: body-size)
#let notes = state("endnotes", ())
#let endnote(body) = context {
let number = notes.get().len() + 1
notes.update(items => items + ((number, body),))
super([#number])
}
#let show-endnotes() = context {
pad(left: note-indent)[
#block(width: note-width, above: 5pt, below: 5pt)[
#set text(size: note-size)
#set par(leading: 1pt)
#for (number, body) in notes.get() {
grid(
columns: (auto, 1fr),
column-gutter: note-size,
[#number.], body,
)
v(2pt)
}
]
]
}
*本文*
本文#endnote[第一の後注です。後注が複数行になる場合も、2行目以降の字下げを保ちます。]と、別の本文#endnote[第二の後注です。]です。
*後注*
#show-endnotes()
#set page(width: 300pt, height: 140pt, margin: (
left: 14pt,
right: 128pt,
rest: 14pt,
))
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 9pt)
#let sidenote(title, body, mark: none, indent: 0pt, left: 190pt) = context {
let position = here().position()
box(width: 0pt)[
#place(
dx: left - position.x,
dy: -10pt,
box(width: 96pt, stroke: 0.5pt, inset: 3pt)[
#set text(size: 6pt)
#set par(leading: 3pt, first-line-indent: indent)
#if mark != none { mark + h(3pt) }
#strong(title)#h(6pt)#body
],
)
]
}
番号なしの傍注#sidenote([用語], [番号を付けず、項目名を太字にしています。], indent: 6pt)から、本文を続けます。
#v(30pt)
記号付きの傍注#sidenote([補足], [注文字の15字分を行長にしています。], mark: [*])も配置できます。
4.2.3 合印の処理
一部対応 脚注の合印は自動生成されます。footnote.numberingで番号形式を変更できます。superのsetルールでtypographic: falseを指定すれば、合印の大きさと位置も変更できます。footnoteのshowルールを使えば、本文中の合印だけを置き換えられます。上付きの合印は行送り方向へはみ出しても、段落の行間を変えずに配置できます。既定のfootnoteではCJK文字と合印の間で改行される場合がありますが、親文字とfootnoteを一つのboxにまとめる関数で、両者の間をベタ組にして分割を防げます。横組では、親文字列の上側の行間へ合印を置き、両者の右端をそろえる配置も構成できます。ただし、この方法では親文字列が分割不能になります。親文字列を分割可能に保ったまま、版面・段の端に応じて合印の位置を切り替える処理と、縦組における合印の向きと配置には対応していません。 CJK文字と、専用字形へ置換されない上付き文字または脚注合印の間で改行される問題はWrong linebreak opportunitity before non-typographic superscript(typst/typst#3129)で報告されています。
#set page(width: 240pt, height: 250pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 9pt)
#let noted(base, note) = box[#base#footnote(note)]
#let interlinear-note(base, note) = box[
#place(top + right, dy: -0.4em, footnote(note))
#base
]
既定の合印#footnote[既定の脚注です。]
#[
#set footnote(numbering: "①")
#set super(typographic: false, size: 0.6em, baseline: 0.5em)
#show footnote: set text(fill: maroon)
変更した合印#footnote[合印だけに色が付きます。]
]
#block(width: 6.6em, stroke: 0.5pt, inset: 2pt)[
日日日日日親#footnote[合印が親文字と分かれる場合があります。]次
]
#block(width: 6.6em, stroke: 0.5pt, inset: 2pt)[
日日日日日#noted([親], [親文字と合印を一体にします。])次
]
行間に置く合印:#interlinear-note([対象語], [対象語の上側に置いた合印です。])
#grid(
columns: (1fr, 1fr),
gutter: 10pt,
[
*合印なし*
#set par(leading: 6pt)
1行目です。\
2行目です。
],
[
*上付き合印*
#set par(leading: 6pt)
1行目#super[1]です。\
2行目です。
],
)
4.2.4 縦組又は横組の後注処理
一部対応 stateを使う関数で合印と任意の後注本文を対応付け、指定した位置に後注をまとめて配置できます。後注の文字サイズに応じた行長、字下げ、行間、前後の空きも計算して指定できます。ただし、基本版面や段の末尾へ行を自動で揃える処理には対応しておらず、縦組の後注も組めません。 後注や傍注などの注形式はMore Note Functions(typst/typst#1337)で提案されています。
#let page-width = 180pt
#let page-margin = 14pt
#let body-size = 8pt
#let note-size = 7pt
#let note-width = 19 * note-size
#let note-indent = page-width - 2 * page-margin - note-width
#set page(width: page-width, height: 145pt, margin: page-margin)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: body-size)
#let notes = state("endnotes", ())
#let endnote(body) = context {
let number = notes.get().len() + 1
notes.update(items => items + ((number, body),))
super([#number])
}
#let show-endnotes() = context {
pad(left: note-indent)[
#block(width: note-width, above: 5pt, below: 5pt)[
#set text(size: note-size)
#set par(leading: 1pt)
#for (number, body) in notes.get() {
grid(
columns: (auto, 1fr),
column-gutter: note-size,
[#number.], body,
)
v(2pt)
}
]
]
}
*本文*
本文#endnote[第一の後注です。後注が複数行になる場合も、2行目以降の字下げを保ちます。]と、別の本文#endnote[第二の後注です。]です。
*後注*
#show-endnotes()
4.2.5 横組の脚注処理
一部対応 Typst 0.4.0以降、footnoteは合印と脚注を生成します(Footnotes(typst/typst@1321862cd5))。0.5.0以降は多段組でも、脚注を合印のある段の下部へ配置します(Fix footnote in columns(typst/typst@2b812259c2))。長い脚注は次の段またはページへ分割されます。footnote.entryのsetルールで区切り線、本文との空き、注間、字下げを変更でき、脚注の文字サイズに応じた行長と字下げも計算して指定できます。全段を通したページ下部への配置と、継続を示す記号には対応していません。
#let page-width = 210pt
#let page-margin = 14pt
#let column-gutter = 10pt
#let body-size = 8pt
#let note-size = 7pt
#let column-width = (page-width - 2 * page-margin - column-gutter) / 2
#let note-chars = calc.floor(column-width / note-size)
#let note-width = note-chars * note-size
#let note-indent = column-width - note-width
#set page(width: page-width, height: 130pt, margin: page-margin, columns: 2)
#set columns(gutter: column-gutter)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: body-size)
#show footnote.entry: set text(size: note-size)
#show footnote.entry: set block(width: note-width)
#set footnote.entry(
separator: line(length: 70%, stroke: .8pt),
clearance: .7em,
gap: .8em,
indent: note-indent,
)
第1段の本文です。#footnote[
長い脚注は段の下部から始まり、入りきらない部分が次の段またはページへ送られます。この文章は分割位置を確認できる長さにしています。脚注の区切り線、本文との空き、注間、字下げは設定できます。
続きの部分も同じ脚注として組まれます。段の残りが少ない場合でも、脚注全体を手作業で二つに分ける必要はありません。
]
#colbreak()
第2段の本文です。#footnote[第2段の脚注です。]
4.2.6 縦組の傍注処理
未対応 縦組の本文フローと、参照位置に対応する傍注を行送りに合わせて配置する処理がないため、構成できません。 傍注などの注形式はMore Note Functions(typst/typst#1337)で、縦組はRFC: Vertical Writing Mode(typst/typst#5908)で提案されています。
4.2.7 頭注(縦組)・脚注(縦組)・傍注(横組)の処理
一部対応 横組の傍注は、placeを使って参照位置と同じ高さの欄外へ配置できます。番号・記号を付ける形式と、番号を付けず項目名の書体を変える形式を構成できます。本文より小さい文字、注文字サイズの整数倍で15〜20字程度、場合によっては25字程度の行長、二分または三分程度の行間、本文と同じ高さの注領域、本文との約2字分の空き、先頭行の字下げも指定できます。番号の後を二分アキ、書体を変えた項目名の後を全角アキにすることもできます。ただし、複数の注の衝突を避け、領域からはみ出す注を次ページへ送る処理には対応していません。頭注と縦組の脚注も構成できません。 傍注などの注形式はMore Note Functions(typst/typst#1337)で、縦組はRFC: Vertical Writing Mode(typst/typst#5908)で提案されています。
#set page(width: 300pt, height: 140pt, margin: (
left: 14pt,
right: 128pt,
rest: 14pt,
))
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 9pt)
#let sidenote(title, body, mark: none, indent: 0pt, left: 190pt) = context {
let position = here().position()
box(width: 0pt)[
#place(
dx: left - position.x,
dy: -10pt,
box(width: 96pt, stroke: 0.5pt, inset: 3pt)[
#set text(size: 6pt)
#set par(leading: 3pt, first-line-indent: indent)
#if mark != none { mark + h(3pt) }
#strong(title)#h(6pt)#body
],
)
]
}
番号なしの傍注#sidenote([用語], [番号を付けず、項目名を太字にしています。], indent: 6pt)から、本文を続けます。
#v(30pt)
記号付きの傍注#sidenote([補足], [注文字の15字分を行長にしています。], mark: [*])も配置できます。
4.3 図版の配置処理
一部対応 figureで図版とキャプションを配置できますが、JLReqの版面・見開き・縦組を前提とする条件は自動化されません。
#set page(width: 160pt, height: 120pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 8pt)
#figure(
rect(width: 60pt, height: 24pt, fill: luma(90%)),
caption: [図版のキャプション],
)
4.3.1 図版配置の指定方法
一部対応 figure.placement、align、placeでフロートと固定配置を指定できます。図版、キャプション、注は一つのfigureにまとめられます。キャプションを図版の下へ置き、図番号、本文より小さい文字、別書体、複数行の狭い行間を指定することもできます。ノド・小口、左右ページ、本文の回り込み、参照位置を基準とするJLReqの配置規則は自動化されません。 フロートの順序と配置範囲はHow to prevent figure appearing outside of its section?(Typst Forum)で、本文の回り込みはHow to wrap text around an image?(typst/typst Discussion #1069)で議論されています。
#set page(width: 170pt, height: 180pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 8pt)
#show figure.caption: set text(font: "Noto Sans CJK JP", size: 6pt)
#show figure.caption: set par(leading: 2pt)
#figure(
block(width: 60pt)[
#rect(width: 60pt, height: 20pt, fill: luma(90%))
#text(size: 6pt)[注 図版と同じfigureに含めた注です。]
],
placement: top,
caption: box(width: 60pt)[上端へ置く図版の複数行キャプション],
)
#align(center)[#rect(width: 45pt, height: 14pt, fill: luma(88%))[中央]]
#place(bottom + right)[
#rect(width: 45pt, height: 14pt, fill: luma(82%))[固定位置]
]
本文中の配置です。
4.3.2 図版配置の基本的な考え方
一部対応 図版を参照箇所の直後へ置くことはできます。ただし、同じページに収まらない場合に、参照箇所との前後関係や見開きを考慮して配置先を決める処理はありません。 フロートの順序と配置範囲はHow to prevent figure appearing outside of its section?(Typst Forum)でも議論されています。
#set page(width: 140pt, height: 110pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 8pt)
#ref(<sample-figure>)を参照します。
#figure(
rect(width: 50pt, height: 20pt, fill: luma(90%)),
caption: [参照後の図版],
) <sample-figure>
4.3.3 縦組における図版配置の条件
未対応 縦組の本文フローがないため、縦組における図版配置条件を適用できません。 縦組に応じた図表の方向と配置はRFC: Vertical Writing Mode(typst/typst#5908)で提案されています。
4.3.4 横組における図版配置の条件
一部対応 横組では、図版を説明段落の直後やページ・段の天または地へ配置できます。複数段をまたぐ図版も天または地へ置けます。右側の固定位置も指定できますが、本文を図版の横へ自動的に回り込ませる処理には対応していません。説明段落の直後に入るかどうかに応じて、地または次ページの天を選ぶJLReqの配置方式、図版の前後に本文を1行だけ残さない処理、説明箇所と図版の位置関係に基づく配置先の決定は自動化されません。
#set page(width: 260pt, height: 190pt, margin: 14pt, columns: 2)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 8pt)
#figure(
rect(width: 110pt, height: 18pt, fill: luma(84%))[段抜き],
placement: top,
scope: "parent",
)
この段落で図版の内容を説明します。
#figure(
rect(width: 70pt, height: 20pt, fill: luma(88%))[直後],
caption: [説明段落の直後に置いた図版],
)
#figure(
rect(width: 55pt, height: 18pt, fill: luma(82%))[地],
placement: bottom,
scope: "parent",
caption: [地に指定した図版],
)
図版の後ろに続く本文です。
#pagebreak()
#set page(columns: 1)
*版面の右側*
#block(height: 20pt)[
#place(right)[
#rect(width: 34pt, height: 16pt, fill: luma(80%))[右端]
]
#pad(right: 42pt)[本文側に図版分の領域を空けます。]
]
4.3.5 JIS X 4051における図版配置の基本的な考え方
一部対応 figureで本文中の指定位置を起点とする配置を、placeでページ内の固定位置を構成できます。ただし、JIS X 4051の相対位置指定と絶対位置指定を選び、版面内に収まる部分をa、はみ出す部分をbとしてa ≧ 2bなら同じページ、a < 2bなら次ページへ送る処理はありません。図版を移動した後のアンカー位置、図版の前後に残る本文行数、天・地の空きも配置先の決定には使われません。 図版を本文中、ページ上端、ページ下端へ配置する指定はHow to use something like “here+top+bottom” as figure placement option?(Typst Forum)でも議論されています。
#set page(width: 230pt, height: 145pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 8pt)
#place(top + right)[
#rect(width: 62pt, height: 22pt, fill: luma(82%))[固定位置]
]
*絶対位置の指定*
#v(18pt)
*本文中の指定を起点にする配置*
図版の説明です。
#figure(
rect(width: 50pt, height: 18pt, fill: luma(88%)),
caption: [指定の直後],
)
4.4 表の処理
一部対応 tableで表を組版し、本文中の指定位置やページ内の固定位置へ置いてページ分割できます。著者が列境界を指定すれば、表データを左右に分けて見開きへ配置することもできます。ただし、縦組、見開き全体を一つの領域とする配置、基本版面や参照位置に応じた配置方式の自動選択には対応していません。
#set page(width: 190pt, height: 220pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 8pt)
#let jidori(width, body) = box(width: width)[
#set par(justify: true)
#body#linebreak(justify: true)
]
#context {
let em = measure(box(width: 1em)).width
let rounded-width(contents) = {
let widest = calc.max(..contents.map(it => measure(it).width))
calc.ceil((widest + em) / em) * em
}
let numeric = ([数値], [12.3], [1.2], [4], [3.4], [0], [16.3], [4.6])
let no-rule(x, y) = y == 4
figure(
table(
columns: (
rounded-width(([分類], [2行を結合], [罫線なし], [計])),
rounded-width(([項目], [和文], [欧文])),
rounded-width(numeric),
rounded-width(numeric),
),
inset: (x, y) => (
x: .5em,
y: if no-rule(x, y) { .25em } else { .5em },
),
align: (left, left, right, right),
fill: (x, y) => if y == 0 { luma(92%) },
stroke: (x, y) => if no-rule(x, y) { none } else { .5pt },
table.header(
repeat: true,
table.cell(colspan: 2, align: center)[*#jidori(4em)[項目名]*],
table.cell(colspan: 2, align: center)[
#set par(leading: 0pt)
*数値*\
*(単位)*
],
),
table.cell(colspan: 4, align: center, fill: luma(88%))[*4列を結合*],
table.cell(rowspan: 2, align: center)[*2行を結合*],
table.cell(align: center)[和文],
[12.3],
[1.2],
table.cell(align: center)[欧文],
[4],
[3.4],
table.cell(colspan: 2, align: center)[罫線なし],
[0],
[0],
table.footer(
repeat: true,
table.cell(colspan: 2, align: center)[*計*], [16.3], [4.6],
),
),
caption: text(size: 7pt)[配置と寸法を指定した表],
)
}
#text(size: 6pt)[注 数値列は右揃え。]
#set page(width: 180pt, height: 130pt, margin: 16pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 8pt)
#let cell-stroke(columns, open-left: false, open-right: false) = (x, y) => (
top: .5pt,
bottom: .5pt,
left: if x == 0 and open-left { none } else { .5pt },
right: if x == columns - 1 and open-right { none } else { .5pt },
)
#let spread-table(headers, rows, split: 2) = {
pagebreak(to: "even", weak: true)
table(
columns: split,
stroke: cell-stroke(split, open-right: true),
table.header(..headers.slice(0, split)),
..rows.map(row => row.slice(0, split)).flatten(),
)
pagebreak()
table(
columns: headers.len() - split,
stroke: cell-stroke(headers.len() - split),
table.header(..headers.slice(split)),
..rows.map(row => row.slice(split)).flatten(),
)
}
見開き表は次の偶数ページから始めます。
#spread-table(
([品名], [数量], [単価], [金額]),
(
([用紙], [10], [100], [1000]),
([封筒], [20], [50], [1000]),
([箱], [5], [200], [1000]),
),
)
#set page(width: 150pt, height: 100pt, margin: 12pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 7pt)
#block(above: 6pt, breakable: false, sticky: true)[*表1 分割する表*]
#table(
columns: (1fr, 1fr),
table.header(
repeat: true,
[*項目*], [*値*],
),
[項目1], [1行目],
[項目2], [2行目],
[項目3], [3行目],
[説明],
table.cell(breakable: true)[
セルの1行目です。\
セルの2行目です。\
セルの3行目です。\
セルの4行目です。\
セルの5行目です。\
セルの6行目です。
],
)
4.4.1 表の構成
評価対象外 表、行、列、セルなど、以降の説明で使用する表の構成要素を定義する項目です。
4.4.2 表の全体の組方向
一部対応 横組の表では、左上を原点としてセルを左から右へ、行を上から下へ配置します。行結合されたセルを飛ばして後続のセルを配置することもできます。ただし、右上を原点とする縦組の表と、セル内容の組方向切替には対応していません。 縦組に応じた図表の方向と配置はRFC: Vertical Writing Mode(typst/typst#5908)で提案されています。
#set page(width: 190pt, height: 220pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 8pt)
#let jidori(width, body) = box(width: width)[
#set par(justify: true)
#body#linebreak(justify: true)
]
#context {
let em = measure(box(width: 1em)).width
let rounded-width(contents) = {
let widest = calc.max(..contents.map(it => measure(it).width))
calc.ceil((widest + em) / em) * em
}
let numeric = ([数値], [12.3], [1.2], [4], [3.4], [0], [16.3], [4.6])
let no-rule(x, y) = y == 4
figure(
table(
columns: (
rounded-width(([分類], [2行を結合], [罫線なし], [計])),
rounded-width(([項目], [和文], [欧文])),
rounded-width(numeric),
rounded-width(numeric),
),
inset: (x, y) => (
x: .5em,
y: if no-rule(x, y) { .25em } else { .5em },
),
align: (left, left, right, right),
fill: (x, y) => if y == 0 { luma(92%) },
stroke: (x, y) => if no-rule(x, y) { none } else { .5pt },
table.header(
repeat: true,
table.cell(colspan: 2, align: center)[*#jidori(4em)[項目名]*],
table.cell(colspan: 2, align: center)[
#set par(leading: 0pt)
*数値*\
*(単位)*
],
),
table.cell(colspan: 4, align: center, fill: luma(88%))[*4列を結合*],
table.cell(rowspan: 2, align: center)[*2行を結合*],
table.cell(align: center)[和文],
[12.3],
[1.2],
table.cell(align: center)[欧文],
[4],
[3.4],
table.cell(colspan: 2, align: center)[罫線なし],
[0],
[0],
table.footer(
repeat: true,
table.cell(colspan: 2, align: center)[*計*], [16.3], [4.6],
),
),
caption: text(size: 7pt)[配置と寸法を指定した表],
)
}
#text(size: 6pt)[注 数値列は右揃え。]
4.4.3 表を配置した例
一部対応 横組では、表本文、キャプション、注の文字サイズ、罫線、セル余白、固定列幅、セル結合、セル内容のそろえを指定できます。内容をmeasureで測り、左右の二分アキを加えた列幅を表の文字サイズの整数倍へ切り上げることもできます。同種の列には同じ列幅を指定でき、罫線の有無とセル余白に同じ条件を適用できます。ヘッダーの均等割り、左右中央配置、複数行ヘッダーの行間0も構成できます。ただし、縦組の基本版面に横組の表を配置する処理、セル内容の縦組、小数点位置を検出してそろえる処理には対応していません。
#set page(width: 190pt, height: 220pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 8pt)
#let jidori(width, body) = box(width: width)[
#set par(justify: true)
#body#linebreak(justify: true)
]
#context {
let em = measure(box(width: 1em)).width
let rounded-width(contents) = {
let widest = calc.max(..contents.map(it => measure(it).width))
calc.ceil((widest + em) / em) * em
}
let numeric = ([数値], [12.3], [1.2], [4], [3.4], [0], [16.3], [4.6])
let no-rule(x, y) = y == 4
figure(
table(
columns: (
rounded-width(([分類], [2行を結合], [罫線なし], [計])),
rounded-width(([項目], [和文], [欧文])),
rounded-width(numeric),
rounded-width(numeric),
),
inset: (x, y) => (
x: .5em,
y: if no-rule(x, y) { .25em } else { .5em },
),
align: (left, left, right, right),
fill: (x, y) => if y == 0 { luma(92%) },
stroke: (x, y) => if no-rule(x, y) { none } else { .5pt },
table.header(
repeat: true,
table.cell(colspan: 2, align: center)[*#jidori(4em)[項目名]*],
table.cell(colspan: 2, align: center)[
#set par(leading: 0pt)
*数値*\
*(単位)*
],
),
table.cell(colspan: 4, align: center, fill: luma(88%))[*4列を結合*],
table.cell(rowspan: 2, align: center)[*2行を結合*],
table.cell(align: center)[和文],
[12.3],
[1.2],
table.cell(align: center)[欧文],
[4],
[3.4],
table.cell(colspan: 2, align: center)[罫線なし],
[0],
[0],
table.footer(
repeat: true,
table.cell(colspan: 2, align: center)[*計*], [16.3], [4.6],
),
),
caption: text(size: 7pt)[配置と寸法を指定した表],
)
}
#text(size: 6pt)[注 数値列は右揃え。]
4.4.4 ページへの配置からみた表の種類
一部対応 キャプション、表本体、注を分割不可の一体として扱う方法、本文中の指定位置を起点とするフロート、ページ内の固定位置、ページや段をまたいで分割する表を構成できます。著者が列境界を指定した表を左右に分け、偶数ページから始まる見開きへ配置することもできます。ただし、見開き全体を一つの領域とする配置と、参照位置や版面に応じた配置方式の自動選択には対応していません。
#set page(width: 240pt, height: 190pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 7pt)
#let small-table(label) = table(
columns: 2,
inset: 2pt,
[*項目*], [*値*],
[#label], [1],
)
#figure(
placement: top,
small-table([フロート]),
caption: [本文中の指定位置を起点とする表],
)
本文はフロートを避けて配置されます。
#block(breakable: false)[
*表とキャプションと注を分割しない配置*
#small-table([分割不可])
#text(size: 6pt)[注 この注も同じブロックに含めています。]
]
#place(bottom + right, small-table([固定位置]))
右下の表はページ内の固定位置に配置しています。
#pagebreak()
#set page(columns: 2)
*段間で分割する表*
#table(
columns: 2,
inset: 2pt,
table.header([*項目*], [*値*]),
..range(24).map(n => ([項目#(n + 1)], [#(n + 1)])).flatten(),
)
#set page(width: 180pt, height: 130pt, margin: 16pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 8pt)
#let cell-stroke(columns, open-left: false, open-right: false) = (x, y) => (
top: .5pt,
bottom: .5pt,
left: if x == 0 and open-left { none } else { .5pt },
right: if x == columns - 1 and open-right { none } else { .5pt },
)
#let spread-table(headers, rows, split: 2) = {
pagebreak(to: "even", weak: true)
table(
columns: split,
stroke: cell-stroke(split, open-right: true),
table.header(..headers.slice(0, split)),
..rows.map(row => row.slice(0, split)).flatten(),
)
pagebreak()
table(
columns: headers.len() - split,
stroke: cell-stroke(headers.len() - split),
table.header(..headers.slice(split)),
..rows.map(row => row.slice(split)).flatten(),
)
}
見開き表は次の偶数ページから始めます。
#spread-table(
([品名], [数量], [単価], [金額]),
(
([用紙], [10], [100], [1000]),
([封筒], [20], [50], [1000]),
([箱], [5], [200], [1000]),
),
)
#set page(width: 150pt, height: 100pt, margin: 12pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 7pt)
#block(above: 6pt, breakable: false, sticky: true)[*表1 分割する表*]
#table(
columns: (1fr, 1fr),
table.header(
repeat: true,
[*項目*], [*値*],
),
[項目1], [1行目],
[項目2], [2行目],
[項目3], [3行目],
[説明],
table.cell(breakable: true)[
セルの1行目です。\
セルの2行目です。\
セルの3行目です。\
セルの4行目です。\
セルの5行目です。\
セルの6行目です。
],
)
4.4.5 見開きに配置する表の処理
一部対応 著者が列境界を指定すれば、構造化した表データを左右に分け、偶数ページから始まる連続2ページへ二つの表として配置できます。分割箇所の罫線は左右の表で個別に指定できます。ただし、左右を一つの表として組版する処理、参照位置と版面から配置する見開きを自動選択する処理、表の構造から分割位置を決める処理、縦組の表には対応していません。 見開き出力はProducing page spreads / booklets(typst/typst#187)で提案されていますが、見開き表の配置規則は扱われていません。
#set page(width: 180pt, height: 130pt, margin: 16pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 8pt)
#let cell-stroke(columns, open-left: false, open-right: false) = (x, y) => (
top: .5pt,
bottom: .5pt,
left: if x == 0 and open-left { none } else { .5pt },
right: if x == columns - 1 and open-right { none } else { .5pt },
)
#let spread-table(headers, rows, split: 2) = {
pagebreak(to: "even", weak: true)
table(
columns: split,
stroke: cell-stroke(split, open-right: true),
table.header(..headers.slice(0, split)),
..rows.map(row => row.slice(0, split)).flatten(),
)
pagebreak()
table(
columns: headers.len() - split,
stroke: cell-stroke(headers.len() - split),
table.header(..headers.slice(split)),
..rows.map(row => row.slice(split)).flatten(),
)
}
見開き表は次の偶数ページから始めます。
#spread-table(
([品名], [数量], [単価], [金額]),
(
([用紙], [10], [100], [1000]),
([封筒], [20], [50], [1000]),
([箱], [5], [200], [1000]),
),
)
4.4.6 分割を可とする表の処理
一部対応 表の幅と前の要素との空きを指定し、複数ページにまたがる表を行境界で分割できます。分割不可でstickyなブロックにキャプションを置けば、キャプション内とキャプション直後での分割を防げます。Typst 0.11.0以降、table.headerは分割されず、最初の本体行と同じページに置かれ、行境界で分割された次のページにも反復します(Repeatable Table Headers [More Flexible Tables Pt.5a](typst/typst#3545))。複数行のセルはページ間で分割でき、セル内部の分割が続く各ページにもヘッダーを反復できます。既定の罫線では分割面の両側に罫線が描かれます。ただし、分割面の片側だけを不可視にする処理と、縦組で偶数ページだけヘッダーを反復する処理には対応していません。 表の分割面に描く罫線の設定はConfigurable table/grid repeated border(typst/typst#6072)で提案されています。
#set page(width: 150pt, height: 100pt, margin: 12pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 7pt)
#block(above: 6pt, breakable: false, sticky: true)[*表1 分割する表*]
#table(
columns: (1fr, 1fr),
table.header(
repeat: true,
[*項目*], [*値*],
),
[項目1], [1行目],
[項目2], [2行目],
[項目3], [3行目],
[説明],
table.cell(breakable: true)[
セルの1行目です。\
セルの2行目です。\
セルの3行目です。\
セルの4行目です。\
セルの5行目です。\
セルの6行目です。
],
)
4.5 行・段落などの行送り方向の配置処理
一部対応 横組のブロック間隔は制御できますが、ルビと基本版面を考慮した行送り方向の自動調整はありません。
#set page(width: 220pt, height: 160pt, margin: 14pt)
#set text(
font: "Noto Serif CJK JP",
lang: "ja",
size: 8pt,
top-edge: .5em,
bottom-edge: -.5em,
)
#set par(leading: 4pt)
#let plain = block(width: 6em)[通常です。\通常です。]
#let decorated = block(width: 6em)[下線#underline[付]。\CO#sub[2]。]
#let enlarged = block(width: 6em)[通常#text(size: 14pt)[大]。\通常です。]
#let fixed-line(body) = context {
let size = measure(body)
box(
width: size.width,
height: 0pt,
baseline: bottom,
move(dy: -size.height / 2, body),
)
}
#let fixed = block(
width: 6em,
)[通常#fixed-line(text(size: 14pt)[大])。\通常です。]
#context table(
columns: (auto, auto),
[通常], [#measure(plain).height],
[装飾あり], [#measure(decorated).height],
[大きな文字], [#measure(enlarged).height],
[行位置を固定], [#measure(fixed).height],
)
#grid(
columns: (1fr, 1fr, 1fr, 1fr),
gutter: 6pt,
plain, decorated, enlarged, fixed,
)
#set page(width: 230pt, height: 220pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 8pt)
#grid(
columns: (1fr, 1fr),
gutter: 18pt,
[
*段落どうし*
#v(8pt)
#par(spacing: 8pt)[#highlight(fill: luma(90%))[前:8pt]]
#par(spacing: 12pt)[#highlight(fill: luma(90%))[後:12pt]]
],
[
*段落とblock*
#v(8pt)
#par(spacing: 12pt)[#highlight(fill: luma(90%))[段落:12pt]]
#block(width: 100%, above: 4pt, below: 0pt, fill: luma(90%))[
block:4pt
]
],
)
#v(12pt)
#let line-pitch = 12pt
*加算する空き*
#block(width: 100%, above: 0pt, below: 0pt, fill: luma(90%))[前]
#v(8pt)
#v(12pt)
#block(width: 100%, above: 0pt, below: 0pt, fill: luma(90%))[後]
#v(12pt)
*2行分の空き*
#block(width: 100%, above: 0pt, below: 0pt, fill: luma(90%))[前]
#v(2 * line-pitch)
#block(width: 100%, above: 0pt, below: 0pt, fill: luma(90%))[後]
4.5.1 ルビなどが付いた場合の行間の処理
一部対応 下線と上付き・下付き文字は、指定した行送りを変えずに行内へ配置できます。本文のtext.top-edgeとtext.bottom-edgeを基線に対して対称にした上で、本文より大きい文字や行送り方向へ移動した内容をmeasureで測り、高さ0のbox内でmoveを使って中心を本文行の中心へそろえれば、後続行の位置を変えずに配置できます。ただし、ページや段の先頭・末尾で版面外へはみ出す側を自動で切り替える処理と、文書全体を基本版面の行位置へ自動的に戻す機能には対応していません。 ルビはAdd support for ruby (CJK, e.g., furigana for Japanese)(typst/typst#1489)で提案されています。
#set page(width: 220pt, height: 160pt, margin: 14pt)
#set text(
font: "Noto Serif CJK JP",
lang: "ja",
size: 8pt,
top-edge: .5em,
bottom-edge: -.5em,
)
#set par(leading: 4pt)
#let plain = block(width: 6em)[通常です。\通常です。]
#let decorated = block(width: 6em)[下線#underline[付]。\CO#sub[2]。]
#let enlarged = block(width: 6em)[通常#text(size: 14pt)[大]。\通常です。]
#let fixed-line(body) = context {
let size = measure(body)
box(
width: size.width,
height: 0pt,
baseline: bottom,
move(dy: -size.height / 2, body),
)
}
#let fixed = block(
width: 6em,
)[通常#fixed-line(text(size: 14pt)[大])。\通常です。]
#context table(
columns: (auto, auto),
[通常], [#measure(plain).height],
[装飾あり], [#measure(decorated).height],
[大きな文字], [#measure(enlarged).height],
[行位置を固定], [#measure(fixed).height],
)
#grid(
columns: (1fr, 1fr, 1fr, 1fr),
gutter: 6pt,
plain, decorated, enlarged, fixed,
)
4.5.2 段落間処理
一部対応 Typst 0.12.0以降はpar.spacingで段落間の空きを指定できます(Paragraph spacing property(typst/typst#4390))。ただし、既定値の1.2emは既定の行間0.65emと異なり、段落前と段落後の空きを個別には指定できません。隣接する段落のpar.spacingは大きい方へまとめられ、段落とblockが隣接する場合はblock.aboveまたはblock.belowが優先されます。関数から強いvを前後へ置けば二つの空きを加算でき、基本版面の行送り量から行数単位の空きも計算できます。版面・段の先頭と末尾にかかった場合の処理は自動化されません。 基本版面の基準線へ揃える組版はGrid typesetting support(typst/typst#1306)で提案されています。
#set page(width: 230pt, height: 220pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 8pt)
#grid(
columns: (1fr, 1fr),
gutter: 18pt,
[
*段落どうし*
#v(8pt)
#par(spacing: 8pt)[#highlight(fill: luma(90%))[前:8pt]]
#par(spacing: 12pt)[#highlight(fill: luma(90%))[後:12pt]]
],
[
*段落とblock*
#v(8pt)
#par(spacing: 12pt)[#highlight(fill: luma(90%))[段落:12pt]]
#block(width: 100%, above: 4pt, below: 0pt, fill: luma(90%))[
block:4pt
]
],
)
#v(12pt)
#let line-pitch = 12pt
*加算する空き*
#block(width: 100%, above: 0pt, below: 0pt, fill: luma(90%))[前]
#v(8pt)
#v(12pt)
#block(width: 100%, above: 0pt, below: 0pt, fill: luma(90%))[後]
#v(12pt)
*2行分の空き*
#block(width: 100%, above: 0pt, below: 0pt, fill: luma(90%))[前]
#v(2 * line-pitch)
#block(width: 100%, above: 0pt, below: 0pt, fill: luma(90%))[後]
4.5.3 行送り方向の領域の調整処理
一部対応 blockで固定量の領域を、vでポイントや文字サイズに対する相対量、余白比例の空きを設定できます。v(1fr)を置いた箇所にはページの残りを比率で配分できます。ただし、版面末尾を揃えるために、JLReqが示す候補と優先順位に従って見出し・図表・後注の前後を自動選択し、伸縮限度内で配分する機能はありません。 基準線へ揃える組版はGrid typesetting support(typst/typst#1306)で、自然長と伸縮限度を持つ空きはAdd equivalent to TeX glue stretching (dynamic vertical spacing)(typst/typst#3442)で提案されています。ページの高さに合わせて段落間を自動調整する処理はDynamic between-paragraph spacing for stretching content across the whole page.(typst/typst#6042)で提案されています。
#set page(width: 180pt, height: 120pt, margin: 12pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 8pt)
#let pitch = 12pt
#let item(body) = block(height: 2 * pitch, stroke: .5pt, body)
*固定量*
#item[上の領域]
#v(pitch)
#item[下の領域]
#pagebreak()
*文字サイズに対する相対量*
#item[上の領域]
#v(1em)
#item[下の領域]
#pagebreak()
*残りの高さを配分*
#item[上の領域]
#v(1fr)
#item[下の領域]
A. 文字クラス一覧
評価対象外 JLReqが組版処理の説明に用いる文字クラスの一覧です。Typstの対応状況は3.9節と附属書B〜Eで評価します。
A.1 始め括弧類(cl-01)
評価対象外
A.2 終わり括弧類(cl-02)
評価対象外
A.3 ハイフン類(cl-03)
評価対象外
A.4 区切り約物(cl-04)
評価対象外
A.5 中点類(cl-05)
評価対象外
A.6 句点類(cl-06)
評価対象外
A.7 読点類(cl-07)
評価対象外
A.8 分離禁止文字(cl-08)
評価対象外
A.9 繰返し記号(cl-09)
評価対象外
A.10 長音記号(cl-10)
評価対象外
A.11 小書きの仮名(cl-11)
評価対象外
A.12 前置省略記号(cl-12)
評価対象外
A.13 後置省略記号(cl-13)
評価対象外
A.14 和字間隔(cl-14)
評価対象外
A.15 平仮名(cl-15)
評価対象外
A.16 片仮名(cl-16)
評価対象外
A.17 等号類(cl-17)
評価対象外
A.18 演算記号(cl-18)
評価対象外
A.19 漢字等(漢字以外の例)(cl-19)
評価対象外
A.20 合印中の文字(cl-20)
評価対象外
A.21 親文字群中の文字(添え字付き)(cl-21)
評価対象外
A.22 親文字群中の文字(熟語ルビ以外のルビ付き)(cl-22)
評価対象外
A.23 親文字群中の文字(熟語ルビ付き)(cl-23)
評価対象外
A.24 連数字中の文字(cl-24)
評価対象外
A.25 単位記号中の文字(cl-25)
評価対象外
A.26 欧文間隔(cl-26)
評価対象外
A.27 欧文用文字(cl-27)
評価対象外
A.28 割注始め括弧類(cl-28)
評価対象外
A.29 割注終わり括弧類(cl-29)
評価対象外
A.30 縦中横中の文字(cl-30)
評価対象外
B. 文字間の空き量
一部対応 CJK約物と和欧文間の空きは組み込み規則で調整されますが、表1に含まれるルビ、添え字、割注、縦中横などの文字群を含むすべての組合せには対応していません。 CJKの空きはBetter CJK support(typst/typst#276)とOption to have raw, unchanged, surpriseless, uniform CJK full-width punctuation width(typst/typst#7643)で扱われています。和欧文間の空きとUnicodeの関係はUnicode drafts a report on text(cjk-latin-spacing)(Typst Forum)でも議論されています。
#set page(width: 170pt, height: 120pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 14pt)
#set text(cjk-latin-spacing: auto)
自動:漢字Latin漢字
#set text(cjk-latin-spacing: none)
なし:漢字Latin漢字
#set page(width: 230pt, height: 165pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 10pt)
#let comparison(label, text) = grid(
columns: (3em, auto, 5.4em),
gutter: .6em,
align: horizon,
[#label],
box(stroke: .5pt, inset: 2pt)[#text],
block(width: 5.4em, stroke: .5pt, inset: 2pt)[
#set par(justify: true)
#text#linebreak(justify: true)
],
)
#grid(
columns: (3em, auto, 5.4em),
gutter: .6em,
[], [*自然幅*], [*狭い行*],
)
#comparison([中点], [項目・・項目])
#comparison([括弧], [項目(項目)])
#comparison([句読点], [項目、項目。])
B.1 表1の見方
評価対象外
B.2 注記
一部対応 通常の約物では、組み込み規則により既定の空きの一部が調整されます。通常段落の空白は行頭・行末で除かれ、配置が行中へ変われば通常幅に戻ります。ただし、ルビの掛かり、割注括弧と隣接文字の空き、添え字・縦中横を含む文字群の空きは、表1の文字クラスに沿って自動処理されません。行末の終わり括弧・句読点・中点について二分アキ、四分アキ、ベタ組を選ぶ処理や、句読点と中点が続く場合の空きも指定できません。中点「・」を単位記号として扱う文脈判定、行頭・割注行頭の「々」・長音記号・小書き仮名について文字クラスを切り替える選択、行頭の始め括弧をベタ組または二分アキにする選択にも対応していません。割注行頭・割注行末の欧文間隔を0にし、配置が変われば復元する処理にも対応していません。 約物幅の選択はOption to have raw, unchanged, surpriseless, uniform CJK full-width punctuation width(typst/typst#7643)で、showルールを適用した約物の圧縮はPunctuation compression does not work with #show(typst/typst#5474)で議論されています。
#set page(width: 230pt, height: 165pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 10pt)
#let comparison(label, text) = grid(
columns: (3em, auto, 5.4em),
gutter: .6em,
align: horizon,
[#label],
box(stroke: .5pt, inset: 2pt)[#text],
block(width: 5.4em, stroke: .5pt, inset: 2pt)[
#set par(justify: true)
#text#linebreak(justify: true)
],
)
#grid(
columns: (3em, auto, 5.4em),
gutter: .6em,
[], [*自然幅*], [*狭い行*],
)
#comparison([中点], [項目・・項目])
#comparison([括弧], [項目(項目)])
#comparison([句読点], [項目、項目。])
C. 文字間での分割の可否
一部対応 CJKの行頭・行末禁則は組み込み規則で処理されますが、表2に含まれる合印、添え字、ルビ、割注、縦中横などの文字群を含むすべての組合せには対応していません。 CJKの改行処理はBetter CJK support(typst/typst#276)で追跡されています。
#set page(width: 130pt, height: 100pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 8pt)
#block(width: 6em)[日日日日日(次)]
#block(width: 6em)[日日日日日日。次]
C.1 表2の見方
評価対象外
C.2 注記
一部対応 行頭・行末禁則と一部の分離禁止は組み込み規則で処理されます。基本的な横組ルビ、親文字と添え字、親文字と合印、振分けは、boxを使って分割不能な行内要素として構成できます。ただし、表2が定める親文字群の同一性と境界に応じた分離禁止・改行可否は自動処理されません。既定のfootnoteではCJK文字と合印の境界で分離する場合があります。割注括弧の直後・直前だけを分割禁止にする処理、熟語ルビを親文字単位で分割して再配置する処理、本文の複数行にまたがる割注の再構成、縦中横には対応していません。 CJKの改行処理はBetter CJK support(typst/typst#276)で追跡されています。CJK文字と、専用字形へ置換されない上付き文字または脚注合印の間で改行される問題はWrong linebreak opportunitity before non-typographic superscript(typst/typst#3129)で報告されています。
#set page(width: 135pt, height: 100pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 8pt)
#block(width: 6em)[ああああああ)次]
#block(width: 6em)[ああああああゃ次]
#set page(width: 360pt, height: 400pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 12pt)
#let ruby-gap = 3pt
#let simple-ruby(
base,
annotation,
side: top,
annotation-size: 0.5em,
third: false,
distribute: false,
) = context {
let annotation = text(size: annotation-size, annotation)
let annotation = if third {
scale(x: 66.667%, reflow: true, annotation)
} else {
annotation
}
let base-width = measure(base).width
let annotation-width = measure(annotation).width
let annotation-height = measure(annotation).height
let width = calc.max(base-width, annotation-width)
let fit(body, body-width) = if distribute and body-width < width {
box(width: width)[
#set par(justify: true)
#body#linebreak(justify: true)
]
} else {
body
}
let base = fit(base, base-width)
let annotation = fit(annotation, annotation-width)
let rows = if side == top {
(annotation, base)
} else {
(base, annotation)
}
box(
baseline: (
at: bottom,
shift: if side == top {
0pt
} else {
annotation-height + ruby-gap
},
),
grid(
columns: (width,),
rows: (auto, auto),
align: center,
row-gutter: ruby-gap,
..rows,
),
)
}
#let both-ruby(base, above, below) = context {
let above = text(size: 0.5em, above)
let below = text(size: 0.5em, below)
box(
baseline: (at: bottom, shift: measure(below).height + ruby-gap),
grid(
columns: (auto,),
rows: (auto, auto, auto),
align: center,
row-gutter: ruby-gap,
above,
base,
below,
),
)
}
上側:本文中の#simple-ruby([漢], [かん])です。
下側:本文中の#simple-ruby([語], [ご], side: bottom)です。
両側:本文中の#both-ruby([型], [かた], [type])です。
グループ(同じ長さ):#simple-ruby([市場], [しじょう], distribute: true)です。
グループ(ルビが短い):#simple-ruby([今日], [きょう], distribute: true)です。
グループ(ルビが長い):#simple-ruby([市場], [マーケット], distribute: true)です。
掛けない方式:前#simple-ruby([漢], [かんじ])後。
三分:本文中の#simple-ruby([私], [わたし], third: true)です。
#text(size: 16pt, weight: "bold")[
大見出し:#simple-ruby([組], [くみ], annotation-size: 0.4em)
]
分割禁止:#block(width: 4em, stroke: 0.5pt)[前前前#simple-ruby([市場], [しじょう])後後]
#set page(width: 220pt, height: 125pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 8pt)
#let attached(base, script) = box[#base#script]
#grid(
columns: (1fr, 1fr),
gutter: 14pt,
[
*通常*
#block(width: 6em, stroke: .5pt)[日日日日日親#super[注]次]
],
[
*box*
#block(width: 6em, stroke: .5pt)[日日日日日#attached([親], super[注])次]
],
)
下付き:#attached([CO], sub[2])
数式:$x^2 + a_1$
#set page(width: 210pt, height: 500pt, margin: 14pt)
#set text(
font: "Noto Serif CJK JP",
lang: "ja",
size: 10pt,
top-edge: .5em,
bottom-edge: -.5em,
)
#let furiwake(width, upper, lower, row-gap: 2pt) = box(
baseline: horizon,
grid(
columns: (width,),
rows: (auto, auto),
align: left,
row-gutter: row-gap,
{
set par(leading: 0pt)
upper
},
{
set par(leading: 0pt)
lower
},
),
)
自動幅:
#furiwake(auto)[短い上段][長い下段]
指定幅での自動折返し:
#furiwake(7em)[短い上段][長い下段を折り返します]
明示改行:
#furiwake(7em)[上段の1行目\ 上段の2行目][下段]
文字・書体・振分け行間:
#text(font: "Noto Sans CJK JP", size: 8pt)[
#furiwake(auto, row-gap: 5pt)[小さい上段][小さい下段]
]
振分けを含む段落の行間:
#[
#set par(leading: 10pt)
前の行です。\
本文中の#furiwake(auto)[上段][下段]です。\
後ろの行です。
]
分割禁止:
#block(width: 4em, stroke: 0.5pt)[前前#furiwake(auto)[上段][下段]後後]
#set page(width: 240pt, height: 250pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 9pt)
#let noted(base, note) = box[#base#footnote(note)]
#let interlinear-note(base, note) = box[
#place(top + right, dy: -0.4em, footnote(note))
#base
]
既定の合印#footnote[既定の脚注です。]
#[
#set footnote(numbering: "①")
#set super(typographic: false, size: 0.6em, baseline: 0.5em)
#show footnote: set text(fill: maroon)
変更した合印#footnote[合印だけに色が付きます。]
]
#block(width: 6.6em, stroke: 0.5pt, inset: 2pt)[
日日日日日親#footnote[合印が親文字と分かれる場合があります。]次
]
#block(width: 6.6em, stroke: 0.5pt, inset: 2pt)[
日日日日日#noted([親], [親文字と合印を一体にします。])次
]
行間に置く合印:#interlinear-note([対象語], [対象語の上側に置いた合印です。])
#grid(
columns: (1fr, 1fr),
gutter: 10pt,
[
*合印なし*
#set par(leading: 6pt)
1行目です。\
2行目です。
],
[
*上付き合印*
#set par(leading: 6pt)
1行目#super[1]です。\
2行目です。
],
)
C.3 補記
一部対応 組み込み規則で禁則処理されますが、補記に示される4段階の許容レベルを選べません。 CJKの改行処理はBetter CJK support(typst/typst#276)で追跡されています。
#set page(width: 130pt, height: 100pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 8pt)
#block(width: 6em)[日日日日日(次)]
#block(width: 6em)[日日日日日日。次]
D. 行の調整処理で詰める処理が可能な箇所
一部対応 両端揃えでは欧文間隔を既定で通常幅の3分の2まで縮めます。CJK約物には文字種ごとの縮小可能量があり、連続する約物の一部は行調整前にも詰められます。Typst 0.14.0以降はpar.justification-limitsで文字間の縮小量も指定できます(Support for character-level justification(typst/typst#6161))。ただし、JLReqの表3〜5が定める方式別の対象箇所、縮小量、段階的な優先順位は選べません。 約物幅の制御はOption to have raw, unchanged, surpriseless, uniform CJK full-width punctuation width(typst/typst#7643)で、CJK文字間の空きを調整して公称の行長へ合わせる処理はStrict grid for CJK, hopefully via glue(typst/typst#4404)で提案されています。
#set page(width: 300pt, height: 140pt, margin: 14pt)
#set text(
font: "Noto Serif CJK JP",
lang: "ja",
size: 12pt,
spacing: 600%,
)
#set par(justify: true)
#let phrase = [AAAA~BBBB~CCCC]
*調整前*
#box(stroke: .5pt)[#phrase]
#grid(
columns: (1fr, 1fr),
gutter: 18pt,
[
*欧文間隔を縮小*
#set par(justification-limits: (
spacing: (min: 1%, max: 100%),
tracking: (min: 0pt, max: 0pt),
))
#block(width: 9em, stroke: .5pt)[#phrase#linebreak(justify: true)]
],
[
*文字間を縮小*
#set par(justification-limits: (
spacing: (min: 100%, max: 100%),
tracking: (min: -0.35em, max: 0pt),
))
#block(width: 9em, stroke: .5pt)[#phrase#linebreak(justify: true)]
],
)
#set page(width: 220pt, height: 175pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 12pt)
#set par(justify: true)
#let comparison(label, text) = grid(
columns: (3em, auto, 5.4em),
gutter: .6em,
align: horizon,
[#label],
box(stroke: .5pt, inset: 2pt)[#text],
block(width: 5.4em, stroke: .5pt, inset: 2pt)[
#text#linebreak(justify: true)
],
)
#grid(
columns: (3em, auto, 5.4em),
gutter: .6em,
[*組合せ*], [*自然幅*], [*狭い行*],
)
#comparison([中点], [漢字・・漢字])
#comparison([句点], [漢字。・漢字])
#comparison([読点], [漢字、・漢字])
D.1 表3,表4及び表5の見方
評価対象外
D.2 注記
一部対応 連続する約物の一部は行調整前に詰められ、行調整では欧文間隔と約物の空きを縮小できます。ただし、表3〜5の文字クラス別の対象箇所、縮小量、段階的な優先順位、ルビなどの複合文字群に対する処理は指定できません。 約物幅の制御はOption to have raw, unchanged, surpriseless, uniform CJK full-width punctuation width(typst/typst#7643)で、CJK文字間の空きを調整して公称の行長へ合わせる処理はStrict grid for CJK, hopefully via glue(typst/typst#4404)で提案されています。
#set page(width: 220pt, height: 175pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 12pt)
#set par(justify: true)
#let comparison(label, text) = grid(
columns: (3em, auto, 5.4em),
gutter: .6em,
align: horizon,
[#label],
box(stroke: .5pt, inset: 2pt)[#text],
block(width: 5.4em, stroke: .5pt, inset: 2pt)[
#text#linebreak(justify: true)
],
)
#grid(
columns: (3em, auto, 5.4em),
gutter: .6em,
[*組合せ*], [*自然幅*], [*狭い行*],
)
#comparison([中点], [漢字・・漢字])
#comparison([句点], [漢字。・漢字])
#comparison([読点], [漢字、・漢字])
#set page(width: 300pt, height: 140pt, margin: 14pt)
#set text(
font: "Noto Serif CJK JP",
lang: "ja",
size: 12pt,
spacing: 600%,
)
#set par(justify: true)
#let phrase = [AAAA~BBBB~CCCC]
*調整前*
#box(stroke: .5pt)[#phrase]
#grid(
columns: (1fr, 1fr),
gutter: 18pt,
[
*欧文間隔を縮小*
#set par(justification-limits: (
spacing: (min: 1%, max: 100%),
tracking: (min: 0pt, max: 0pt),
))
#block(width: 9em, stroke: .5pt)[#phrase#linebreak(justify: true)]
],
[
*文字間を縮小*
#set par(justification-limits: (
spacing: (min: 100%, max: 100%),
tracking: (min: -0.35em, max: 0pt),
))
#block(width: 9em, stroke: .5pt)[#phrase#linebreak(justify: true)]
],
)
E. 行の調整処理で空ける処理が可能な箇所
一部対応 両端揃えでは、最初の調整で欧文間隔を通常幅の1.5倍まで広げます。Typst 0.14.0以降はpar.justification-limitsで文字間も指定した上限まで一律に広げられます(Support for character-level justification(typst/typst#6161))。この調整だけで不足する場合は、欧文間隔やCJK文字間の調整可能な箇所に残りの空きを加えます。JLReqの表6に基づく対象箇所、拡大量、優先順位は指定できません。 CJK文字間の空きを調整して公称の行長へ合わせる処理はStrict grid for CJK, hopefully via glue(typst/typst#4404)で提案されています。
#set page(width: 320pt, height: 130pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 12pt)
#set par(justify: true)
#grid(
columns: (1fr, 1fr),
gutter: 18pt,
[
*欧文間隔を拡大*
#set par(justification-limits: (
spacing: (min: 100%, max: 400%),
tracking: (min: 0pt, max: 0pt),
))
#block(width: 11em, stroke: .5pt)[AB CD EF GH#linebreak(justify: true)]
],
[
*文字間を拡大*
#set par(justification-limits: (
spacing: (min: 100%, max: 100%),
tracking: (min: 0pt, max: 1em),
))
#block(
width: 11em,
stroke: .5pt,
)[漢字とかなの文字列#linebreak(justify: true)]
],
)
E.1 表6の見方
評価対象外
E.2 注記
一部対応 欧文間隔と文字間を拡大できます。ただし、文字クラス、文字群の同一性、前後の文脈に応じて対象箇所、拡大量、優先順位を切り替えることはできません。 CJK文字間の空きを調整して公称の行長へ合わせる処理はStrict grid for CJK, hopefully via glue(typst/typst#4404)で提案されています。
#set page(width: 320pt, height: 130pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 12pt)
#set par(justify: true)
#grid(
columns: (1fr, 1fr),
gutter: 18pt,
[
*欧文間隔を拡大*
#set par(justification-limits: (
spacing: (min: 100%, max: 400%),
tracking: (min: 0pt, max: 0pt),
))
#block(width: 11em, stroke: .5pt)[AB CD EF GH#linebreak(justify: true)]
],
[
*文字間を拡大*
#set par(justification-limits: (
spacing: (min: 100%, max: 100%),
tracking: (min: 0pt, max: 1em),
))
#block(
width: 11em,
stroke: .5pt,
)[漢字とかなの文字列#linebreak(justify: true)]
],
)
F. 熟語ルビの配置方法
未対応 この附属書は、縦組の肩付きルビについて、熟語の構成と前後の文字に応じた配置方法を定めています。縦組の肩付き配置、親文字とルビの対応、熟語内と隣接文字への掛かり、空き量、改行位置を文書内容に応じて連動させる処理には対応していません。 ルビはAdd support for ruby (CJK, e.g., furigana for Japanese)(typst/typst#1489)で提案されています。
F.1 熟語ルビの配置方法の原則その1
未対応 縦組の肩付き熟語ルビについて、親文字ごとのルビが2字以下なら対応関係を保ち、熟語内ではルビ文字サイズの1字分または1.5字分まで掛ける処理はありません。隣接する漢字等へは掛けず、平仮名・片仮名へは最大1字分掛けるという文字クラス別の調整にも対応していません。 ルビはAdd support for ruby (CJK, e.g., furigana for Japanese)(typst/typst#1489)で提案されています。
F.2 熟語ルビの配置方法の原則その2
未対応 縦組の肩付き熟語ルビについて、3字以上のルビを、同じ熟語内では後ろ、次に前の親文字へ掛け、その後に隣接する平仮名などへ掛け、なお収まらなければ親文字の字間を空ける順序で処理できません。 ルビはAdd support for ruby (CJK, e.g., furigana for Japanese)(typst/typst#1489)で提案されています。
F.3 熟語ルビの親文字の字間を空ける処理の原則
未対応 縦組の肩付き熟語ルビについて、3字以上のルビが付く親文字を対象に、ルビの超過分から熟語内と隣接文字への掛かりを引いた空き量を求め、ルビ文字数に比例して配分する処理はありません。配分量を親文字の前後へ等分し、行頭では後ろ、行末では前へ全量を置く処理にも対応していません。 ルビはAdd support for ruby (CJK, e.g., furigana for Japanese)(typst/typst#1489)で提案されています。
F.4 熟語ルビの親文字の字間を空ける処理例
未対応 ルビ文字数と前後の文字に応じて親文字の前後を空け、行頭・行末では親文字とルビ文字列の端をそろえる処理はありません。 ルビはAdd support for ruby (CJK, e.g., furigana for Japanese)(typst/typst#1489)で提案されています。
G. 用語集
評価対象外
H. 参考文献
評価対象外
I. 謝辞
評価対象外
J. 変更記録
評価対象外
その他
JLReqで扱われていない、Typstにおける日本語組版の課題をまとめます。
CJKフォントのフォールバック
一部対応 text.fontには複数のフォントを優先順に指定できます。CJKフォントを指定しない場合は利用可能なフォント全体から字形ごとにフォールバックするため、環境によって書体が変わり、同じ文章内で複数の書体が混在することがあります。 Typst Web Appで、未指定のCJK文字が複数のフォールバックフォントに分かれる問題はWriting non-Latin (e.g. Chinese) text without a configured font leads to unpredictable font fallback(typst/typst#5040)で追跡されています。
#set page(width: 250pt, height: 150pt, margin: 14pt)
#set text(lang: "ja", size: 10pt)
*フォント未指定* #linebreak()
#text(size: 16pt)[ABC 日本語]
*単一のフォント* #linebreak()
#text(font: "Noto Serif CJK JP", size: 16pt)[ABC 日本語]
*字形ごとのフォールバック* #linebreak()
#text(
font: (
(name: "Noto Sans CJK JP", covers: regex("[A-Z]")),
"Noto Serif CJK JP",
),
size: 16pt,
)[
ABC 日本語
]
和文フォントと欧文フォントの大きさ
未対応 text.fontのフォールバック候補ごとに文字サイズを指定し、和文と欧文の見かけの大きさを自動調整する機能はありません。 フォントごとの文字サイズ指定はSize per font(typst/typst#6295)で提案されています。
言語・地域に応じた字形選択
一部対応 lang、region、scriptは指定できます。約物が参照や装飾によって前後の文字と別に処理されると、scriptを自動推定できず、OpenTypeのloclによる地域別字形が選ばれない場合があります。 言語に応じた字形選択はThe inferred writing script is not passed to HarfBuzz, making locl ineffective(typst/typst#7396)で追跡されています。
#set page(width: 240pt, height: 145pt, margin: 14pt)
#set text(font: "Noto Serif CJK SC", lang: "zh", region: "TW", size: 9pt)
*自動推定*
#text(size: 20pt)[#text(fill: blue)[句號]。#text(fill: red)[何故]?]
*scriptを指定*
#text(size: 20pt, script: "hani")[
#text(fill: blue)[句號]。#text(fill: red)[何故]?
]
rawテキスト前後の和欧文間隔
未対応 Typst 0.13.0以降、rawテキストは和欧文間隔の自動調整の対象外であることが明記されています(Disable cjk_latin_spacing in raw by default(typst/typst#5753))。そのため、通常の漢字・仮名と欧字・数字の境界に入る空きは、rawテキストとの境界には入りません。 rawテキストとの境界に空きを設ける要望はCJK-Latin-spacing not working with raw text(typst/typst#2702)にありますが、rawを自動調整の対象外とする挙動は0.13.0で明記されました(Disable cjk_latin_spacing in raw by default(typst/typst#5753))。
#set page(width: 360pt, height: 185pt, margin: 14pt)
#set text(font: "Noto Serif CJK JP", lang: "ja", size: 16pt)
*通常* 漢字Latin漢字 漢字Latin漢字
*raw* 漢字`code`漢字 漢字`code`漢字
rawテキストのCJK等幅フォント
一部対応 show raw: set text(font: ...)でCJK字形を含む等幅フォントを指定できます。既定のDejaVu Sans MonoにはCJK字形がないため、CJK文字には別の利用可能なフォントを探索します。対応するフォントがなければ欠落字形になり、見つかった場合も選択結果は利用できるフォントによって変わります。 Windowsでrawテキストに不適切なCJKフォントが選ばれる問題はWrong “monospace” font fallback for CJK characters in raw block(typst/typst#3385)で追跡されています。
#set page(width: 250pt, height: 190pt, margin: 14pt)
#set text(size: 9pt)
#show raw: set text(size: 16pt)
既定:
```txt
実行結果:日本語 ABC 012
```
#show raw: set text(font: "Noto Sans Mono CJK JP")
フォント指定後:
```txt
実行結果:日本語 ABC 012
```