How to use Arabic and Roman page numbers in one document?

Hi everyone,

I’m new to Typst and are trying so set up the page numbering in my document. For each chapter I have a separate .typ document, which I include in the main.typ with the #include function as you see in the following snippet.

// first section

#include "deckblatt.typ"
#pagebreak()

#include "sperrvermerk.typ"
#pagebreak()

#include "danksagung.typ"
#pagebreak()

#include "inhaltsverzeichnis.typ"
#pagebreak()

#include "abkuerzungsverzeichnis.typ"
#pagebreak()

#include "abbildungsverzeichnis.typ"
#pagebreak()

// main section

#include "einleitung.typ"
#pagebreak()

// last section

#include "versicherung.typ"
#pagebreak()

#include "anhang.typ"

In the main.typ I want to set up the page numbering, which should look like this: the first section (as shown in the snippet) should have Roman page numbers. Arabic page numbers should be used in the main section, but these should start with “1”. The last section should again have Roman page numbers, which should continue counting from where they left off in the first section.
Preferably this should not be done using static page numbers, but it should be possible for me to specify from which section or which #include function which page numbers are used.
I’ve already tried it with #label in the included documents and #location(ref()) in main.typ, but that didn’t work.

Do you have any idea for a possible solution?

For the first switch from Roman numerals to Arabic numerals you can call the set rule for the page numbering (again) and reset the page counter to 1. This is also shown as the example in the documentation for the counter, see here.

The second switch is a bit more complicated since you want to continue with the roman page count from the first section. I would propose to customize the page numbering to add the page counter at the end of the first section to the current page counter. I added a single metadata element here to mark the end of the first section.

#set page(numbering: "I")
#include "first-section.typ"
#metadata("end-of-first-section") <end-of-first-section>

#set page(numbering: "1")
#counter(page).update(1)
#include "main.typ"

#let last-section-numbering(..n) = context {
  let offset = counter(page).at(<end-of-first-section>).at(0)
  numbering("I", n.at(0) + offset)
}
#set page(numbering: last-section-numbering)
#counter(page).update(1)
#include "last-section.typ"

Thanks for your answer, the solution seems to be almost right!
There’s only one little problem: after applying your code, the first section ends with page VII, but the last section starts with IX, so there’s is one page “missing”. I added -1 behind the offset in numbering("I", n.at(0) + offset), so the final result is numbering("I", n.at(0) + offset -1). With that, everything works well. Is this a good solution or do you want to correct it in another way?

I think this is just caused by the order of the metadata label and the page breaks that you put between the sections in your initial post. I can reproduce your issue with the following code where the metadata comes after the page break. This causes the page counter to be incremented again even though the next page already uses the Arabic numbers starting at 1.

#set page(numbering: "I")
#include "first-section.typ"
#pagebreak()
#metadata("end-of-first-section") <end-of-first-section>

If you put the metadata before the page break, it should work without the manual offset.

#set page(numbering: "I")
#include "first-section.typ"
#metadata("end-of-first-section") <end-of-first-section>
#pagebreak()

If this does not fix your issue, please post a minimal working example that reproduces the issue. You can use lorem() to just add some text instead of including the section files that only you have access to.

#set page(numbering: "I")
#lorem(1000)
#metadata("end-of-first-section") <end-of-first-section>
#pagebreak()
...

Hi. In essence, you want something like this:

#set page(width: 5cm, height: 2cm, footer-descent: 0pt, margin: 3mm)
#set pagebreak(weak: true)

#set page(numbering: "I")

= I First section
#pagebreak()

#let saved-page = state("saved-page")
#context saved-page.update(counter(page).get())
#set page(numbering: "1")
#counter(page).update(1)

= 1 Main section
#pagebreak()

= 2 Main section
#pagebreak()

#set page(numbering: "I")
#context counter(page).update(saved-page.get())

= II Last section
#pagebreak()

= III Last section

You can create a bunch of wrappers, but if it’s in the main file that doesn’t have anything, then I think it’s fine to leave it as is, because it explains itself pretty well. You can add intention comments.

Hi, that was exactly the solution I needed. Now it works. Thank you very much!