Hi
a new version attached.
/PA
On 20/09/2026 11:12, Ihor Radchenko wrote:
"Pedro A. Aranda" <[email protected]> writes:
Subject: [PATCH] Add OTHER_LANGUAGES to the metadata
I think the patch is good in general.
+- =OTHER_LANGUAGES= ::
+
+ #+cindex: @samp{OTHER_LANGUAGES}, keyword
+ #+vindex: org-export-other-languages
+ List of secondary languages present in the document.
Nit: "space-separated list".
Fixed
+ For example:
+ #+begin_src org
+,#+LANGUAGE: en
+,#+OTHER_LANGUAGES: es, fr
#+OTHER_LANGUAGES: es fr
+*** New custom variable ~org-export-other-languages~
+
+Org allows you to indicate secondary languages (as opposed to the main
+language stored in ~org-export-default-language~). This variable is a
+lisp of Org language codes and can also be indicated with keyword
Nit: *list
Fixed
+ ;; We might need a function here to translate
from
+ ;; Org to BCP-47 language codes
Nit: We can mark this comment with FIXME: so that it is more visible.
Fixed
+(defcustom org-export-other-languages nil
+ "A list of strings with the Org language codes for other languages
+used in the document.
+
+ox-latex inserts this list as \"other-languages = {<list>}\" in
+the document metadata (along with the export language defined in the
+#+LANGUAGE: keyword as \"language = {<lang>}\"), when the shorthand
+DOC_LANGS is included in `org-latex-doc-metadata'."
I think we should not provide all these details about ox-latex inside a
docstring in ox.el. I suggest describing these details in
`org-latex-doc-metadata' docstring. In ox.el, we can simply refer to
that variable then. WDYT?
Done. The longer description now resides in `org-latex-doc-metadata'
(slightly adapted to the context).
+ :package-version '(Org . "10")
+ :type '(repeat
+ (string :tag "Other languages used in the document."))
The value can also be nil.
Fixed>
+ (let ((doc-metadata (plist-get info :latex-doc-metadata)))
+ (when (and doc-metadata
+ (string-match-p "DOC_LANGS" doc-metadata))
I nice optional feature would be allowing org-latex-doc-metadata value
to be 'auto - populate all the possible the metadata fields.
It can be an equivalent of
#+LATEX_DOC_METADATA: tagging = on, DOC_LANGS
and maybe more things we add in future.
Similar to what we have in org-html-postamble.
Not a blocked for this patch though.
Let's see how things evolve. We don't know what "all possible fields" in
DocumentMetadata{} might look like.
I am not sure if we can simply move it.
Neither was I and the stress was on TOWARDS... And the Rationale in the
commit message, just to show my thoughts.
Unfortunately, it was not fully clear to me that your intention is just
discussing the patch. I interpreted it as the first patch that will
follow by new different patches related to multi-language export to
LaTeX.
Fine, maybe as [DRAFT]? I don't know if the 'automated "burocrazy"' ;-)
would allow this tag.
It would be easier if you clearly stated that the patch is some kind of
"draft". Just for future reference to avoid confusion.
--
Pedro A. Aranda
ox-latex & ox-beamer maintainer
Sagen's Paradeiser! (ORF: Als Radiohören gefährlich war) => write BE!
IA: onomatopeya del rebuzno
2nd year of the New Koprocracy
From 082519966760e747886e98b55a7281cc7bfb9b1f Mon Sep 17 00:00:00 2001
From: "Pedro A. Aranda" <[email protected]>
Date: Sat, 12 Sep 2026 18:03:43 +0200
Subject: [PATCH] Add OTHER_LANGUAGES to the metadata
* doc/org-manual.org : Document the OTHER_LANGUAGES keyword.
* lisp/ox.el (backend): New keyword OTHER_LANGUAGES.
(org-export-other-languages): New variable for the secondary
languages list.
* lisp/ox-latex.el (org-latex--build-metadata-string): New function
to build the metadata from the INFO channel. Treat shorthand DOC_LANGS
to ease defining multiple languages for a document.
(org-latex-make-preamble): Use new function instead of extracting from
the INFO channel directly.
* testing/lisp/test-ox-latex.el (org-latex-make-preamble): Silence first
Metadata test.
(test-ox-latex/metadata-langs): New test, checking the OTHER_LANGUAGES
keyword and the DOC_LANGS shorthand.
(test-ox-latex/example-env-options),
(test-ox-latex/lualatex-fontspec-fallback),
(test-ox-latex/lualatex-fontspec-latex-header-not-lost): Fix #+LANGUAGE
keyword; remove second language there.
Rationale: this is the first step towards adding the new generation
multi-language support with the babel and polyglossia
packages. DocumentMetadata provides a good playground to test language
coding, which might need additions.
---
doc/org-manual.org | 36 +++++++++++++++++++++++++++++++++++
etc/ORG-NEWS | 21 +++++++++++++++++++-
lisp/ox-latex.el | 25 +++++++++++++++++++++++-
lisp/ox.el | 15 +++++++++++++++
testing/lisp/test-ox-latex.el | 33 +++++++++++++++++++++++++++-----
5 files changed, 123 insertions(+), 7 deletions(-)
diff --git a/doc/org-manual.org b/doc/org-manual.org
index f68de4690..91cc5143e 100644
--- a/doc/org-manual.org
+++ b/doc/org-manual.org
@@ -12399,6 +12399,12 @@ global variables, include:
example, Org translates =Table of contents= to the French =Table des
matières=[fn:42].
+- =OTHER_LANGUAGES= ::
+
+ #+cindex: @samp{OTHER_LANGUAGES}, keyword
+ #+vindex: org-export-other-languages
+ List of secondary languages present in the document.
+
- =SELECT_TAGS= ::
#+cindex: @samp{SELECT_TAGS}, keyword
@@ -14421,6 +14427,36 @@ general options (see [[*Export Settings]]).
'("AUTO" "polyglossia" t ("xelatex" "lualatex")))
#+end_src
+- =OTHER_LANGUAGES= ::
+
+ #+cindex: @samp{OTHER_LANGUAGES}, keyword
+ #+vindex: org-export-other-languages
+ #+vindex: org-latex-doc-metadata
+
+ This is the list of secondary languages you want to declare in the
+ document metadata. When the document metadata include the shorthand
+ ~DOC_LANGS~, it will be replaced by the main language declared with
+ the ~LANGUAGE~ keyword and this list.
+
+ For example:
+ #+begin_src org
+,#+LANGUAGE: en
+,#+OTHER_LANGUAGES: es, fr
+,#+LATEX_DOC_METADATA: tagging = on, DOC_LANGS
+ #+end_src
+
+ will result in
+ #+BEGIN_SRC latex
+\DocumentMetadata{tagging=on, language=en, other-languages={es, fr}}
+ #+END_SRC
+ as the first line of the LaTeX preamble *before* the document class
+ declaration.
+
+ *NOTE:* In the absence of a declaration for ~OTHER_LANGUAGES~, the
+ language declared with the ~LANGUAGE~ keyword will be the only one
+ added to the metadata, when ~DOC_LANGS~ is found in
+ ~LATEX_DOC_METADATA~.
+
- =LATEX_CLASS= ::
#+cindex: @samp{LATEX_CLASS}, keyword
diff --git a/etc/ORG-NEWS b/etc/ORG-NEWS
index 80cd17ba6..4b1dff252 100644
--- a/etc/ORG-NEWS
+++ b/etc/ORG-NEWS
@@ -252,7 +252,7 @@ keywords or with =#+OPTIONS:=.
Option keys can be used like this:
: #+OPTIONS: html-self-link-headlines:t
: #+OPTIONS: html-tag-class-prefix:"myorg-"
-
+
To know which value you can use, find the allowed option values in the
manual or in the default variable documentation.
@@ -431,6 +431,25 @@ description are always previewed by ~org-link-preview~. When set to
non-nil, previewing links with description will not require =[C-u 1]=
toggle.
+*** New custom variable ~org-export-other-languages~
+
+Org allows you to indicate secondary languages (as opposed to the main
+language stored in ~org-export-default-language~). This variable is a
+lisp of Org language codes and can also be indicated with keyword
+~#+OTHER_LANGUAGES~, for example:
+
+#+BEGIN_SRC org
+,#+LANGUAGE: en
+,#+OTHER_LANGUAGES: es de
+#+END_SRC
+
+indicates that the document is mainly written in American English and
+includes passages in Spanish and German.
+
+It is up to the exporters to use this variable or not. Currently, it
+is used to add language information in the PDF metadata when exporting
+through ox-latex or ox-beamer.
+
** New functions and changes in function arguments
# This also includes changes in function behavior from Elisp perspective.
diff --git a/lisp/ox-latex.el b/lisp/ox-latex.el
index 56ca3ada9..5c9906975 100644
--- a/lisp/ox-latex.el
+++ b/lisp/ox-latex.el
@@ -665,6 +665,29 @@ (defcustom org-latex-doc-metadata nil
(string :tag "Metadata for the PDF output"))
:safe #'string-or-null-p)
+
+(defun org-latex--build-metadata-string (info)
+ "Extract the document metadata from INFO and handle language info.
+
+When metadata are defined and contain the keyword DOC_LANGS, replace it with
+\"language=<main>[, other-languages={<other>}]\", where <main> is defined in
+#+LANGUAGE and <other> is defined in #+OTHER_LANGUAGES. Omit the other-languages
+if not defined.
+
+Cf. URL `https://latex3.github.io/babel/news/whats-new-in-babel-26.9.html'."
+ (let ((doc-metadata (plist-get info :latex-doc-metadata)))
+ (when (and doc-metadata
+ (string-match-p "DOC_LANGS" doc-metadata))
+ (let* ((replace-other (plist-get info :other-languages))
+ (replace-other (and replace-other
+ ;; We might need a function here to translate from
+ ;; Org to BCP-47 language codes
+ (mapconcat #'identity replace-other ", ")))
+ (replace-langs (concat "language=" (plist-get info :language)
+ (and replace-other (concat ", other-languages={ " replace-other " }")))))
+ (setq doc-metadata (string-replace "DOC_LANGS" replace-langs doc-metadata))))
+ doc-metadata))
+
;;;; Headline
(defcustom org-latex-format-headline-function
@@ -2247,7 +2270,7 @@ (defun org-latex-make-preamble (info &optional template snippet?)
specified in `org-latex-default-packages-alist' or
`org-latex-packages-alist'."
(let* ((class (plist-get info :latex-class))
- (doc-metadata (plist-get info :latex-doc-metadata))
+ (doc-metadata (org-latex--build-metadata-string info))
(class-template
(or template
(let* ((class-options (org-latex--mk-options (plist-get info :latex-class-options)))
diff --git a/lisp/ox.el b/lisp/ox.el
index 182aefc1b..b3782be99 100644
--- a/lisp/ox.el
+++ b/lisp/ox.el
@@ -112,6 +112,7 @@ (defconst org-export-options-alist
(:author "AUTHOR" nil user-full-name parse)
(:email "EMAIL" nil user-mail-address t)
(:language "LANGUAGE" nil org-export-default-language t)
+ (:other-languages "OTHER_LANGUAGES" nil org-export-other-languages split)
(:select-tags "SELECT_TAGS" nil org-export-select-tags split)
(:exclude-tags "EXCLUDE_TAGS" nil org-export-exclude-tags split)
(:creator "CREATOR" nil org-export-creator-string)
@@ -553,6 +554,20 @@ (defcustom org-export-default-language "en"
:type '(string :tag "Language")
:safe #'stringp)
+(defcustom org-export-other-languages nil
+ "A list of strings with the Org language codes for other languages
+used in the document.
+
+ox-latex inserts this list as \"other-languages = {<list>}\" in
+the document metadata (along with the export language defined in the
+#+LANGUAGE: keyword as \"language = {<lang>}\"), when the shorthand
+DOC_LANGS is included in `org-latex-doc-metadata'."
+
+ :package-version '(Org . "10")
+ :type '(repeat
+ (string :tag "Other languages used in the document."))
+ :safe #'string-or-null-p)
+
(defcustom org-export-preserve-breaks nil
"Non-nil means preserve all line breaks when exporting.
This option can also be set with the OPTIONS keyword,
diff --git a/testing/lisp/test-ox-latex.el b/testing/lisp/test-ox-latex.el
index 9cd83d509..24ef90b4a 100644
--- a/testing/lisp/test-ox-latex.el
+++ b/testing/lisp/test-ox-latex.el
@@ -527,7 +527,8 @@ (ert-deftest test-ox-latex/pdf-metadata ()
(org-test-with-exported-text
'latex
"#+TITLE: PDF Metadata
-#+LANGUAGE: en-gb es
+#+LANGUAGE: en-gb
+#+OTHER_LANGUAGE: es
#+OPTIONS: toc:nil H:3 num:nil
#+LATEX_COMPILER: pdflatex
#+LATEX_DOC_METADATA: tagging = on
@@ -537,12 +538,34 @@ (ert-deftest test-ox-latex/pdf-metadata ()
Just to see that DocumentMetadata comes before PassOptions and documentclass
"
- (message "pdf-metadata: %s" (buffer-string))
+ ;; (message "pdf-metadata: %s" (buffer-string))
(goto-char (point-min))
(should (search-forward "\\DocumentMetadata{tagging = on}" nil t))
(should (search-forward "\\PassOptionsToPackage{dvipsnames}{xcolor}" nil t))
(should (re-search-forward "^\\\\documentclass\\[.+?]{report}" nil t))))
+(ert-deftest test-ox-latex/metadata-langs ()
+ "Test that DocumentMetadata treat the DOC_LANGS keyword correctly."
+ (org-test-with-exported-text
+ 'latex
+ "#+TITLE: PDF Metadata with languages
+#+LANGUAGE: en
+#+OTHER_LANGUAGES: es fr
+#+OPTIONS: toc:nil H:3 num:nil
+#+LATEX_COMPILER: pdflatex
+#+LATEX_DOC_METADATA: tagging = on,
+#+LATEX_DOC_METADATA: DOC_LANGS
+#+LATEX_CLASS: report
+* Testing
+
+Just to see that DocumentMetadata has the right languages
+"
+ ;; (message "pdf-metadata: %s" (buffer-string))
+ (goto-char (point-min))
+ (should (search-forward "\\DocumentMetadata{tagging = on," nil t))
+ (should (search-forward "language=en, other-languages={ es, fr }}" nil t))
+ (should (re-search-forward "^\\\\documentclass\\[.+?]{report}" nil t))))
+
(ert-deftest test-ox-latex/example-env-options ()
"We can set and override the options in an EXAMPLE block."
(let ((org-latex-default-example-environment "Verbatim")
@@ -587,7 +610,7 @@ (ert-deftest test-ox-latex/lualatex-fontspec-recognised ()
(org-test-with-exported-text
'latex
"#+TITLE: LuaLaTeX fonts
-#+LANGUAGE: en-gb es
+#+LANGUAGE: en-gb
#+OPTIONS: toc:nil H:3 num:nil
#+LATEX_COMPILER: lualatex
#+LATEX_CLASS: report
@@ -611,7 +634,7 @@ (ert-deftest test-ox-latex/lualatex-fontspec-fallback ()
(org-test-with-exported-text
'latex
"#+TITLE: LuaLaTeX fonts with emojis
-#+LANGUAGE: en-gb es
+#+LANGUAGE: en-gb
#+OPTIONS: toc:nil H:3 num:nil
#+LATEX_COMPILER: lualatex
#+LATEX_CLASS: report
@@ -639,7 +662,7 @@ (ert-deftest test-ox-latex/lualatex-fontspec-latex-header-not-lost ()
(org-test-with-exported-text
'latex
"#+TITLE: LuaLaTeX fonts
-#+LANGUAGE: en-gb es
+#+LANGUAGE: en-gb
#+OPTIONS: toc:nil H:3 num:nil
#+LATEX_COMPILER: lualatex
#+LATEX_HEADER: \\setsansfont{TeX Gyre Heros}
--
2.43.0