Skip to content

Commit

Permalink
Add optional arg. to case commands and keyval BCP47 interface (#936)
Browse files Browse the repository at this point in the history
  • Loading branch information
josephwright committed Oct 26, 2022
1 parent e0f0d7e commit 7447e93
Show file tree
Hide file tree
Showing 32 changed files with 404 additions and 328 deletions.
7 changes: 7 additions & 0 deletions base/changes.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@ completeness or accuracy and it contains some references to files that
are not part of the distribution.
================================================================================

2022-10-26 Joseph Wright <Joseph.Wright@latex-project.org>

* ltfinal.dtx:
Introduce optional argument for case-changing commands
Make case changing commands language-aware
Auto-detect babel locale for case changing

2022-10-22 David Carlisle <David.Carlisle@latex-project.org>

* ltclass.dtx, ltdefns.dtx: Further \protect guards for gh/932
Expand Down
24 changes: 20 additions & 4 deletions base/doc/ltnews36.tex
Original file line number Diff line number Diff line change
Expand Up @@ -221,10 +221,26 @@ \subsection{Encoding subsets for \texttt{TS1} encoded fonts}
%
\githubissue{905}



%\section{New or improved commands}

\section{New or improved commands}

\subsection{Better language handling for case-changing commands}

The commands \cs{MakeUppercase}, \cs{MakeLowercase} and \cs{MakeTitlecase} now
automatically detect the locale currently in use when \pkg{babel} is loaded.
This allows automatic adjustment of letter mappings where appropriate. They
also accept a leading optional argument. This accepts a key--value list of
control settings. At present, there is one key available: \texttt{locale},
which can also be accessed via the alias \texttt{lang}. This are intended to
allow local setting of the language, which can be done using a BCP-47
descriptor. For example, this could be used to force Turkic case changing in
otherwise English input
\begin{verbatim}
\MakeUppercase[lang = tr]{Ragıp Hulûsi Özdem}
\end{verbatim}
yields
\begin{quotation}
\MakeUppercase[lang = tr]{Ragıp Hulûsi Özdem}.
\end{quotation}

\section{Code improvements}

Expand Down
7 changes: 7 additions & 0 deletions base/doc/usrguide.tex
Original file line number Diff line number Diff line change
Expand Up @@ -1166,6 +1166,13 @@ \section{Case changing}
\end{tabular}
\end{quotation}

The case-changing commands take an optional argument which can be used to
tailor the output. This optional argument accepts the key \texttt{locale},
also available under the alias \texttt{lang},
which can be used to give a language identifier in BCP-47
format. This is then applied to select language-specific features during
case-changing.

The input given to these commands is `expanded' before case changing is
applied. This means that any commands within the input that convert to pure
text will be case changed. Mathematical content is automatically excluded, as
Expand Down
60 changes: 53 additions & 7 deletions base/ltfinal.dtx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
%<*driver>
% \fi
\ProvidesFile{ltfinal.dtx}
[2022/08/29 v2.2w LaTeX Kernel (Final Settings)]
[2022/10/26 v2.2x LaTeX Kernel (Final Settings)]
% \iffalse
\documentclass{ltxdoc}
\GetFileInfo{ltfinal.dtx}
Expand Down Expand Up @@ -1085,6 +1085,9 @@
% \changes{v2.2t}{2022/04/21}{Support \cs{noexpand} in argument of \cs{@expl@text@uppercase@@n}}
% \changes{v2.2v}{2022/06/30}{Just use \cs{text_lowercase:n} without \cs{protectd@edf} gh/881x}%
% \changes{v2.2w}{2022/07/04}{Introduced \cs{CaseSwitch}, \cs{DeclareCaseChangeEquivalent} and \cs{MakeTitlecase} to support hooking into case changing gh/889}%
% \changes{v2.2x}{2022/10/26}{Introduce optional argument for case-changing commands}
% \changes{v2.2x}{2022/10/26}{Make case changing commands language-aware}
% \changes{v2.2x}{2022/10/26}{Auto-detect \pkg{babel} locale}
% Wrappers around the L3 case changing functions.
% |\protected| to make them mostly safe as replacements for |uppercase|
% and |\lowercase|.
Expand All @@ -1109,12 +1112,55 @@
% functions.
% \begin{macrocode}
\ExplSyntaxOn
\cs_new_protected_nopar:cpn{MakeUppercase~}{\text_uppercase:n}
\cs_set_nopar:Npx\MakeUppercase#1{\use:c{MakeUppercase~}{#1}}
\cs_new_protected_nopar:cpn{MakeLowercase~}{\text_lowercase:n}
\cs_set_nopar:Npx\MakeLowercase#1{\use:c{MakeLowercase~}{#1}}
\cs_new_protected_nopar:cpn{MakeTitlecase~}{\text_titlecase:n}
\cs_set_nopar:Npx\MakeTitlecase#1{\use:c{MakeTitlecase~}{#1}}
\keys_define:nn { __kernel }
{
lang .str_set:N = \reserved@a ,
locale .str_set:N = \reserved@a
}
\cs_new_protected:Npn \@@text@case@aux #1#2#3
{
\cs_set_nopar:Npn \reserved@a { }
\tl_if_blank:nTF {#2}
{ \@@text@case@aux@ }
{ \keys_set:nn { __kernel } {#2} }
\use:c { text_ #1 case:Vn } \reserved@a {#3}
}
\cs_new_protected:Npn \@@text@case@aux@ { }
\tl_gput_right:Nn \@kernel@after@begindocument
{
\@ifpackageloaded { babel }
{
\@ifpackagelater { babel } { 2020-01-15 }
{
\cs_gset_protected:Npn \@@text@case@aux@
{
\str_set:Nx \reserved@a
{ \localeinfo* { tag.bcp47 } }
}
}
{ }
}
{ }
}
\exp_args_generate:n { cnx }
% \end{macrocode}
% The odd use of \emph{three} spaces here is needed as \pkg{ltcmd} uses the
% name with one and two spaces to give a `friendly' error message for a runaway
% argument: that means we can't use it here.
% \begin{macrocode}
\cs_set_protected:Npn \reserved@a #1
{
\cs_generate_variant:cn { text_ \str_lowercase:n {#1} case:nn } { V }
\cs_new_protected:cpx { Make#1case \c_space_tl \c_space_tl \c_space_tl } [##1] ##2
{ \exp_not:N \@@text@case@aux { \str_lowercase:n {#1} } {##1} {##2} }
\ExpandArgs { cnx } \NewExpandableDocumentCommand
{ Make#1case }
{ O{} +m }
{ \exp_not:c { Make#1case \c_space_tl \c_space_tl \c_space_tl } [####1] {####2} }
}
\reserved@a { Upper }
\reserved@a { Lower }
\reserved@a { Title }
% \end{macrocode}
%
% \changes{v2.2u}{2022/06/02}{Add \cs{NoCaseChange}}
Expand Down
2 changes: 1 addition & 1 deletion base/testfiles-lthooks/ltcmdhooks-001.tlg
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ l. ...\ShowHook{cmd/foo/after}
#1#2->FOO #1 #2.
l. ...\show\foo
> \@kernel@after@begindocument=macro:
->\prop_map_inline:Nn \l_keys_usage_preamble_prop {\clist_map_inline:nn {##2}{\keys_define:nn {##1}{####1.code:n=\msg_error:nnn {keys}{preamble-only}{####1}}}}\__hook_cmd_begindocument_code: \bool_gset_true:N \g__pdf_init_bool \group_begin: \cs_set_protected:Npn \__text_tmp:w ##1{\tl_clear:N \l_text_expand_exclude_tl \tl_map_inline:nn {##1}{\bool_lazy_any:nF {{\token_if_protected_macro_p:N ####1}{\token_if_protected_long_macro_p:N ####1}{\str_if_eq_p:ee {\cs_replacement_spec:N ####1}{\exp_not:n {\protect ####1}\c_space_tl }}}{\tl_put_right:Nn \l_text_expand_exclude_tl {####1}}}}\exp_args:NV \__text_tmp:w \l_text_expand_exclude_tl \exp_args:NNNV \group_end: \tl_set:Nn \l_text_expand_exclude_tl \l_text_expand_exclude_tl \group_begin: \cs_set_protected:Npn \__text_change_case_setup:Nn ##1##2{\quark_if_recursion_tail_stop:N ##1\tl_if_single_token:nT {##2}{\cs_if_exist:cF {c__text_uppercase_\token_to_str:N ##1_tl}{\tl_const:cn {c__text_uppercase_\token_to_str:N ##1_tl}{##2}}\cs_if_exist:cF {c__text_lowercase_\token_to_str:N ##2_tl}{\tl_const:cn {c__text_lowercase_\token_to_str:N ##2_tl}{##1}}}\__text_change_case_setup:Nn }\exp_after:wN \__text_change_case_setup:Nn \@uclclist \q_recursion_tail ?\q_recursion_stop \group_end: .
->\prop_map_inline:Nn \l_keys_usage_preamble_prop {\clist_map_inline:nn {##2}{\keys_define:nn {##1}{####1.code:n=\msg_error:nnn {keys}{preamble-only}{####1}}}}\__hook_cmd_begindocument_code: \bool_gset_true:N \g__pdf_init_bool \group_begin: \cs_set_protected:Npn \__text_tmp:w ##1{\tl_clear:N \l_text_expand_exclude_tl \tl_map_inline:nn {##1}{\bool_lazy_any:nF {{\token_if_protected_macro_p:N ####1}{\token_if_protected_long_macro_p:N ####1}{\str_if_eq_p:ee {\cs_replacement_spec:N ####1}{\exp_not:n {\protect ####1}\c_space_tl }}}{\tl_put_right:Nn \l_text_expand_exclude_tl {####1}}}}\exp_args:NV \__text_tmp:w \l_text_expand_exclude_tl \exp_args:NNNV \group_end: \tl_set:Nn \l_text_expand_exclude_tl \l_text_expand_exclude_tl \group_begin: \cs_set_protected:Npn \__text_change_case_setup:Nn ##1##2{\quark_if_recursion_tail_stop:N ##1\tl_if_single_token:nT {##2}{\cs_if_exist:cF {c__text_uppercase_\token_to_str:N ##1_tl}{\tl_const:cn {c__text_uppercase_\token_to_str:N ##1_tl}{##2}}\cs_if_exist:cF {c__text_lowercase_\token_to_str:N ##2_tl}{\tl_const:cn {c__text_lowercase_\token_to_str:N ##2_tl}{##1}}}\__text_change_case_setup:Nn }\exp_after:wN \__text_change_case_setup:Nn \@uclclist \q_recursion_tail ?\q_recursion_stop \group_end: \@ifpackageloaded {babel}{\@ifpackagelater {babel}{....-..-..}{\cs_gset_protected:Npn \@@text@case@aux@ {\str_set:Nx \reserved@a {\localeinfo *{tag.bcp47}}}}{}}{}.
l. ...\show\@kernel@after@begindocument
Update code for hook 'para/before' on input line ...:
Update code for hook 'para/after' on input line ...:
Expand Down
Loading

0 comments on commit 7447e93

Please sign in to comment.