\RequirePackage{expl3} \ProvidesExplPackage{changelog}{2024/12/18}{2.6.0}{Typesetting changelogs} % Description: Provides the changelog environment for typesetting changelogs % License: LPPL 1.3c % Homepage: https://github.com/9999years/latex-changelog % https://ctan.org/pkg/changelog % Maintainer: Rebecca Turner % % This work may be distributed and/or modified under the % conditions of the LaTeX Project Public License, either version 1.3 % of this license or (at your option) any later version. % The latest version of this license is in % http://www.latex-project.org/lppl.txt % and version 1.3 or later is part of all distributions of LaTeX % version 2005/12/01 or later. % % This work has the LPPL maintenance status `maintained'. % % The Current Maintainer of this work is Rebecca Turner . % % This work consists of the files changelog.sty and changelog.tex. \RequirePackage{translations} % See https://github.com/olivierlacan/keep-a-changelog/issues/195 % for a discussion about the term yanked % Fallback translations will be used if there is no translation for % the current document language \DeclareTranslationFallback{changelog}{Changelog} \DeclareTranslationFallback{changelog-Added}{Added} \DeclareTranslationFallback{changelog-Changed}{Changed} \DeclareTranslationFallback{changelog-Deprecated}{Deprecated} \DeclareTranslationFallback{changelog-Removed}{Removed} \DeclareTranslationFallback{changelog-Fixed}{Fixed} \DeclareTranslationFallback{changelog-Security}{Security} \DeclareTranslationFallback{changelog-Miscellaneous}{Miscellaneous} \DeclareTranslationFallback{changelog-Unreleased}{Unreleased} \DeclareTranslationFallback{changelog-Yanked}{YANKED} % English translations by Rebecca Turner \DeclareTranslation{English}{changelog}{Changelog} \DeclareTranslation{English}{changelog-Added}{Added} \DeclareTranslation{English}{changelog-Changed}{Changed} \DeclareTranslation{English}{changelog-Deprecated}{Deprecated} \DeclareTranslation{English}{changelog-Removed}{Removed} \DeclareTranslation{English}{changelog-Fixed}{Fixed} \DeclareTranslation{English}{changelog-Security}{Security} \DeclareTranslation{English}{changelog-Miscellaneous}{Miscellaneous} \DeclareTranslation{English}{changelog-Unreleased}{Unreleased} \DeclareTranslation{English}{changelog-Yanked}{YANKED} % German translations by Holger Schieferdecker % Alternative german translations as comment at the end of the line \DeclareTranslation{German}{changelog}{\"Anderungsnachweis} \DeclareTranslation{German}{changelog-Added}{Hinzugef\"{u}gt}% Neu \DeclareTranslation{German}{changelog-Changed}{Ge\"{a}ndert} \DeclareTranslation{German}{changelog-Deprecated}{Überholt}% Veraltet \DeclareTranslation{German}{changelog-Removed}{Entfernt} \DeclareTranslation{German}{changelog-Fixed}{Behoben}% Fehlerbehebung \DeclareTranslation{German}{changelog-Security}{Sicherheit} \DeclareTranslation{German}{changelog-Miscellaneous}{Verschiedenes} \DeclareTranslation{German}{changelog-Unreleased}{Unver\"{o}ffentlicht} \DeclareTranslation{German}{changelog-Yanked}{Zur{\"u}ckgezogen} % Spanish translations by David Arnold \DeclareTranslation{Spanish}{changelog}{Registro de cambios} \DeclareTranslation{Spanish}{changelog-Added}{Agregado} \DeclareTranslation{Spanish}{changelog-Changed}{Cambiado} \DeclareTranslation{Spanish}{changelog-Deprecated}{Obsoleto} \DeclareTranslation{Spanish}{changelog-Removed}{Removido} \DeclareTranslation{Spanish}{changelog-Fixed}{Arreglado} \DeclareTranslation{Spanish}{changelog-Security}{Seguridad} \DeclareTranslation{Spanish}{changelog-Miscellaneous}{Miscel{\'a}neo} \DeclareTranslation{Spanish}{changelog-Unreleased}{No Publicado} \DeclareTranslation{Spanish}{changelog-Yanked}{REVOCADO} % French translations by Damien Calesse \DeclareTranslation{French}{changelog}{Journal des modifications} \DeclareTranslation{French}{changelog-Added}{Ajouté} \DeclareTranslation{French}{changelog-Changed}{Modifié} \DeclareTranslation{French}{changelog-Deprecated}{Déprécié} \DeclareTranslation{French}{changelog-Removed}{Supprimé} \DeclareTranslation{French}{changelog-Fixed}{Corrigé} \DeclareTranslation{French}{changelog-Security}{Sécurité} \DeclareTranslation{French}{changelog-Miscellaneous}{Divers} \DeclareTranslation{French}{changelog-Unreleased}{Non publié} \DeclareTranslation{French}{changelog-Yanked}{Annulé} % Japanese translations by cmplstofB \DeclareTranslation{Japanese}{changelog}{変更履歴} \DeclareTranslation{Japanese}{changelog-Added}{追加} \DeclareTranslation{Japanese}{changelog-Changed}{変更} \DeclareTranslation{Japanese}{changelog-Deprecated}{非推奨} \DeclareTranslation{Japanese}{changelog-Removed}{削除} \DeclareTranslation{Japanese}{changelog-Fixed}{修正} \DeclareTranslation{Japanese}{changelog-Security}{安全性} \DeclareTranslation{Japanese}{changelog-Miscellaneous}{雑題} \DeclareTranslation{Japanese}{changelog-Unreleased}{未公開} \DeclareTranslation{Japanese}{changelog-Yanked}{緊急変更} \msg_new:nnnn { changelog } { missing_section } { Something's~wrong~in~version~environment;~perhaps~a~missing~ \protect\added,~\protect\changed,~\protect\deprecated,~ \protect\removed,~\protect\fixed,~\protect\security,~ or~\protect\misc? } { A~version~environment~needs~to~introduce~its~ \protect\item-ized~lists~with~one~of~the~provided~section~commands;~ maybe~you~meant~to~use~the~[simple]~option? } \msg_new:nnnn { changelog } { missing_version } { No~versions~listed~in~changelog~environment~body. } { A~changelog~environment~must~have~at~least~one~version~environment~or~ \protect\shortversion~command~in~it. } \bool_new:N \g__changelog_version_first_bool \cs_set:Npn \changelog__item:n #1 { \noindent \bool_if:NTF \g__changelog_version_first_bool { \bool_gset_false:N \g__changelog_version_first_bool } { \end{changelogitemize} } \textbf{#1} \begin{changelogitemize} } \cs_set:Npn \changelogremark #1 { \fbox{\textbf{#1}} } \cs_set:Npn \changelogyanked { \changelogremark{\GetTranslation{changelog-Yanked}} } \tl_new:N \g__changelog_extra_section_cmds \cs_set:Npn \changelog__define_section_cmds { \cs_set:Npn \added {\changelog__item:n{\GetTranslation{changelog-Added}}} \cs_set:Npn \changed {\changelog__item:n{\GetTranslation{changelog-Changed}}} \cs_set:Npn \deprecated {\changelog__item:n{\GetTranslation{changelog-Deprecated}}} \cs_set:Npn \removed {\changelog__item:n{\GetTranslation{changelog-Removed}}} \cs_set:Npn \fixed {\changelog__item:n{\GetTranslation{changelog-Fixed}}} \cs_set:Npn \security {\changelog__item:n{\GetTranslation{changelog-Security}}} \cs_set:Npn \misc {\changelog__item:n{\GetTranslation{changelog-Miscellaneous}}} \tl_use:N \g__changelog_extra_section_cmds } \NewDocumentCommand{\newchangelogsection}{m m} { \tl_gput_right:Nn \g__changelog_extra_section_cmds { \cs_set:Npn #1 { \changelog__item:n { #2 } } } } \keys_define:nn { changelog_version } { author .tl_set:N = \g__changelog_author_tl , v .tl_set:N = \g__changelog_version_tl , version .tl_set:N = \g__changelog_version_tl , date .tl_set:N = \g__changelog_date_tl , changes .tl_set:N = \g__changelog_changes_tl , yanked .bool_set:N = \g__changelog_yanked_bool , simple .bool_set:N = \g__changelog_simple_bool , short .bool_set:N = \g__changelog_short_bool , remark .tl_set:N = \g__changelog_remark_tl , remarks .clist_set:N = \g__changelog_remarks_clist , } \keys_define:nn { changelog_changelog } { sectioncmd .tl_set:N = \g__changelog_sectioncmd_tl , sectioncmd .initial:n = \section , title .tl_set:N = \g__changelog_title_tl , title .initial:n = \GetTranslation{changelog} , label .tl_set:N = \g__changelog_label_tl , label .initial:n = sec:changelog , section .bool_gset:N = \g__changelog_section_bool , section .initial:n = true , } \keys_define:nn { } { changelog_changelog .inherit:n = changelog_version } \newenvironment{changelogdescription} {\begin{description}} {\end{description}} \newenvironment{changelogitemize} {\begin{itemize}} {\end{itemize}} \cs_set:Npn \changelog__section_maybe { \bool_if:NTF \g__changelog_section_bool { \exp_after:wN \g__changelog_sectioncmd_tl { \g__changelog_title_tl } \tl_if_empty:NF \g__changelog_label_tl { \exp_after:wN \label { \tl_use:N \g__changelog_label_tl } } } {} } % Display the current version, which may be a version number, a date, or "Unreleased". \cs_set:Npn \changelog__display_version { \tl_if_empty:NTF \g__changelog_version_tl { \tl_if_empty:NTF \g__changelog_date_tl { \GetTranslation{changelog-Unreleased} \tl_set:Nn \g__changelog_date_tl { \today } } { \tl_use:N \g__changelog_date_tl } } { \tl_use:N \g__changelog_version_tl } } \cs_set:Npn \changelog__short_version_item { \changelog__display_version \bool_if:NT \g__changelog_yanked_bool { \ \changelogyanked } \tl_if_empty:NF \g__changelog_remark_tl { \ \changelogremark{\tl_use:N \g__changelog_remark_tl} } \clist_if_empty:NF \g__changelog_remarks_clist { \clist_map_variable:NNn \g__changelog_remarks_clist \l__changelog_remark_tl { \ \changelogremark{\tl_use:N \l__changelog_remark_tl} } } } \cs_set:Npn \changelog__short_version_author_date { % This might output nothing if there's no author and the date is being used % as a version number, so make sure to `\leavevmode` to avoid a weird % indent at the start of the item. \mode_leave_vertical: \tl_use:N \g__changelog_author_tl \tl_if_empty:NF \g__changelog_date_tl { % If no version number is given, the date is used instead, so we don't % want to show the date twice. \tl_if_empty:NF \g__changelog_version_tl { \tl_if_empty:NF \g__changelog_author_tl { ~ } (\tl_use:N \g__changelog_date_tl) } } } \cs_set:Npn \changelog__version_pre { \par \bool_gset_true:N \g__changelog_version_first_bool \changelog__define_section_cmds \bool_if:NT \g__changelog_simple_bool { \begin{changelogitemize} } } \cs_set:Npn \changelog__version_post { \bool_if:NT \g__changelog_version_first_bool { \bool_if:NF \g__changelog_simple_bool { \msg_error:nn { changelog } { missing_section } } } \end{changelogitemize} } \bool_new:N \g__changelog_seen_version_bool \NewDocumentEnvironment{changelog}{o} { \bool_gset_false:N \g__changelog_seen_version_bool \IfValueT{#1}{\keys_set:nn{changelog_changelog}{#1}} \changelog__section_maybe % Define the version environment, which wraps an `itemize`-style list. \NewDocumentEnvironment{version}{ O{} } { \keys_set:nn { changelog_version } { ##1 } \changelog__short_version \bool_if:NF \g__changelog_short_bool { \changelog__version_pre } } { \bool_if:NF \g__changelog_short_bool { \changelog__version_post } } % doesn't set keys so this can share code with the version % environment \cs_set:Npn \changelog__short_version { \bool_gset_true:N \g__changelog_seen_version_bool \item[\changelog__short_version_item] \changelog__short_version_author_date \bool_if:NT \g__changelog_short_bool { \ ---\ \tl_use:N \g__changelog_changes_tl } } % A short version; "like a 1-bullet list. \NewDocumentCommand{\shortversion}{m} % The extra braces here keep the keys we set local. {{ \keys_set:nn{changelog_version}{##1, short} \changelog__short_version }} \begin{changelogdescription} } { \bool_if:NF \g__changelog_seen_version_bool { \msg_error:nn { changelog } { missing_version } } \end{changelogdescription} }