From 547b6dc806cbfb6f8f26af57993579b23e98b837 Mon Sep 17 00:00:00 2001 From: Sina Atalay <79940989+sinaatalay@users.noreply.github.com> Date: Fri, 12 Dec 2025 13:29:15 +0300 Subject: [PATCH] Improve placeholders and JSON Schema --- schema.json | 126 +++++++------- .../renderer/templater/footer_and_top_note.py | 24 +++ .../schema/models/design/classic_theme.py | 159 ++++++++++++++---- tests/cli/render_command/test_run_rendercv.py | 4 +- .../test_entry_templates_from_input.py | 5 +- .../templater/test_markdown_parser.py | 2 +- 6 files changed, 217 insertions(+), 103 deletions(-) diff --git a/schema.json b/schema.json index 2c1f7cb1..aa18ceab 100644 --- a/schema.json +++ b/schema.json @@ -3131,7 +3131,7 @@ "properties": { "main_column": { "default": "**INSTITUTION**, AREA\nSUMMARY\nHIGHLIGHTS", - "description": "The content of the template. The available placeholders are all the keys used in the entries in uppercase. For example, **TITLE**. The default value is `**INSTITUTION**, AREA\\nSUMMARY\\nHIGHLIGHTS`.", + "description": "Template for education entry main column. Available placeholders:\n- `INSTITUTION`: Institution name\n- `AREA`: Field of study/major\n- `DEGREE`: Degree type (e.g., BS, PhD)\n- `SUMMARY`: Summary text\n- `HIGHLIGHTS`: Bullet points list\n- `LOCATION`: Location text\n- `DATE`: Formatted date or date range\n\nYou can also add arbitrary keys to entries and use them as UPPERCASE placeholders.\n\nThe default value is `**INSTITUTION**, AREA\\nSUMMARY\\nHIGHLIGHTS`.", "title": "Main Column", "type": "string" }, @@ -3145,12 +3145,12 @@ } ], "default": "**DEGREE**", - "description": "If given, a degree column will be added to the education entry. If \"null\", no degree column will be shown. The available placeholders are all the keys used in the entries (in uppercase). The default value is `**DEGREE**`.", + "description": "Optional degree column template. If provided, displays degree in separate column. If `null`, no degree column is shown. Available placeholders:\n- `INSTITUTION`: Institution name\n- `AREA`: Field of study/major\n- `DEGREE`: Degree type (e.g., BS, PhD)\n- `SUMMARY`: Summary text\n- `HIGHLIGHTS`: Bullet points list\n- `LOCATION`: Location text\n- `DATE`: Formatted date or date range\n\nYou can also add arbitrary keys to entries and use them as UPPERCASE placeholders.\n\nThe default value is `**DEGREE**`.", "title": "Degree Column" }, "date_and_location_column": { "default": "LOCATION\nDATE", - "description": "The content of the template. The available placeholders are all the keys used in the entries in uppercase. For example, **TITLE**. The default value is `LOCATION\\nDATE`.", + "description": "Template for education entry date/location column. Available placeholders:\n- `INSTITUTION`: Institution name\n- `AREA`: Field of study/major\n- `DEGREE`: Degree type (e.g., BS, PhD)\n- `SUMMARY`: Summary text\n- `HIGHLIGHTS`: Bullet points list\n- `LOCATION`: Location text\n- `DATE`: Formatted date or date range\n\nYou can also add arbitrary keys to entries and use them as UPPERCASE placeholders.\n\nThe default value is `LOCATION\\nDATE`.", "title": "Date And Location Column", "type": "string" } @@ -3163,7 +3163,7 @@ "properties": { "main_column": { "default": "**INSTITUTION**, DEGREE in AREA -- LOCATION\nSUMMARY\nHIGHLIGHTS", - "description": "The content of the template. The available placeholders are all the keys used in the entries in uppercase. For example, **TITLE**. The default value is `**INSTITUTION**, AREA\\nSUMMARY\\nHIGHLIGHTS`.", + "description": "Template for education entry main column. Available placeholders:\n- `INSTITUTION`: Institution name\n- `AREA`: Field of study/major\n- `DEGREE`: Degree type (e.g., BS, PhD)\n- `SUMMARY`: Summary text\n- `HIGHLIGHTS`: Bullet points list\n- `LOCATION`: Location text\n- `DATE`: Formatted date or date range\n\nYou can also add arbitrary keys to entries and use them as UPPERCASE placeholders.\n\nThe default value is `**INSTITUTION**, AREA\\nSUMMARY\\nHIGHLIGHTS`.", "title": "Main Column", "type": "string" }, @@ -3177,12 +3177,12 @@ } ], "default": null, - "description": "If given, a degree column will be added to the education entry. If \"null\", no degree column will be shown. The available placeholders are all the keys used in the entries (in uppercase). The default value is `None`.", + "description": "Optional degree column template. If provided, displays degree in separate column. If `null`, no degree column is shown. Available placeholders:\n- `INSTITUTION`: Institution name\n- `AREA`: Field of study/major\n- `DEGREE`: Degree type (e.g., BS, PhD)\n- `SUMMARY`: Summary text\n- `HIGHLIGHTS`: Bullet points list\n- `LOCATION`: Location text\n- `DATE`: Formatted date or date range\n\nYou can also add arbitrary keys to entries and use them as UPPERCASE placeholders.\n\nThe default value is `None`.", "title": "Degree Column" }, "date_and_location_column": { "default": "DATE", - "description": "The content of the template. The available placeholders are all the keys used in the entries in uppercase. For example, **TITLE**. The default value is `LOCATION\\nDATE`.", + "description": "Template for education entry date/location column. Available placeholders:\n- `INSTITUTION`: Institution name\n- `AREA`: Field of study/major\n- `DEGREE`: Degree type (e.g., BS, PhD)\n- `SUMMARY`: Summary text\n- `HIGHLIGHTS`: Bullet points list\n- `LOCATION`: Location text\n- `DATE`: Formatted date or date range\n\nYou can also add arbitrary keys to entries and use them as UPPERCASE placeholders.\n\nThe default value is `LOCATION\\nDATE`.", "title": "Date And Location Column", "type": "string" } @@ -3195,7 +3195,7 @@ "properties": { "main_column": { "default": "**INSTITUTION**, DEGREE in AREA -- LOCATION\nSUMMARY\nHIGHLIGHTS", - "description": "The content of the template. The available placeholders are all the keys used in the entries in uppercase. For example, **TITLE**. The default value is `**INSTITUTION**, AREA\\nSUMMARY\\nHIGHLIGHTS`.", + "description": "Template for education entry main column. Available placeholders:\n- `INSTITUTION`: Institution name\n- `AREA`: Field of study/major\n- `DEGREE`: Degree type (e.g., BS, PhD)\n- `SUMMARY`: Summary text\n- `HIGHLIGHTS`: Bullet points list\n- `LOCATION`: Location text\n- `DATE`: Formatted date or date range\n\nYou can also add arbitrary keys to entries and use them as UPPERCASE placeholders.\n\nThe default value is `**INSTITUTION**, AREA\\nSUMMARY\\nHIGHLIGHTS`.", "title": "Main Column", "type": "string" }, @@ -3209,12 +3209,12 @@ } ], "default": null, - "description": "If given, a degree column will be added to the education entry. If \"null\", no degree column will be shown. The available placeholders are all the keys used in the entries (in uppercase). The default value is `None`.", + "description": "Optional degree column template. If provided, displays degree in separate column. If `null`, no degree column is shown. Available placeholders:\n- `INSTITUTION`: Institution name\n- `AREA`: Field of study/major\n- `DEGREE`: Degree type (e.g., BS, PhD)\n- `SUMMARY`: Summary text\n- `HIGHLIGHTS`: Bullet points list\n- `LOCATION`: Location text\n- `DATE`: Formatted date or date range\n\nYou can also add arbitrary keys to entries and use them as UPPERCASE placeholders.\n\nThe default value is `None`.", "title": "Degree Column" }, "date_and_location_column": { "default": "DATE", - "description": "The content of the template. The available placeholders are all the keys used in the entries in uppercase. For example, **TITLE**. The default value is `LOCATION\\nDATE`.", + "description": "Template for education entry date/location column. Available placeholders:\n- `INSTITUTION`: Institution name\n- `AREA`: Field of study/major\n- `DEGREE`: Degree type (e.g., BS, PhD)\n- `SUMMARY`: Summary text\n- `HIGHLIGHTS`: Bullet points list\n- `LOCATION`: Location text\n- `DATE`: Formatted date or date range\n\nYou can also add arbitrary keys to entries and use them as UPPERCASE placeholders.\n\nThe default value is `LOCATION\\nDATE`.", "title": "Date And Location Column", "type": "string" } @@ -3227,7 +3227,7 @@ "properties": { "main_column": { "default": "**INSTITUTION**, DEGREE in AREA -- LOCATION\nSUMMARY\nHIGHLIGHTS", - "description": "The content of the template. The available placeholders are all the keys used in the entries in uppercase. For example, **TITLE**. The default value is `**INSTITUTION**, AREA\\nSUMMARY\\nHIGHLIGHTS`.", + "description": "Template for education entry main column. Available placeholders:\n- `INSTITUTION`: Institution name\n- `AREA`: Field of study/major\n- `DEGREE`: Degree type (e.g., BS, PhD)\n- `SUMMARY`: Summary text\n- `HIGHLIGHTS`: Bullet points list\n- `LOCATION`: Location text\n- `DATE`: Formatted date or date range\n\nYou can also add arbitrary keys to entries and use them as UPPERCASE placeholders.\n\nThe default value is `**INSTITUTION**, AREA\\nSUMMARY\\nHIGHLIGHTS`.", "title": "Main Column", "type": "string" }, @@ -3241,12 +3241,12 @@ } ], "default": null, - "description": "If given, a degree column will be added to the education entry. If \"null\", no degree column will be shown. The available placeholders are all the keys used in the entries (in uppercase). The default value is `None`.", + "description": "Optional degree column template. If provided, displays degree in separate column. If `null`, no degree column is shown. Available placeholders:\n- `INSTITUTION`: Institution name\n- `AREA`: Field of study/major\n- `DEGREE`: Degree type (e.g., BS, PhD)\n- `SUMMARY`: Summary text\n- `HIGHLIGHTS`: Bullet points list\n- `LOCATION`: Location text\n- `DATE`: Formatted date or date range\n\nYou can also add arbitrary keys to entries and use them as UPPERCASE placeholders.\n\nThe default value is `None`.", "title": "Degree Column" }, "date_and_location_column": { "default": "DATE", - "description": "The content of the template. The available placeholders are all the keys used in the entries in uppercase. For example, **TITLE**. The default value is `LOCATION\\nDATE`.", + "description": "Template for education entry date/location column. Available placeholders:\n- `INSTITUTION`: Institution name\n- `AREA`: Field of study/major\n- `DEGREE`: Degree type (e.g., BS, PhD)\n- `SUMMARY`: Summary text\n- `HIGHLIGHTS`: Bullet points list\n- `LOCATION`: Location text\n- `DATE`: Formatted date or date range\n\nYou can also add arbitrary keys to entries and use them as UPPERCASE placeholders.\n\nThe default value is `LOCATION\\nDATE`.", "title": "Date And Location Column", "type": "string" } @@ -3259,7 +3259,7 @@ "properties": { "main_column": { "default": "**INSTITUTION**\n*DEGREE* *in* *AREA*\nSUMMARY\nHIGHLIGHTS", - "description": "The content of the template. The available placeholders are all the keys used in the entries in uppercase. For example, **TITLE**. The default value is `**INSTITUTION**, AREA\\nSUMMARY\\nHIGHLIGHTS`.", + "description": "Template for education entry main column. Available placeholders:\n- `INSTITUTION`: Institution name\n- `AREA`: Field of study/major\n- `DEGREE`: Degree type (e.g., BS, PhD)\n- `SUMMARY`: Summary text\n- `HIGHLIGHTS`: Bullet points list\n- `LOCATION`: Location text\n- `DATE`: Formatted date or date range\n\nYou can also add arbitrary keys to entries and use them as UPPERCASE placeholders.\n\nThe default value is `**INSTITUTION**, AREA\\nSUMMARY\\nHIGHLIGHTS`.", "title": "Main Column", "type": "string" }, @@ -3273,12 +3273,12 @@ } ], "default": null, - "description": "If given, a degree column will be added to the education entry. If \"null\", no degree column will be shown. The available placeholders are all the keys used in the entries (in uppercase). The default value is `None`.", + "description": "Optional degree column template. If provided, displays degree in separate column. If `null`, no degree column is shown. Available placeholders:\n- `INSTITUTION`: Institution name\n- `AREA`: Field of study/major\n- `DEGREE`: Degree type (e.g., BS, PhD)\n- `SUMMARY`: Summary text\n- `HIGHLIGHTS`: Bullet points list\n- `LOCATION`: Location text\n- `DATE`: Formatted date or date range\n\nYou can also add arbitrary keys to entries and use them as UPPERCASE placeholders.\n\nThe default value is `None`.", "title": "Degree Column" }, "date_and_location_column": { "default": "*LOCATION*\n*DATE*", - "description": "The content of the template. The available placeholders are all the keys used in the entries in uppercase. For example, **TITLE**. The default value is `LOCATION\\nDATE`.", + "description": "Template for education entry date/location column. Available placeholders:\n- `INSTITUTION`: Institution name\n- `AREA`: Field of study/major\n- `DEGREE`: Degree type (e.g., BS, PhD)\n- `SUMMARY`: Summary text\n- `HIGHLIGHTS`: Bullet points list\n- `LOCATION`: Location text\n- `DATE`: Formatted date or date range\n\nYou can also add arbitrary keys to entries and use them as UPPERCASE placeholders.\n\nThe default value is `LOCATION\\nDATE`.", "title": "Date And Location Column", "type": "string" } @@ -3501,13 +3501,13 @@ "properties": { "main_column": { "default": "**COMPANY**, POSITION\nSUMMARY\nHIGHLIGHTS", - "description": "The content of the template. The available placeholders are all the keys used in the entries in uppercase. For example, **TITLE**. The default value is `**COMPANY**, POSITION\\nSUMMARY\\nHIGHLIGHTS`.", + "description": "Template for experience entry main column. Available placeholders:\n- `COMPANY`: Company name\n- `POSITION`: Job title/position\n- `SUMMARY`: Summary text\n- `HIGHLIGHTS`: Bullet points list\n- `LOCATION`: Location text\n- `DATE`: Formatted date or date range\n\nYou can also add arbitrary keys to entries and use them as UPPERCASE placeholders.\n\nThe default value is `**COMPANY**, POSITION\\nSUMMARY\\nHIGHLIGHTS`.", "title": "Main Column", "type": "string" }, "date_and_location_column": { "default": "LOCATION\nDATE", - "description": "The content of the template. The available placeholders are all the keys used in the entries in uppercase. For example, **TITLE**. The default value is `LOCATION\\nDATE`.", + "description": "Template for experience entry date/location column. Available placeholders:\n- `COMPANY`: Company name\n- `POSITION`: Job title/position\n- `SUMMARY`: Summary text\n- `HIGHLIGHTS`: Bullet points list\n- `LOCATION`: Location text\n- `DATE`: Formatted date or date range\n\nYou can also add arbitrary keys to entries and use them as UPPERCASE placeholders.\n\nThe default value is `LOCATION\\nDATE`.", "title": "Date And Location Column", "type": "string" } @@ -3520,13 +3520,13 @@ "properties": { "main_column": { "default": "**POSITION**, COMPANY -- LOCATION\nSUMMARY\nHIGHLIGHTS", - "description": "The content of the template. The available placeholders are all the keys used in the entries in uppercase. For example, **TITLE**. The default value is `**COMPANY**, POSITION\\nSUMMARY\\nHIGHLIGHTS`.", + "description": "Template for experience entry main column. Available placeholders:\n- `COMPANY`: Company name\n- `POSITION`: Job title/position\n- `SUMMARY`: Summary text\n- `HIGHLIGHTS`: Bullet points list\n- `LOCATION`: Location text\n- `DATE`: Formatted date or date range\n\nYou can also add arbitrary keys to entries and use them as UPPERCASE placeholders.\n\nThe default value is `**COMPANY**, POSITION\\nSUMMARY\\nHIGHLIGHTS`.", "title": "Main Column", "type": "string" }, "date_and_location_column": { "default": "DATE", - "description": "The content of the template. The available placeholders are all the keys used in the entries in uppercase. For example, **TITLE**. The default value is `LOCATION\\nDATE`.", + "description": "Template for experience entry date/location column. Available placeholders:\n- `COMPANY`: Company name\n- `POSITION`: Job title/position\n- `SUMMARY`: Summary text\n- `HIGHLIGHTS`: Bullet points list\n- `LOCATION`: Location text\n- `DATE`: Formatted date or date range\n\nYou can also add arbitrary keys to entries and use them as UPPERCASE placeholders.\n\nThe default value is `LOCATION\\nDATE`.", "title": "Date And Location Column", "type": "string" } @@ -3539,13 +3539,13 @@ "properties": { "main_column": { "default": "**POSITION**, COMPANY -- LOCATION\nSUMMARY\nHIGHLIGHTS", - "description": "The content of the template. The available placeholders are all the keys used in the entries in uppercase. For example, **TITLE**. The default value is `**COMPANY**, POSITION\\nSUMMARY\\nHIGHLIGHTS`.", + "description": "Template for experience entry main column. Available placeholders:\n- `COMPANY`: Company name\n- `POSITION`: Job title/position\n- `SUMMARY`: Summary text\n- `HIGHLIGHTS`: Bullet points list\n- `LOCATION`: Location text\n- `DATE`: Formatted date or date range\n\nYou can also add arbitrary keys to entries and use them as UPPERCASE placeholders.\n\nThe default value is `**COMPANY**, POSITION\\nSUMMARY\\nHIGHLIGHTS`.", "title": "Main Column", "type": "string" }, "date_and_location_column": { "default": "DATE", - "description": "The content of the template. The available placeholders are all the keys used in the entries in uppercase. For example, **TITLE**. The default value is `LOCATION\\nDATE`.", + "description": "Template for experience entry date/location column. Available placeholders:\n- `COMPANY`: Company name\n- `POSITION`: Job title/position\n- `SUMMARY`: Summary text\n- `HIGHLIGHTS`: Bullet points list\n- `LOCATION`: Location text\n- `DATE`: Formatted date or date range\n\nYou can also add arbitrary keys to entries and use them as UPPERCASE placeholders.\n\nThe default value is `LOCATION\\nDATE`.", "title": "Date And Location Column", "type": "string" } @@ -3558,13 +3558,13 @@ "properties": { "main_column": { "default": "**POSITION**, COMPANY -- LOCATION\nSUMMARY\nHIGHLIGHTS", - "description": "The content of the template. The available placeholders are all the keys used in the entries in uppercase. For example, **TITLE**. The default value is `**COMPANY**, POSITION\\nSUMMARY\\nHIGHLIGHTS`.", + "description": "Template for experience entry main column. Available placeholders:\n- `COMPANY`: Company name\n- `POSITION`: Job title/position\n- `SUMMARY`: Summary text\n- `HIGHLIGHTS`: Bullet points list\n- `LOCATION`: Location text\n- `DATE`: Formatted date or date range\n\nYou can also add arbitrary keys to entries and use them as UPPERCASE placeholders.\n\nThe default value is `**COMPANY**, POSITION\\nSUMMARY\\nHIGHLIGHTS`.", "title": "Main Column", "type": "string" }, "date_and_location_column": { "default": "DATE", - "description": "The content of the template. The available placeholders are all the keys used in the entries in uppercase. For example, **TITLE**. The default value is `LOCATION\\nDATE`.", + "description": "Template for experience entry date/location column. Available placeholders:\n- `COMPANY`: Company name\n- `POSITION`: Job title/position\n- `SUMMARY`: Summary text\n- `HIGHLIGHTS`: Bullet points list\n- `LOCATION`: Location text\n- `DATE`: Formatted date or date range\n\nYou can also add arbitrary keys to entries and use them as UPPERCASE placeholders.\n\nThe default value is `LOCATION\\nDATE`.", "title": "Date And Location Column", "type": "string" } @@ -3577,13 +3577,13 @@ "properties": { "main_column": { "default": "**POSITION**\n*COMPANY*\nSUMMARY\nHIGHLIGHTS", - "description": "The content of the template. The available placeholders are all the keys used in the entries in uppercase. For example, **TITLE**. The default value is `**COMPANY**, POSITION\\nSUMMARY\\nHIGHLIGHTS`.", + "description": "Template for experience entry main column. Available placeholders:\n- `COMPANY`: Company name\n- `POSITION`: Job title/position\n- `SUMMARY`: Summary text\n- `HIGHLIGHTS`: Bullet points list\n- `LOCATION`: Location text\n- `DATE`: Formatted date or date range\n\nYou can also add arbitrary keys to entries and use them as UPPERCASE placeholders.\n\nThe default value is `**COMPANY**, POSITION\\nSUMMARY\\nHIGHLIGHTS`.", "title": "Main Column", "type": "string" }, "date_and_location_column": { "default": "*LOCATION*\n*DATE*", - "description": "The content of the template. The available placeholders are all the keys used in the entries in uppercase. For example, **TITLE**. The default value is `LOCATION\\nDATE`.", + "description": "Template for experience entry date/location column. Available placeholders:\n- `COMPANY`: Company name\n- `POSITION`: Job title/position\n- `SUMMARY`: Summary text\n- `HIGHLIGHTS`: Bullet points list\n- `LOCATION`: Location text\n- `DATE`: Formatted date or date range\n\nYou can also add arbitrary keys to entries and use them as UPPERCASE placeholders.\n\nThe default value is `LOCATION\\nDATE`.", "title": "Date And Location Column", "type": "string" } @@ -4284,13 +4284,13 @@ "properties": { "main_column": { "default": "**NAME**\nSUMMARY\nHIGHLIGHTS", - "description": "The content of the template. The available placeholders are all the keys used in the entries in uppercase. For example, **TITLE**. The default value is `**NAME**\\nSUMMARY\\nHIGHLIGHTS`.", + "description": "Template for normal entry main column. Available placeholders:\n- `NAME`: Entry name/title\n- `SUMMARY`: Summary text\n- `HIGHLIGHTS`: Bullet points list\n- `LOCATION`: Location text\n- `DATE`: Formatted date or date range\n\nYou can also add arbitrary keys to entries and use them as UPPERCASE placeholders.\n\nThe default value is `**NAME**\\nSUMMARY\\nHIGHLIGHTS`.", "title": "Main Column", "type": "string" }, "date_and_location_column": { "default": "LOCATION\nDATE", - "description": "The content of the template. The available placeholders are all the keys used in the entries in uppercase. For example, **TITLE**. The default value is `LOCATION\\nDATE`.", + "description": "Template for normal entry date/location column. Available placeholders:\n- `NAME`: Entry name/title\n- `SUMMARY`: Summary text\n- `HIGHLIGHTS`: Bullet points list\n- `LOCATION`: Location text\n- `DATE`: Formatted date or date range\n\nYou can also add arbitrary keys to entries and use them as UPPERCASE placeholders.\n\nThe default value is `LOCATION\\nDATE`.", "title": "Date And Location Column", "type": "string" } @@ -4303,13 +4303,13 @@ "properties": { "main_column": { "default": "**NAME** -- **LOCATION**\nSUMMARY\nHIGHLIGHTS", - "description": "The content of the template. The available placeholders are all the keys used in the entries in uppercase. For example, **TITLE**. The default value is `**NAME**\\nSUMMARY\\nHIGHLIGHTS`.", + "description": "Template for normal entry main column. Available placeholders:\n- `NAME`: Entry name/title\n- `SUMMARY`: Summary text\n- `HIGHLIGHTS`: Bullet points list\n- `LOCATION`: Location text\n- `DATE`: Formatted date or date range\n\nYou can also add arbitrary keys to entries and use them as UPPERCASE placeholders.\n\nThe default value is `**NAME**\\nSUMMARY\\nHIGHLIGHTS`.", "title": "Main Column", "type": "string" }, "date_and_location_column": { "default": "DATE", - "description": "The content of the template. The available placeholders are all the keys used in the entries in uppercase. For example, **TITLE**. The default value is `LOCATION\\nDATE`.", + "description": "Template for normal entry date/location column. Available placeholders:\n- `NAME`: Entry name/title\n- `SUMMARY`: Summary text\n- `HIGHLIGHTS`: Bullet points list\n- `LOCATION`: Location text\n- `DATE`: Formatted date or date range\n\nYou can also add arbitrary keys to entries and use them as UPPERCASE placeholders.\n\nThe default value is `LOCATION\\nDATE`.", "title": "Date And Location Column", "type": "string" } @@ -4322,13 +4322,13 @@ "properties": { "main_column": { "default": "**NAME** -- **LOCATION**\nSUMMARY\nHIGHLIGHTS", - "description": "The content of the template. The available placeholders are all the keys used in the entries in uppercase. For example, **TITLE**. The default value is `**NAME**\\nSUMMARY\\nHIGHLIGHTS`.", + "description": "Template for normal entry main column. Available placeholders:\n- `NAME`: Entry name/title\n- `SUMMARY`: Summary text\n- `HIGHLIGHTS`: Bullet points list\n- `LOCATION`: Location text\n- `DATE`: Formatted date or date range\n\nYou can also add arbitrary keys to entries and use them as UPPERCASE placeholders.\n\nThe default value is `**NAME**\\nSUMMARY\\nHIGHLIGHTS`.", "title": "Main Column", "type": "string" }, "date_and_location_column": { "default": "DATE", - "description": "The content of the template. The available placeholders are all the keys used in the entries in uppercase. For example, **TITLE**. The default value is `LOCATION\\nDATE`.", + "description": "Template for normal entry date/location column. Available placeholders:\n- `NAME`: Entry name/title\n- `SUMMARY`: Summary text\n- `HIGHLIGHTS`: Bullet points list\n- `LOCATION`: Location text\n- `DATE`: Formatted date or date range\n\nYou can also add arbitrary keys to entries and use them as UPPERCASE placeholders.\n\nThe default value is `LOCATION\\nDATE`.", "title": "Date And Location Column", "type": "string" } @@ -4341,13 +4341,13 @@ "properties": { "main_column": { "default": "**NAME** -- **LOCATION**\nSUMMARY\nHIGHLIGHTS", - "description": "The content of the template. The available placeholders are all the keys used in the entries in uppercase. For example, **TITLE**. The default value is `**NAME**\\nSUMMARY\\nHIGHLIGHTS`.", + "description": "Template for normal entry main column. Available placeholders:\n- `NAME`: Entry name/title\n- `SUMMARY`: Summary text\n- `HIGHLIGHTS`: Bullet points list\n- `LOCATION`: Location text\n- `DATE`: Formatted date or date range\n\nYou can also add arbitrary keys to entries and use them as UPPERCASE placeholders.\n\nThe default value is `**NAME**\\nSUMMARY\\nHIGHLIGHTS`.", "title": "Main Column", "type": "string" }, "date_and_location_column": { "default": "DATE", - "description": "The content of the template. The available placeholders are all the keys used in the entries in uppercase. For example, **TITLE**. The default value is `LOCATION\\nDATE`.", + "description": "Template for normal entry date/location column. Available placeholders:\n- `NAME`: Entry name/title\n- `SUMMARY`: Summary text\n- `HIGHLIGHTS`: Bullet points list\n- `LOCATION`: Location text\n- `DATE`: Formatted date or date range\n\nYou can also add arbitrary keys to entries and use them as UPPERCASE placeholders.\n\nThe default value is `LOCATION\\nDATE`.", "title": "Date And Location Column", "type": "string" } @@ -4360,13 +4360,13 @@ "properties": { "main_column": { "default": "**NAME**\nSUMMARY\nHIGHLIGHTS", - "description": "The content of the template. The available placeholders are all the keys used in the entries in uppercase. For example, **TITLE**. The default value is `**NAME**\\nSUMMARY\\nHIGHLIGHTS`.", + "description": "Template for normal entry main column. Available placeholders:\n- `NAME`: Entry name/title\n- `SUMMARY`: Summary text\n- `HIGHLIGHTS`: Bullet points list\n- `LOCATION`: Location text\n- `DATE`: Formatted date or date range\n\nYou can also add arbitrary keys to entries and use them as UPPERCASE placeholders.\n\nThe default value is `**NAME**\\nSUMMARY\\nHIGHLIGHTS`.", "title": "Main Column", "type": "string" }, "date_and_location_column": { "default": "*LOCATION*\n*DATE*", - "description": "The content of the template. The available placeholders are all the keys used in the entries in uppercase. For example, **TITLE**. The default value is `LOCATION\\nDATE`.", + "description": "Template for normal entry date/location column. Available placeholders:\n- `NAME`: Entry name/title\n- `SUMMARY`: Summary text\n- `HIGHLIGHTS`: Bullet points list\n- `LOCATION`: Location text\n- `DATE`: Formatted date or date range\n\nYou can also add arbitrary keys to entries and use them as UPPERCASE placeholders.\n\nThe default value is `LOCATION\\nDATE`.", "title": "Date And Location Column", "type": "string" } @@ -4379,7 +4379,7 @@ "properties": { "main_column": { "default": "**LABEL:** DETAILS", - "description": "The content of the template. The available placeholders are all the keys used in the entries in uppercase. For example, **TITLE**. The default value is `**LABEL:** DETAILS`.", + "description": "Template for one-line entries. Available placeholders:\n- `LABEL`: The label text (e.g., \"Languages\", \"Citizenship\")\n- `DETAILS`: The details text (e.g., \"English (native), Spanish (fluent)\")\n\nYou can also add arbitrary keys to entries and use them as UPPERCASE placeholders.\n\nThe default value is `**LABEL:** DETAILS`.", "title": "Main Column", "type": "string" } @@ -4480,13 +4480,13 @@ "properties": { "main_column": { "default": "**TITLE**\nSUMMARY\nAUTHORS\nURL (JOURNAL)", - "description": "The content of the template. The available placeholders are all the keys used in the entries in uppercase. For example, **TITLE**. The default value is `**TITLE**\\nSUMMARY\\nAUTHORS\\nURL (JOURNAL)`.", + "description": "Template for publication entry main column. Available placeholders:\n- `TITLE`: Publication title\n- `AUTHORS`: List of authors (formatted as comma-separated string)\n- `SUMMARY`: Summary/abstract text\n- `DOI`: Digital Object Identifier\n- `URL`: Publication URL (if DOI not provided)\n- `JOURNAL`: Journal/conference/venue name\n- `DATE`: Formatted date\n\nYou can also add arbitrary keys to entries and use them as UPPERCASE placeholders.\n\nThe default value is `**TITLE**\\nSUMMARY\\nAUTHORS\\nURL (JOURNAL)`.", "title": "Main Column", "type": "string" }, "date_and_location_column": { "default": "DATE", - "description": "The content of the template. The available placeholders are all the keys used in the entries in uppercase. For example, **TITLE**. The default value is `DATE`.", + "description": "Template for publication entry date column. Available placeholders:\n- `TITLE`: Publication title\n- `AUTHORS`: List of authors (formatted as comma-separated string)\n- `SUMMARY`: Summary/abstract text\n- `DOI`: Digital Object Identifier\n- `URL`: Publication URL (if DOI not provided)\n- `JOURNAL`: Journal/conference/venue name\n- `DATE`: Formatted date\n\nYou can also add arbitrary keys to entries and use them as UPPERCASE placeholders.\n\nThe default value is `DATE`.", "title": "Date And Location Column", "type": "string" } @@ -4869,31 +4869,31 @@ "properties": { "footer": { "default": "*NAME -- PAGE_NUMBER/TOTAL_PAGES*", - "description": "Template for the footer. Available placeholders: NAME, PAGE_NUMBER, TOTAL_PAGES. The default value is `*NAME -- PAGE_NUMBER/TOTAL_PAGES*`.", + "description": "Template for the footer. Available placeholders:\n- `NAME`: The CV owner's name from `cv.name`\n- `PAGE_NUMBER`: Current page number\n- `TOTAL_PAGES`: Total number of pages\n- `CURRENT_DATE`: Formatted date based on `design.templates.single_date`\n- `MONTH_NAME`: Full month name (e.g., January)\n- `MONTH_ABBREVIATION`: Abbreviated month name (e.g., Jan)\n- `MONTH`: Month number (e.g., 1)\n- `MONTH_IN_TWO_DIGITS`: Zero-padded month (e.g., 01)\n- `YEAR`: Full year (e.g., 2025)\n- `YEAR_IN_TWO_DIGITS`: Two-digit year (e.g., 25)\n\nThe default value is `*NAME -- PAGE_NUMBER/TOTAL_PAGES*`.", "title": "Footer", "type": "string" }, "top_note": { "default": "*LAST_UPDATED CURRENT_DATE*", - "description": "Template for the top note. Available placeholders: LAST_UPDATED, CURRENT_DATE. The default value is `*LAST_UPDATED CURRENT_DATE*`.", + "description": "Template for the top note. Available placeholders:\n- `LAST_UPDATED`: Localized \"last updated\" text from `locale.last_updated`\n- `CURRENT_DATE`: Formatted date based on `design.templates.single_date`\n- `NAME`: The CV owner's name from `cv.name`\n- `MONTH_NAME`: Full month name (e.g., January)\n- `MONTH_ABBREVIATION`: Abbreviated month name (e.g., Jan)\n- `MONTH`: Month number (e.g., 1)\n- `MONTH_IN_TWO_DIGITS`: Zero-padded month (e.g., 01)\n- `YEAR`: Full year (e.g., 2025)\n- `YEAR_IN_TWO_DIGITS`: Two-digit year (e.g., 25)\n\nThe default value is `*LAST_UPDATED CURRENT_DATE*`.", "title": "Top Note", "type": "string" }, "single_date": { "default": "MONTH_ABBREVIATION YEAR", - "description": "Template for single dates. Available placeholders: MONTH_ABBREVIATION, YEAR. The default value is `MONTH_ABBREVIATION YEAR`.", + "description": "Template for single dates. Available placeholders:\n- `MONTH_NAME`: Full month name (e.g., January)\n- `MONTH_ABBREVIATION`: Abbreviated month name (e.g., Jan)\n- `MONTH`: Month number (e.g., 1)\n- `MONTH_IN_TWO_DIGITS`: Zero-padded month (e.g., 01)\n- `YEAR`: Full year (e.g., 2025)\n- `YEAR_IN_TWO_DIGITS`: Two-digit year (e.g., 25)\n\nThe default value is `MONTH_ABBREVIATION YEAR`.", "title": "Single Date", "type": "string" }, "date_range": { "default": "START_DATE – END_DATE", - "description": "Template for date ranges. Available placeholders: START_DATE, END_DATE. The default value is `START_DATE – END_DATE`.", + "description": "Template for date ranges. Available placeholders:\n- `START_DATE`: Formatted start date based on `design.templates.single_date`\n- `END_DATE`: Formatted end date based on `design.templates.single_date` (or \"present\"/\"ongoing\" for current positions)\n\nThe default value is `START_DATE – END_DATE`.", "title": "Date Range", "type": "string" }, "time_span": { "default": "HOW_MANY_YEARS YEARS HOW_MANY_MONTHS MONTHS", - "description": "Template for time spans. Available placeholders: HOW_MANY_YEARS, YEARS, HOW_MANY_MONTHS, MONTHS. The default value is `HOW_MANY_YEARS YEARS HOW_MANY_MONTHS MONTHS`.", + "description": "Template for time spans (duration calculations). Available placeholders:\n- `HOW_MANY_YEARS`: Number of years (e.g., 2)\n- `YEARS`: Localized word for \"years\" from `locale.years` (or singular \"year\")\n- `HOW_MANY_MONTHS`: Number of months (e.g., 3)\n- `MONTHS`: Localized word for \"months\" from `locale.months` (or singular \"month\")\n\nThe default value is `HOW_MANY_YEARS YEARS HOW_MANY_MONTHS MONTHS`.", "title": "Time Span", "type": "string" }, @@ -4926,31 +4926,31 @@ "properties": { "footer": { "default": "*NAME -- PAGE_NUMBER/TOTAL_PAGES*", - "description": "Template for the footer. Available placeholders: NAME, PAGE_NUMBER, TOTAL_PAGES. The default value is `*NAME -- PAGE_NUMBER/TOTAL_PAGES*`.", + "description": "Template for the footer. Available placeholders:\n- `NAME`: The CV owner's name from `cv.name`\n- `PAGE_NUMBER`: Current page number\n- `TOTAL_PAGES`: Total number of pages\n- `CURRENT_DATE`: Formatted date based on `design.templates.single_date`\n- `MONTH_NAME`: Full month name (e.g., January)\n- `MONTH_ABBREVIATION`: Abbreviated month name (e.g., Jan)\n- `MONTH`: Month number (e.g., 1)\n- `MONTH_IN_TWO_DIGITS`: Zero-padded month (e.g., 01)\n- `YEAR`: Full year (e.g., 2025)\n- `YEAR_IN_TWO_DIGITS`: Two-digit year (e.g., 25)\n\nThe default value is `*NAME -- PAGE_NUMBER/TOTAL_PAGES*`.", "title": "Footer", "type": "string" }, "top_note": { "default": "*LAST_UPDATED CURRENT_DATE*", - "description": "Template for the top note. Available placeholders: LAST_UPDATED, CURRENT_DATE. The default value is `*LAST_UPDATED CURRENT_DATE*`.", + "description": "Template for the top note. Available placeholders:\n- `LAST_UPDATED`: Localized \"last updated\" text from `locale.last_updated`\n- `CURRENT_DATE`: Formatted date based on `design.templates.single_date`\n- `NAME`: The CV owner's name from `cv.name`\n- `MONTH_NAME`: Full month name (e.g., January)\n- `MONTH_ABBREVIATION`: Abbreviated month name (e.g., Jan)\n- `MONTH`: Month number (e.g., 1)\n- `MONTH_IN_TWO_DIGITS`: Zero-padded month (e.g., 01)\n- `YEAR`: Full year (e.g., 2025)\n- `YEAR_IN_TWO_DIGITS`: Two-digit year (e.g., 25)\n\nThe default value is `*LAST_UPDATED CURRENT_DATE*`.", "title": "Top Note", "type": "string" }, "single_date": { "default": "MONTH_ABBREVIATION YEAR", - "description": "Template for single dates. Available placeholders: MONTH_ABBREVIATION, YEAR. The default value is `MONTH_ABBREVIATION YEAR`.", + "description": "Template for single dates. Available placeholders:\n- `MONTH_NAME`: Full month name (e.g., January)\n- `MONTH_ABBREVIATION`: Abbreviated month name (e.g., Jan)\n- `MONTH`: Month number (e.g., 1)\n- `MONTH_IN_TWO_DIGITS`: Zero-padded month (e.g., 01)\n- `YEAR`: Full year (e.g., 2025)\n- `YEAR_IN_TWO_DIGITS`: Two-digit year (e.g., 25)\n\nThe default value is `MONTH_ABBREVIATION YEAR`.", "title": "Single Date", "type": "string" }, "date_range": { "default": "START_DATE – END_DATE", - "description": "Template for date ranges. Available placeholders: START_DATE, END_DATE. The default value is `START_DATE – END_DATE`.", + "description": "Template for date ranges. Available placeholders:\n- `START_DATE`: Formatted start date based on `design.templates.single_date`\n- `END_DATE`: Formatted end date based on `design.templates.single_date` (or \"present\"/\"ongoing\" for current positions)\n\nThe default value is `START_DATE – END_DATE`.", "title": "Date Range", "type": "string" }, "time_span": { "default": "HOW_MANY_YEARS YEARS HOW_MANY_MONTHS MONTHS", - "description": "Template for time spans. Available placeholders: HOW_MANY_YEARS, YEARS, HOW_MANY_MONTHS, MONTHS. The default value is `HOW_MANY_YEARS YEARS HOW_MANY_MONTHS MONTHS`.", + "description": "Template for time spans (duration calculations). Available placeholders:\n- `HOW_MANY_YEARS`: Number of years (e.g., 2)\n- `YEARS`: Localized word for \"years\" from `locale.years` (or singular \"year\")\n- `HOW_MANY_MONTHS`: Number of months (e.g., 3)\n- `MONTHS`: Localized word for \"months\" from `locale.months` (or singular \"month\")\n\nThe default value is `HOW_MANY_YEARS YEARS HOW_MANY_MONTHS MONTHS`.", "title": "Time Span", "type": "string" }, @@ -4983,31 +4983,31 @@ "properties": { "footer": { "default": "*NAME -- PAGE_NUMBER/TOTAL_PAGES*", - "description": "Template for the footer. Available placeholders: NAME, PAGE_NUMBER, TOTAL_PAGES. The default value is `*NAME -- PAGE_NUMBER/TOTAL_PAGES*`.", + "description": "Template for the footer. Available placeholders:\n- `NAME`: The CV owner's name from `cv.name`\n- `PAGE_NUMBER`: Current page number\n- `TOTAL_PAGES`: Total number of pages\n- `CURRENT_DATE`: Formatted date based on `design.templates.single_date`\n- `MONTH_NAME`: Full month name (e.g., January)\n- `MONTH_ABBREVIATION`: Abbreviated month name (e.g., Jan)\n- `MONTH`: Month number (e.g., 1)\n- `MONTH_IN_TWO_DIGITS`: Zero-padded month (e.g., 01)\n- `YEAR`: Full year (e.g., 2025)\n- `YEAR_IN_TWO_DIGITS`: Two-digit year (e.g., 25)\n\nThe default value is `*NAME -- PAGE_NUMBER/TOTAL_PAGES*`.", "title": "Footer", "type": "string" }, "top_note": { "default": "*LAST_UPDATED CURRENT_DATE*", - "description": "Template for the top note. Available placeholders: LAST_UPDATED, CURRENT_DATE. The default value is `*LAST_UPDATED CURRENT_DATE*`.", + "description": "Template for the top note. Available placeholders:\n- `LAST_UPDATED`: Localized \"last updated\" text from `locale.last_updated`\n- `CURRENT_DATE`: Formatted date based on `design.templates.single_date`\n- `NAME`: The CV owner's name from `cv.name`\n- `MONTH_NAME`: Full month name (e.g., January)\n- `MONTH_ABBREVIATION`: Abbreviated month name (e.g., Jan)\n- `MONTH`: Month number (e.g., 1)\n- `MONTH_IN_TWO_DIGITS`: Zero-padded month (e.g., 01)\n- `YEAR`: Full year (e.g., 2025)\n- `YEAR_IN_TWO_DIGITS`: Two-digit year (e.g., 25)\n\nThe default value is `*LAST_UPDATED CURRENT_DATE*`.", "title": "Top Note", "type": "string" }, "single_date": { "default": "MONTH_ABBREVIATION YEAR", - "description": "Template for single dates. Available placeholders: MONTH_ABBREVIATION, YEAR. The default value is `MONTH_ABBREVIATION YEAR`.", + "description": "Template for single dates. Available placeholders:\n- `MONTH_NAME`: Full month name (e.g., January)\n- `MONTH_ABBREVIATION`: Abbreviated month name (e.g., Jan)\n- `MONTH`: Month number (e.g., 1)\n- `MONTH_IN_TWO_DIGITS`: Zero-padded month (e.g., 01)\n- `YEAR`: Full year (e.g., 2025)\n- `YEAR_IN_TWO_DIGITS`: Two-digit year (e.g., 25)\n\nThe default value is `MONTH_ABBREVIATION YEAR`.", "title": "Single Date", "type": "string" }, "date_range": { "default": "START_DATE – END_DATE", - "description": "Template for date ranges. Available placeholders: START_DATE, END_DATE. The default value is `START_DATE – END_DATE`.", + "description": "Template for date ranges. Available placeholders:\n- `START_DATE`: Formatted start date based on `design.templates.single_date`\n- `END_DATE`: Formatted end date based on `design.templates.single_date` (or \"present\"/\"ongoing\" for current positions)\n\nThe default value is `START_DATE – END_DATE`.", "title": "Date Range", "type": "string" }, "time_span": { "default": "HOW_MANY_YEARS YEARS HOW_MANY_MONTHS MONTHS", - "description": "Template for time spans. Available placeholders: HOW_MANY_YEARS, YEARS, HOW_MANY_MONTHS, MONTHS. The default value is `HOW_MANY_YEARS YEARS HOW_MANY_MONTHS MONTHS`.", + "description": "Template for time spans (duration calculations). Available placeholders:\n- `HOW_MANY_YEARS`: Number of years (e.g., 2)\n- `YEARS`: Localized word for \"years\" from `locale.years` (or singular \"year\")\n- `HOW_MANY_MONTHS`: Number of months (e.g., 3)\n- `MONTHS`: Localized word for \"months\" from `locale.months` (or singular \"month\")\n\nThe default value is `HOW_MANY_YEARS YEARS HOW_MANY_MONTHS MONTHS`.", "title": "Time Span", "type": "string" }, @@ -5040,31 +5040,31 @@ "properties": { "footer": { "default": "*NAME -- PAGE_NUMBER/TOTAL_PAGES*", - "description": "Template for the footer. Available placeholders: NAME, PAGE_NUMBER, TOTAL_PAGES. The default value is `*NAME -- PAGE_NUMBER/TOTAL_PAGES*`.", + "description": "Template for the footer. Available placeholders:\n- `NAME`: The CV owner's name from `cv.name`\n- `PAGE_NUMBER`: Current page number\n- `TOTAL_PAGES`: Total number of pages\n- `CURRENT_DATE`: Formatted date based on `design.templates.single_date`\n- `MONTH_NAME`: Full month name (e.g., January)\n- `MONTH_ABBREVIATION`: Abbreviated month name (e.g., Jan)\n- `MONTH`: Month number (e.g., 1)\n- `MONTH_IN_TWO_DIGITS`: Zero-padded month (e.g., 01)\n- `YEAR`: Full year (e.g., 2025)\n- `YEAR_IN_TWO_DIGITS`: Two-digit year (e.g., 25)\n\nThe default value is `*NAME -- PAGE_NUMBER/TOTAL_PAGES*`.", "title": "Footer", "type": "string" }, "top_note": { "default": "*LAST_UPDATED CURRENT_DATE*", - "description": "Template for the top note. Available placeholders: LAST_UPDATED, CURRENT_DATE. The default value is `*LAST_UPDATED CURRENT_DATE*`.", + "description": "Template for the top note. Available placeholders:\n- `LAST_UPDATED`: Localized \"last updated\" text from `locale.last_updated`\n- `CURRENT_DATE`: Formatted date based on `design.templates.single_date`\n- `NAME`: The CV owner's name from `cv.name`\n- `MONTH_NAME`: Full month name (e.g., January)\n- `MONTH_ABBREVIATION`: Abbreviated month name (e.g., Jan)\n- `MONTH`: Month number (e.g., 1)\n- `MONTH_IN_TWO_DIGITS`: Zero-padded month (e.g., 01)\n- `YEAR`: Full year (e.g., 2025)\n- `YEAR_IN_TWO_DIGITS`: Two-digit year (e.g., 25)\n\nThe default value is `*LAST_UPDATED CURRENT_DATE*`.", "title": "Top Note", "type": "string" }, "single_date": { "default": "MONTH_ABBREVIATION YEAR", - "description": "Template for single dates. Available placeholders: MONTH_ABBREVIATION, YEAR. The default value is `MONTH_ABBREVIATION YEAR`.", + "description": "Template for single dates. Available placeholders:\n- `MONTH_NAME`: Full month name (e.g., January)\n- `MONTH_ABBREVIATION`: Abbreviated month name (e.g., Jan)\n- `MONTH`: Month number (e.g., 1)\n- `MONTH_IN_TWO_DIGITS`: Zero-padded month (e.g., 01)\n- `YEAR`: Full year (e.g., 2025)\n- `YEAR_IN_TWO_DIGITS`: Two-digit year (e.g., 25)\n\nThe default value is `MONTH_ABBREVIATION YEAR`.", "title": "Single Date", "type": "string" }, "date_range": { "default": "START_DATE – END_DATE", - "description": "Template for date ranges. Available placeholders: START_DATE, END_DATE. The default value is `START_DATE – END_DATE`.", + "description": "Template for date ranges. Available placeholders:\n- `START_DATE`: Formatted start date based on `design.templates.single_date`\n- `END_DATE`: Formatted end date based on `design.templates.single_date` (or \"present\"/\"ongoing\" for current positions)\n\nThe default value is `START_DATE – END_DATE`.", "title": "Date Range", "type": "string" }, "time_span": { "default": "HOW_MANY_YEARS YEARS HOW_MANY_MONTHS MONTHS", - "description": "Template for time spans. Available placeholders: HOW_MANY_YEARS, YEARS, HOW_MANY_MONTHS, MONTHS. The default value is `HOW_MANY_YEARS YEARS HOW_MANY_MONTHS MONTHS`.", + "description": "Template for time spans (duration calculations). Available placeholders:\n- `HOW_MANY_YEARS`: Number of years (e.g., 2)\n- `YEARS`: Localized word for \"years\" from `locale.years` (or singular \"year\")\n- `HOW_MANY_MONTHS`: Number of months (e.g., 3)\n- `MONTHS`: Localized word for \"months\" from `locale.months` (or singular \"month\")\n\nThe default value is `HOW_MANY_YEARS YEARS HOW_MANY_MONTHS MONTHS`.", "title": "Time Span", "type": "string" }, @@ -5097,31 +5097,31 @@ "properties": { "footer": { "default": "*NAME -- PAGE_NUMBER/TOTAL_PAGES*", - "description": "Template for the footer. Available placeholders: NAME, PAGE_NUMBER, TOTAL_PAGES. The default value is `*NAME -- PAGE_NUMBER/TOTAL_PAGES*`.", + "description": "Template for the footer. Available placeholders:\n- `NAME`: The CV owner's name from `cv.name`\n- `PAGE_NUMBER`: Current page number\n- `TOTAL_PAGES`: Total number of pages\n- `CURRENT_DATE`: Formatted date based on `design.templates.single_date`\n- `MONTH_NAME`: Full month name (e.g., January)\n- `MONTH_ABBREVIATION`: Abbreviated month name (e.g., Jan)\n- `MONTH`: Month number (e.g., 1)\n- `MONTH_IN_TWO_DIGITS`: Zero-padded month (e.g., 01)\n- `YEAR`: Full year (e.g., 2025)\n- `YEAR_IN_TWO_DIGITS`: Two-digit year (e.g., 25)\n\nThe default value is `*NAME -- PAGE_NUMBER/TOTAL_PAGES*`.", "title": "Footer", "type": "string" }, "top_note": { "default": "*LAST_UPDATED CURRENT_DATE*", - "description": "Template for the top note. Available placeholders: LAST_UPDATED, CURRENT_DATE. The default value is `*LAST_UPDATED CURRENT_DATE*`.", + "description": "Template for the top note. Available placeholders:\n- `LAST_UPDATED`: Localized \"last updated\" text from `locale.last_updated`\n- `CURRENT_DATE`: Formatted date based on `design.templates.single_date`\n- `NAME`: The CV owner's name from `cv.name`\n- `MONTH_NAME`: Full month name (e.g., January)\n- `MONTH_ABBREVIATION`: Abbreviated month name (e.g., Jan)\n- `MONTH`: Month number (e.g., 1)\n- `MONTH_IN_TWO_DIGITS`: Zero-padded month (e.g., 01)\n- `YEAR`: Full year (e.g., 2025)\n- `YEAR_IN_TWO_DIGITS`: Two-digit year (e.g., 25)\n\nThe default value is `*LAST_UPDATED CURRENT_DATE*`.", "title": "Top Note", "type": "string" }, "single_date": { "default": "MONTH_ABBREVIATION YEAR", - "description": "Template for single dates. Available placeholders: MONTH_ABBREVIATION, YEAR. The default value is `MONTH_ABBREVIATION YEAR`.", + "description": "Template for single dates. Available placeholders:\n- `MONTH_NAME`: Full month name (e.g., January)\n- `MONTH_ABBREVIATION`: Abbreviated month name (e.g., Jan)\n- `MONTH`: Month number (e.g., 1)\n- `MONTH_IN_TWO_DIGITS`: Zero-padded month (e.g., 01)\n- `YEAR`: Full year (e.g., 2025)\n- `YEAR_IN_TWO_DIGITS`: Two-digit year (e.g., 25)\n\nThe default value is `MONTH_ABBREVIATION YEAR`.", "title": "Single Date", "type": "string" }, "date_range": { "default": "START_DATE – END_DATE", - "description": "Template for date ranges. Available placeholders: START_DATE, END_DATE. The default value is `START_DATE – END_DATE`.", + "description": "Template for date ranges. Available placeholders:\n- `START_DATE`: Formatted start date based on `design.templates.single_date`\n- `END_DATE`: Formatted end date based on `design.templates.single_date` (or \"present\"/\"ongoing\" for current positions)\n\nThe default value is `START_DATE – END_DATE`.", "title": "Date Range", "type": "string" }, "time_span": { "default": "HOW_MANY_YEARS YEARS HOW_MANY_MONTHS MONTHS", - "description": "Template for time spans. Available placeholders: HOW_MANY_YEARS, YEARS, HOW_MANY_MONTHS, MONTHS. The default value is `HOW_MANY_YEARS YEARS HOW_MANY_MONTHS MONTHS`.", + "description": "Template for time spans (duration calculations). Available placeholders:\n- `HOW_MANY_YEARS`: Number of years (e.g., 2)\n- `YEARS`: Localized word for \"years\" from `locale.years` (or singular \"year\")\n- `HOW_MANY_MONTHS`: Number of months (e.g., 3)\n- `MONTHS`: Localized word for \"months\" from `locale.months` (or singular \"month\")\n\nThe default value is `HOW_MANY_YEARS YEARS HOW_MANY_MONTHS MONTHS`.", "title": "Time Span", "type": "string" }, diff --git a/src/rendercv/renderer/templater/footer_and_top_note.py b/src/rendercv/renderer/templater/footer_and_top_note.py index 1ec2817a..85740afb 100644 --- a/src/rendercv/renderer/templater/footer_and_top_note.py +++ b/src/rendercv/renderer/templater/footer_and_top_note.py @@ -49,6 +49,12 @@ def render_top_note_template( if string_processors is None: string_processors = [] + month_names = locale.month_names + month_abbreviations = locale.month_abbreviations + + month = int(current_date.strftime("%m")) + year = int(current_date.strftime(format="%Y")) + placeholders: dict[str, str] = { "CURRENT_DATE": date_object_to_string( current_date, @@ -57,6 +63,12 @@ def render_top_note_template( ), "LAST_UPDATED": locale.last_updated, "NAME": name or "", + "MONTH_NAME": month_names[month - 1], + "MONTH_ABBREVIATION": month_abbreviations[month - 1], + "MONTH": str(month), + "MONTH_IN_TWO_DIGITS": f"{month:02d}", + "YEAR": str(year), + "YEAR_IN_TWO_DIGITS": str(year)[-2:], } return apply_string_processors( substitute_placeholders(top_note_template, placeholders), string_processors @@ -105,6 +117,12 @@ def render_footer_template( if string_processors is None: string_processors = [] + month_names = locale.month_names + month_abbreviations = locale.month_abbreviations + + month = int(current_date.strftime("%m")) + year = int(current_date.strftime(format="%Y")) + placeholders: dict[str, str] = { "CURRENT_DATE": date_object_to_string( current_date, @@ -114,6 +132,12 @@ def render_footer_template( "NAME": name or "", "PAGE_NUMBER": "#str(here().page())", "TOTAL_PAGES": "#str(counter(page).final().first())", + "MONTH_NAME": month_names[month - 1], + "MONTH_ABBREVIATION": month_abbreviations[month - 1], + "MONTH": str(month), + "MONTH_IN_TWO_DIGITS": f"{month:02d}", + "YEAR": str(year), + "YEAR_IN_TWO_DIGITS": str(year)[-2:], } return ( "context {" diff --git a/src/rendercv/schema/models/design/classic_theme.py b/src/rendercv/schema/models/design/classic_theme.py index cb08c69a..d25f8bff 100644 --- a/src/rendercv/schema/models/design/classic_theme.py +++ b/src/rendercv/schema/models/design/classic_theme.py @@ -600,77 +600,133 @@ class Entries(BaseModelWithoutExtraKeys): ) -template_common_description = ( - "The content of the template. The available placeholders are all the keys used in" - " the entries in uppercase. For example, **TITLE**." -) - - class OneLineEntry(BaseModelWithoutExtraKeys): main_column: str = pydantic.Field( default="**LABEL:** DETAILS", - description=template_common_description - + " The default value is `**LABEL:** DETAILS`.", + description=( + "Template for one-line entries. Available placeholders:\n- `LABEL`: The" + ' label text (e.g., "Languages", "Citizenship")\n- `DETAILS`: The details' + ' text (e.g., "English (native), Spanish (fluent)")\n\nYou can also add' + " arbitrary keys to entries and use them as UPPERCASE placeholders.\n\nThe" + " default value is `**LABEL:** DETAILS`." + ), ) class EducationEntry(BaseModelWithoutExtraKeys): main_column: str = pydantic.Field( default="**INSTITUTION**, AREA\nSUMMARY\nHIGHLIGHTS", - description=template_common_description - + " The default value is `**INSTITUTION**, AREA\\nSUMMARY\\nHIGHLIGHTS`.", + description=( + "Template for education entry main column. Available placeholders:\n-" + " `INSTITUTION`: Institution name\n- `AREA`: Field of study/major\n-" + " `DEGREE`: Degree type (e.g., BS, PhD)\n- `SUMMARY`: Summary text\n-" + " `HIGHLIGHTS`: Bullet points list\n- `LOCATION`: Location text\n- `DATE`:" + " Formatted date or date range\n\nYou can also add arbitrary keys to" + " entries and use them as UPPERCASE placeholders.\n\nThe default value is" + " `**INSTITUTION**, AREA\\nSUMMARY\\nHIGHLIGHTS`." + ), ) degree_column: str | None = pydantic.Field( default="**DEGREE**", description=( - 'If given, a degree column will be added to the education entry. If "null",' - " no degree column will be shown. The available placeholders are all the" - " keys used in the entries (in uppercase). The default value is" + "Optional degree column template. If provided, displays degree in separate" + " column. If `null`, no degree column is shown. Available placeholders:\n-" + " `INSTITUTION`: Institution name\n- `AREA`: Field of study/major\n-" + " `DEGREE`: Degree type (e.g., BS, PhD)\n- `SUMMARY`: Summary text\n-" + " `HIGHLIGHTS`: Bullet points list\n- `LOCATION`: Location text\n- `DATE`:" + " Formatted date or date range\n\nYou can also add arbitrary keys to" + " entries and use them as UPPERCASE placeholders.\n\nThe default value is" " `**DEGREE**`." ), ) date_and_location_column: str = pydantic.Field( default="LOCATION\nDATE", - description=template_common_description - + " The default value is `LOCATION\\nDATE`.", + description=( + "Template for education entry date/location column. Available" + " placeholders:\n- `INSTITUTION`: Institution name\n- `AREA`: Field of" + " study/major\n- `DEGREE`: Degree type (e.g., BS, PhD)\n- `SUMMARY`:" + " Summary text\n- `HIGHLIGHTS`: Bullet points list\n- `LOCATION`: Location" + " text\n- `DATE`: Formatted date or date range\n\nYou can also add" + " arbitrary keys to entries and use them as UPPERCASE placeholders.\n\nThe" + " default value is `LOCATION\\nDATE`." + ), ) class NormalEntry(BaseModelWithoutExtraKeys): main_column: str = pydantic.Field( default="**NAME**\nSUMMARY\nHIGHLIGHTS", - description=template_common_description - + " The default value is `**NAME**\\nSUMMARY\\nHIGHLIGHTS`.", + description=( + "Template for normal entry main column. Available placeholders:\n- `NAME`:" + " Entry name/title\n- `SUMMARY`: Summary text\n- `HIGHLIGHTS`: Bullet" + " points list\n- `LOCATION`: Location text\n- `DATE`: Formatted date or" + " date range\n\nYou can also add arbitrary keys to entries and use them as" + " UPPERCASE placeholders.\n\nThe default value is" + " `**NAME**\\nSUMMARY\\nHIGHLIGHTS`." + ), ) date_and_location_column: str = pydantic.Field( default="LOCATION\nDATE", - description=template_common_description - + " The default value is `LOCATION\\nDATE`.", + description=( + "Template for normal entry date/location column. Available placeholders:\n-" + " `NAME`: Entry name/title\n- `SUMMARY`: Summary text\n- `HIGHLIGHTS`:" + " Bullet points list\n- `LOCATION`: Location text\n- `DATE`: Formatted date" + " or date range\n\nYou can also add arbitrary keys to entries and use them" + " as UPPERCASE placeholders.\n\nThe default value is `LOCATION\\nDATE`." + ), ) class ExperienceEntry(BaseModelWithoutExtraKeys): main_column: str = pydantic.Field( default="**COMPANY**, POSITION\nSUMMARY\nHIGHLIGHTS", - description=template_common_description - + " The default value is `**COMPANY**, POSITION\\nSUMMARY\\nHIGHLIGHTS`.", + description=( + "Template for experience entry main column. Available placeholders:\n-" + " `COMPANY`: Company name\n- `POSITION`: Job title/position\n- `SUMMARY`:" + " Summary text\n- `HIGHLIGHTS`: Bullet points list\n- `LOCATION`: Location" + " text\n- `DATE`: Formatted date or date range\n\nYou can also add" + " arbitrary keys to entries and use them as UPPERCASE placeholders.\n\nThe" + " default value is `**COMPANY**, POSITION\\nSUMMARY\\nHIGHLIGHTS`." + ), ) date_and_location_column: str = pydantic.Field( default="LOCATION\nDATE", - description=template_common_description - + " The default value is `LOCATION\\nDATE`.", + description=( + "Template for experience entry date/location column. Available" + " placeholders:\n- `COMPANY`: Company name\n- `POSITION`: Job" + " title/position\n- `SUMMARY`: Summary text\n- `HIGHLIGHTS`: Bullet points" + " list\n- `LOCATION`: Location text\n- `DATE`: Formatted date or date" + " range\n\nYou can also add arbitrary keys to entries and use them as" + " UPPERCASE placeholders.\n\nThe default value is `LOCATION\\nDATE`." + ), ) class PublicationEntry(BaseModelWithoutExtraKeys): main_column: str = pydantic.Field( default="**TITLE**\nSUMMARY\nAUTHORS\nURL (JOURNAL)", - description=template_common_description - + " The default value is `**TITLE**\\nSUMMARY\\nAUTHORS\\nURL (JOURNAL)`.", + description=( + "Template for publication entry main column. Available placeholders:\n-" + " `TITLE`: Publication title\n- `AUTHORS`: List of authors (formatted as" + " comma-separated string)\n- `SUMMARY`: Summary/abstract text\n- `DOI`:" + " Digital Object Identifier\n- `URL`: Publication URL (if DOI not" + " provided)\n- `JOURNAL`: Journal/conference/venue name\n- `DATE`:" + " Formatted date\n\nYou can also add arbitrary keys to entries and use them" + " as UPPERCASE placeholders.\n\nThe default value is" + " `**TITLE**\\nSUMMARY\\nAUTHORS\\nURL (JOURNAL)`." + ), ) date_and_location_column: str = pydantic.Field( default="DATE", - description=template_common_description + " The default value is `DATE`.", + description=( + "Template for publication entry date column. Available placeholders:\n-" + " `TITLE`: Publication title\n- `AUTHORS`: List of authors (formatted as" + " comma-separated string)\n- `SUMMARY`: Summary/abstract text\n- `DOI`:" + " Digital Object Identifier\n- `URL`: Publication URL (if DOI not" + " provided)\n- `JOURNAL`: Journal/conference/venue name\n- `DATE`:" + " Formatted date\n\nYou can also add arbitrary keys to entries and use them" + " as UPPERCASE placeholders.\n\nThe default value is `DATE`." + ), ) @@ -678,37 +734,66 @@ class Templates(BaseModelWithoutExtraKeys): footer: str = pydantic.Field( default="*NAME -- PAGE_NUMBER/TOTAL_PAGES*", description=( - "Template for the footer. Available placeholders: NAME, PAGE_NUMBER," - " TOTAL_PAGES. The default value is `*NAME -- PAGE_NUMBER/TOTAL_PAGES*`." + "Template for the footer. Available placeholders:\n" + "- `NAME`: The CV owner's name from `cv.name`\n" + "- `PAGE_NUMBER`: Current page number\n" + "- `TOTAL_PAGES`: Total number of pages\n" + "- `CURRENT_DATE`: Formatted date based on `design.templates.single_date`\n" + "- `MONTH_NAME`: Full month name (e.g., January)\n" + "- `MONTH_ABBREVIATION`: Abbreviated month name (e.g., Jan)\n" + "- `MONTH`: Month number (e.g., 1)\n" + "- `MONTH_IN_TWO_DIGITS`: Zero-padded month (e.g., 01)\n" + "- `YEAR`: Full year (e.g., 2025)\n" + "- `YEAR_IN_TWO_DIGITS`: Two-digit year (e.g., 25)\n\n" + "The default value is `*NAME -- PAGE_NUMBER/TOTAL_PAGES*`." ), ) top_note: str = pydantic.Field( default="*LAST_UPDATED CURRENT_DATE*", description=( - "Template for the top note. Available placeholders: LAST_UPDATED," - " CURRENT_DATE. The default value is `*LAST_UPDATED CURRENT_DATE*`." + "Template for the top note. Available placeholders:\n- `LAST_UPDATED`:" + ' Localized "last updated" text from `locale.last_updated`\n-' + " `CURRENT_DATE`: Formatted date based on `design.templates.single_date`\n-" + " `NAME`: The CV owner's name from `cv.name`\n- `MONTH_NAME`: Full month" + " name (e.g., January)\n- `MONTH_ABBREVIATION`: Abbreviated month name" + " (e.g., Jan)\n- `MONTH`: Month number (e.g., 1)\n- `MONTH_IN_TWO_DIGITS`:" + " Zero-padded month (e.g., 01)\n- `YEAR`: Full year (e.g., 2025)\n-" + " `YEAR_IN_TWO_DIGITS`: Two-digit year (e.g., 25)\n\nThe default value is" + " `*LAST_UPDATED CURRENT_DATE*`." ), ) single_date: str = pydantic.Field( default="MONTH_ABBREVIATION YEAR", description=( - "Template for single dates. Available placeholders: MONTH_ABBREVIATION," - " YEAR. The default value is `MONTH_ABBREVIATION YEAR`." + "Template for single dates. Available placeholders:\n" + "- `MONTH_NAME`: Full month name (e.g., January)\n" + "- `MONTH_ABBREVIATION`: Abbreviated month name (e.g., Jan)\n" + "- `MONTH`: Month number (e.g., 1)\n" + "- `MONTH_IN_TWO_DIGITS`: Zero-padded month (e.g., 01)\n" + "- `YEAR`: Full year (e.g., 2025)\n" + "- `YEAR_IN_TWO_DIGITS`: Two-digit year (e.g., 25)\n\n" + "The default value is `MONTH_ABBREVIATION YEAR`." ), ) date_range: str = pydantic.Field( default="START_DATE – END_DATE", description=( - "Template for date ranges. Available placeholders: START_DATE, END_DATE." - " The default value is `START_DATE – END_DATE`." + "Template for date ranges. Available placeholders:\n- `START_DATE`:" + " Formatted start date based on `design.templates.single_date`\n-" + " `END_DATE`: Formatted end date based on `design.templates.single_date`" + ' (or "present"/"ongoing" for current positions)\n\nThe default value is' + " `START_DATE – END_DATE`." ), ) time_span: str = pydantic.Field( default="HOW_MANY_YEARS YEARS HOW_MANY_MONTHS MONTHS", description=( - "Template for time spans. Available placeholders: HOW_MANY_YEARS, YEARS," - " HOW_MANY_MONTHS, MONTHS. The default value is `HOW_MANY_YEARS YEARS" - " HOW_MANY_MONTHS MONTHS`." + "Template for time spans (duration calculations). Available" + " placeholders:\n- `HOW_MANY_YEARS`: Number of years (e.g., 2)\n- `YEARS`:" + ' Localized word for "years" from `locale.years` (or singular "year")\n-' + " `HOW_MANY_MONTHS`: Number of months (e.g., 3)\n- `MONTHS`: Localized word" + ' for "months" from `locale.months` (or singular "month")\n\nThe default' + " value is `HOW_MANY_YEARS YEARS HOW_MANY_MONTHS MONTHS`." ), ) one_line_entry: OneLineEntry = pydantic.Field( diff --git a/tests/cli/render_command/test_run_rendercv.py b/tests/cli/render_command/test_run_rendercv.py index aff572df..176761e7 100644 --- a/tests/cli/render_command/test_run_rendercv.py +++ b/tests/cli/render_command/test_run_rendercv.py @@ -135,7 +135,9 @@ design: with pytest.raises(typer.Exit) as _, progress: run_rendercv(yaml_file, progress) - @pytest.mark.skipif(sys.platform == "win32", reason="chmod doesn't work the same on Windows") + @pytest.mark.skipif( + sys.platform == "win32", reason="chmod doesn't work the same on Windows" + ) def test_os_error_unreadable_file(self, tmp_path): """Test that OSError is properly caught when file is unreadable.""" yaml_file = tmp_path / "unreadable.yaml" diff --git a/tests/renderer/templater/test_entry_templates_from_input.py b/tests/renderer/templater/test_entry_templates_from_input.py index 31d72e9a..80dd4b42 100644 --- a/tests/renderer/templater/test_entry_templates_from_input.py +++ b/tests/renderer/templater/test_entry_templates_from_input.py @@ -159,7 +159,10 @@ class TestProcessDoi: ("This is a summary", "!!! summary\n This is a summary"), ("Short", "!!! summary\n Short"), ("Multi word summary text", "!!! summary\n Multi word summary text"), - ("This is a multi-line summary\nwith two lines", "!!! summary\n This is a multi-line summary\n with two lines"), + ( + "This is a multi-line summary\nwith two lines", + "!!! summary\n This is a multi-line summary\n with two lines", + ), ], ) def test_process_summary(summary, expected): diff --git a/tests/renderer/templater/test_markdown_parser.py b/tests/renderer/templater/test_markdown_parser.py index 91ada979..6b30453e 100644 --- a/tests/renderer/templater/test_markdown_parser.py +++ b/tests/renderer/templater/test_markdown_parser.py @@ -178,7 +178,7 @@ class TestEscapeTypstCharacters: ( "!!! summary\n This is a multi-line summary\n with two lines", "#summary[This is a multi-line summary \\ with two lines]", - ) + ), ], ) def test_markdown_to_typst(markdown_string, expected_typst_string):