Add separate functions to sort index entries and cache in converters

* tta/C/Makefile.am (C_libtexinfo_convert_sources): add
tta/C/convert/convert_indices.c.

* tta/C/convert/convert_indices.c (new_index_entry_text_or_command)
(idx_leading_text_or_command)
(index_entry_first_letter_text_or_command): move to convert_indices.c,
since index_entry_first_letter_text_or_command should only be called
from converters.

* tta/C/main/document.c (document_sorted_indices_by_index)
(document_sorted_indices_by_letter): rename sorted_indices_by_index as
document_sorted_indices_by_index and sorted_indices_by_letter as
document_sorted_indices_by_letter.

* tta/C/main/manipulate_indices.c (document_index_content_element),
tta/perl/Texinfo/Indices.pm (document_index_content_element):
rename index_content_element as document_index_content_element.

* tta/perl/Texinfo/DocumentNonXS.pm (document_indices_sort_strings):
remove indices_sort_strings as document_indices_sort_strings.  Update
callers.

* tta/C/main/manipulate_indices.c (get_index_content_info_element)
(document_index_content_element), tta/perl/Texinfo/Indices.pm
(get_index_content_info_element, document_index_content_element):
add get_index_content_info_element that gets index content element for
the cases where translation is not needed, and also gets information
on object-oriented definitions that can be used by the caller to
prepare an index content element.  Remove def_command_index_entry.

* tta/C/main/manipulate_indices.c (entry_tree_element_sort_string)
(index_entry_element_sort_string): add entry_tree_element_sort_string
based on index_entry_element_sort_string code.

* tta/C/main/manipulate_indices.c (setup_index_entries_sort_strings):
add index_entry_element_sort_string_fn argument to be able
to use a different function than the index_entry_element_sort_string
default, when called from converters.  A function argument instead of
a call to a function if converter argument is set is used to avoid
depending on the libtexinfo-converter library.

* tta/C/main/document.c (document_sorted_indices_by_index)
(document_sorted_indices_by_letter),
tta/C/main/manipulate_indices.c (new_collation_sorted_indices_by_index)
(new_base_collations_sorted_indices_by_index)
(get_collation_sorted_indices_by_index)
(new_base_collations_sorted_indices_by_letter)
(get_collation_sorted_indices_by_letter):
add new_base_collations_sorted_indices_by_index,
get_collation_sorted_indices_by_index,
new_base_collations_sorted_indices_by_letter and
get_collation_sorted_indices_by_letter based on
document_sorted_indices_by_* code and call these functions.
move new_collation_sorted_indices_by_index,
find_collation_sorted_indices_by_index,
new_collation_sorted_indices_by_letter and
find_collation_sorted_indices_by_letter to manipulate_indices.c.

* tta/C/main/document.c (document_sorted_indices_by_index)
(document_sorted_indices_by_letter), tta/C/main/manipulate_indices.c
(sort_indices_by_index) (sort_indices_by_letter,
setup_sort_sortable_strings_collator), tta/perl/Texinfo/Document.pm
(sorted_indices_by_letter) (sorted_indices_by_index),
tta/perl/Texinfo/Indices.pm (_setup_sort_sortable_strings_collator)
(sort_indices_by_index, sort_indices_by_letter):
use indices_sort_strings as argument to sort_indices_by_index,
sort_indices_by_letter and setup_sort_sortable_strings_collator, do
not call document_indices_sort_strings in those functions, but in
document_sorted_indices_by_index, document_sorted_indices_by_letter
before calling sort_indices_by_index or sort_indices_by_letter.

* tta/C/convert/converter.c
(converter_index_entry_element_sort_string)
(converter_indices_sort_strings, converter_sorted_indices_by_index)
(get_converter_indices_sorted_by_index)
(converter_sorted_indices_by_letter)
(get_converter_indices_sorted_by_letter),
tta/C/convert/convert_indices.c (converter_index_content_element)
(index_entry_first_letter_text_or_command),
tta/C/main/converter_types.h (CONVERTER),
tta/C/main/manipulate_indices.c (document_index_content_element),
tta/perl/Texinfo/Convert/Converter.pm (converter_indices_sort_strings)
(_converter_sorted_indices_by_letter)
(_converter_sorted_indices_by_index),
tta/perl/Texinfo/Convert/ConverterNonXS.pm
(get_converter_indices_sorted_by_letter)
(get_converter_indices_sorted_by_index),
tta/perl/Texinfo/Indices.pm (converter_index_content_element),
tta/perl/Texinfo/IndicesNonXS.pm (index_entry_element_sort_string): add
index sorting functions for converters that cache in the converter,
using the new fields indices_sort_strings, sorted_indices_by_index and
sorted_indices_by_letter, and use converter information.  Use those
functions in get_converter_indices_sorted_by_*, in
index_entry_first_letter_text_or_command and in converters.
Remove document_index_content_element converter and consider only the
case of no converter in this function. Update
callers, replacing index_content_element by
converter_index_content_element in converters.  Remove
index_content_element.

* tta/C/main/document.c (document_indices_sort_strings),
tta/perl/Texinfo/Document.pm (sorted_indices_by_letter)
(sorted_indices_by_index), tta/perl/Texinfo/DocumentNonXS.pm
(document_indices_sort_strings), tta/perl/Texinfo/Indices.pm
(sort_indices_by_index, sort_indices_by_letter),
tta/perl/XSTexinfo/parser_document/DocumentXS.xs
(document_indices_sort_strings): remove converter
argument.  Update callers.

* tta/perl/XSTexinfo/parser_document/DocumentXS.xs
(setup_indices_sort_strings): never use the converter argument.

* tta/C/convert/texinfo.c (txi_complete_document),
tta/perl/texi2any.pl: do not call document_indices_sort_strings or
Document::setup_indices_sort_strings in advance anymore, as the sorted
index entries used by converters are not in the document anymore.

* tta/C/main/manipulate_indices.c (destroy_sorted_indices_by_index)
(destroy_sorted_indices_by_letter), tta/C/main/document.c
(destroy_document_information_except_tree): add
destroy_sorted_indices_by_index and destroy_sorted_indices_by_letter
based on destroy_document_information_except_tree code.

* tta/perl/Texinfo/Convert/Converter.pm (conversion_initialization),
tta/perl/Texinfo/Convert/DocBook.pm (converter_initialize),
tta/perl/Texinfo/Convert/LaTeX.pm (conversion_initialization),
tta/perl/Texinfo/Convert/Plaintext.pm (conversion_initialization):
call set_document even if document is undef, to get the other
initialization/destructions.

* tta/C/convert/converter.c (destroy_converter_index_sorting)
(converter_set_document, free_generic_converter),
tta/C/main/build_perl_info.c (pass_document_sv_to_converter_sv),
tta/perl/Texinfo/Convert/Converter.pm (converter_perl_release),
tta/perl/Texinfo/Convert/ConverterNonXS.pm (set_document):
destroy index sorting information set in converter.  Destroy document
in set_document if input document is undef.

* tta/C/convert/converter.c (element_cdt_tree): add and call
html_element_cdt_tree from this function only and call this function
directly in converter_index_content_element.  Remove all the now
unneeded element_cdt_tree_fn arguments.

* tta/perl/t/z_misc/test_sort.t: update.
diff --git a/ChangeLog b/ChangeLog
index 54db153..4de2811 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,152 @@
+2026-06-16 Patrice Dumas  <pertusus@free.fr>
+
+	Add separate functions to sort index entries and cache in converters
+
+	* tta/C/Makefile.am (C_libtexinfo_convert_sources): add
+	tta/C/convert/convert_indices.c.
+
+	* tta/C/convert/convert_indices.c (new_index_entry_text_or_command)
+	(idx_leading_text_or_command)
+	(index_entry_first_letter_text_or_command): move to convert_indices.c,
+	since index_entry_first_letter_text_or_command should only be called
+	from converters.
+
+	* tta/C/main/document.c (document_sorted_indices_by_index)
+	(document_sorted_indices_by_letter): rename sorted_indices_by_index as
+	document_sorted_indices_by_index and sorted_indices_by_letter as
+	document_sorted_indices_by_letter.
+
+	* tta/C/main/manipulate_indices.c (document_index_content_element),
+	tta/perl/Texinfo/Indices.pm (document_index_content_element):
+	rename index_content_element as document_index_content_element.
+
+	* tta/perl/Texinfo/DocumentNonXS.pm (document_indices_sort_strings):
+	remove indices_sort_strings as document_indices_sort_strings.  Update
+	callers.
+
+	* tta/C/main/manipulate_indices.c (get_index_content_info_element)
+	(document_index_content_element), tta/perl/Texinfo/Indices.pm
+	(get_index_content_info_element, document_index_content_element):
+	add get_index_content_info_element that gets index content element for
+	the cases where translation is not needed, and also gets information
+	on object-oriented definitions that can be used by the caller to
+	prepare an index content element.  Remove def_command_index_entry.
+
+	* tta/C/main/manipulate_indices.c (entry_tree_element_sort_string)
+	(index_entry_element_sort_string): add entry_tree_element_sort_string
+	based on index_entry_element_sort_string code.
+
+	* tta/C/main/manipulate_indices.c (setup_index_entries_sort_strings):
+	add index_entry_element_sort_string_fn argument to be able
+	to use a different function than the index_entry_element_sort_string
+	default, when called from converters.  A function argument instead of
+	a call to a function if converter argument is set is used to avoid
+	depending on the libtexinfo-converter library.
+
+	* tta/C/main/document.c (document_sorted_indices_by_index)
+	(document_sorted_indices_by_letter),
+	tta/C/main/manipulate_indices.c (new_collation_sorted_indices_by_index)
+	(new_base_collations_sorted_indices_by_index)
+	(get_collation_sorted_indices_by_index)
+	(new_base_collations_sorted_indices_by_letter)
+	(get_collation_sorted_indices_by_letter):
+	add new_base_collations_sorted_indices_by_index,
+	get_collation_sorted_indices_by_index,
+	new_base_collations_sorted_indices_by_letter and
+	get_collation_sorted_indices_by_letter based on
+	document_sorted_indices_by_* code and call these functions.
+	move new_collation_sorted_indices_by_index,
+	find_collation_sorted_indices_by_index,
+	new_collation_sorted_indices_by_letter and
+	find_collation_sorted_indices_by_letter to manipulate_indices.c.
+
+	* tta/C/main/document.c (document_sorted_indices_by_index)
+	(document_sorted_indices_by_letter), tta/C/main/manipulate_indices.c
+	(sort_indices_by_index) (sort_indices_by_letter,
+	setup_sort_sortable_strings_collator), tta/perl/Texinfo/Document.pm
+	(sorted_indices_by_letter) (sorted_indices_by_index),
+	tta/perl/Texinfo/Indices.pm (_setup_sort_sortable_strings_collator)
+	(sort_indices_by_index, sort_indices_by_letter):
+	use indices_sort_strings as argument to sort_indices_by_index,
+	sort_indices_by_letter and setup_sort_sortable_strings_collator, do
+	not call document_indices_sort_strings in those functions, but in
+	document_sorted_indices_by_index, document_sorted_indices_by_letter
+	before calling sort_indices_by_index or sort_indices_by_letter.
+
+	* tta/C/convert/converter.c
+	(converter_index_entry_element_sort_string)
+	(converter_indices_sort_strings, converter_sorted_indices_by_index)
+	(get_converter_indices_sorted_by_index)
+	(converter_sorted_indices_by_letter)
+	(get_converter_indices_sorted_by_letter),
+	tta/C/convert/convert_indices.c (converter_index_content_element)
+	(index_entry_first_letter_text_or_command),
+	tta/C/main/converter_types.h (CONVERTER),
+	tta/C/main/manipulate_indices.c (document_index_content_element),
+	tta/perl/Texinfo/Convert/Converter.pm (converter_indices_sort_strings)
+	(_converter_sorted_indices_by_letter)
+	(_converter_sorted_indices_by_index),
+	tta/perl/Texinfo/Convert/ConverterNonXS.pm
+	(get_converter_indices_sorted_by_letter)
+	(get_converter_indices_sorted_by_index),
+	tta/perl/Texinfo/Indices.pm (converter_index_content_element),
+	tta/perl/Texinfo/IndicesNonXS.pm (index_entry_element_sort_string): add
+	index sorting functions for converters that cache in the converter,
+	using the new fields indices_sort_strings, sorted_indices_by_index and
+	sorted_indices_by_letter, and use converter information.  Use those
+	functions in get_converter_indices_sorted_by_*, in
+	index_entry_first_letter_text_or_command and in converters.  
+	Remove document_index_content_element converter and consider only the
+	case of no converter in this function. Update
+	callers, replacing index_content_element by
+	converter_index_content_element in converters.  Remove
+	index_content_element.
+
+	* tta/C/main/document.c (document_indices_sort_strings),
+	tta/perl/Texinfo/Document.pm (sorted_indices_by_letter)
+	(sorted_indices_by_index), tta/perl/Texinfo/DocumentNonXS.pm
+	(document_indices_sort_strings), tta/perl/Texinfo/Indices.pm
+	(sort_indices_by_index, sort_indices_by_letter),
+	tta/perl/XSTexinfo/parser_document/DocumentXS.xs
+	(document_indices_sort_strings): remove converter
+	argument.  Update callers.
+
+	* tta/perl/XSTexinfo/parser_document/DocumentXS.xs
+	(setup_indices_sort_strings): never use the converter argument.
+
+	* tta/C/convert/texinfo.c (txi_complete_document),
+	tta/perl/texi2any.pl: do not call document_indices_sort_strings or
+	Document::setup_indices_sort_strings in advance anymore, as the sorted
+	index entries used by converters are not in the document anymore.
+
+	* tta/C/main/manipulate_indices.c (destroy_sorted_indices_by_index)
+	(destroy_sorted_indices_by_letter), tta/C/main/document.c
+	(destroy_document_information_except_tree): add
+	destroy_sorted_indices_by_index and destroy_sorted_indices_by_letter
+	based on destroy_document_information_except_tree code.
+
+	* tta/perl/Texinfo/Convert/Converter.pm (conversion_initialization),
+	tta/perl/Texinfo/Convert/DocBook.pm (converter_initialize),
+	tta/perl/Texinfo/Convert/LaTeX.pm (conversion_initialization),
+	tta/perl/Texinfo/Convert/Plaintext.pm (conversion_initialization):
+	call set_document even if document is undef, to get the other
+	initialization/destructions.
+
+	* tta/C/convert/converter.c (destroy_converter_index_sorting)
+	(converter_set_document, free_generic_converter),
+	tta/C/main/build_perl_info.c (pass_document_sv_to_converter_sv),
+	tta/perl/Texinfo/Convert/Converter.pm (converter_perl_release),
+	tta/perl/Texinfo/Convert/ConverterNonXS.pm (set_document):
+	destroy index sorting information set in converter.  Destroy document
+	in set_document if input document is undef.
+
+	* tta/C/convert/converter.c (element_cdt_tree): add and call
+	html_element_cdt_tree from this function only and call this function
+	directly in converter_index_content_element.  Remove all the now
+	unneeded element_cdt_tree_fn arguments.
+
+	* tta/perl/t/z_misc/test_sort.t: update.
+
 2026-06-15 Patrice Dumas  <pertusus@free.fr>
 
 	* tta/C/main/manipulate_indices.c (def_command_index_entry),
diff --git a/doc/tta_api/api_includes/Texinfo-Convert-Converter.texi b/doc/tta_api/api_includes/Texinfo-Convert-Converter.texi
index 2f75928..a29ab40 100644
--- a/doc/tta_api/api_includes/Texinfo-Convert-Converter.texi
+++ b/doc/tta_api/api_includes/Texinfo-Convert-Converter.texi
@@ -24,12 +24,9 @@
   }
 
   sub conversion_initialization($;$) {
-    my $self = shift;
-    my $document = shift;
+    my ($self, $document) = @_;
 
-    if ($document) {
-      $self->set_document($document);
-    }
+    $self->set_document($document);
 
     $self->set_global_document_commands('before', \@global_commands);
     ...
@@ -47,8 +44,7 @@
   }
 
   sub convert($$) {
-    my $self = shift;
-    my $document = shift;
+    my ($self, $document) = @_;
 
     $self->conversion_initialization($document);
 
@@ -57,8 +53,7 @@
   }
 
   sub output($$) {
-    my $self = shift;
-    my $document = shift;
+    my ($self, $document) = @_;
 
     $self->conversion_initialization($document);
 
@@ -259,8 +254,10 @@
 
 Associate @emph{$document} to @emph{$converter}.  Also set the encoding related customization
 options based on @emph{$converter} customization information and information on
-document encoding, and setup converter hash @code{convert_text_options} value that
+document encoding, setup converter hash @code{convert_text_options} value that
 can be used to call @ref{Texinfo@asis{::}Convert@asis{::}Text $result = convert_to_text($tree@comma{} $text_options),, @code{Texinfo::Convert::Text::convert_to_text}}.
+Also resets generic converter information that is invalidated by
+a new document.
 
 @end table
 
diff --git a/doc/tta_api/api_includes/Texinfo-Indices.texi b/doc/tta_api/api_includes/Texinfo-Indices.texi
index 75fc0d9..14bb7d2 100644
--- a/doc/tta_api/api_includes/Texinfo-Indices.texi
+++ b/doc/tta_api/api_includes/Texinfo-Indices.texi
@@ -17,16 +17,16 @@
   my $merged_index_entries
      = Texinfo::Indices::merge_indices($indices_information);
 
-  # $converter is a converter object
+  my $indices_sort_strings
+    = Texinfo::Document::indices_sort_strings($document, undef);
+
   my $index_entries_sorted;
   if ($sort_by_letter) {
     $index_entries_sorted
-      = Texinfo::Indices::sort_indices_by_letter($document,
-                                                 $converter);
+      = Texinfo::Indices::sort_indices_by_letter($indices_sort_strings);
   } else {
     $index_entries_sorted
-      = Texinfo::Indices::sort_indices_by_index($document,
-                                                $converter);
+      = Texinfo::Indices::sort_indices_by_index($indices_sort_strings);
   }
 @end verbatim
 
@@ -179,6 +179,8 @@
 @item $entry_content_element = index_content_element($element, $prefer_reference_element, $converter, $debug_level)
 @anchor{Texinfo@asis{::}Indices $entry_content_element = index_content_element($element@comma{} $prefer_reference_element@comma{} $converter@comma{} $debug_level)}
 
+FIXME incorrect, does not exist anymore, converter and document variants.
+
 Return a Texinfo tree element corresponding to the content of the index
 entry associated to @emph{$element}.  If @emph{$prefer_reference_element} is set,
 prefer an untranslated element.  If the element is an index command like
diff --git a/tta/C/Makefile.am b/tta/C/Makefile.am
index 2b212d3..1d2e244 100644
--- a/tta/C/Makefile.am
+++ b/tta/C/Makefile.am
@@ -269,7 +269,7 @@
 C_libtexinfo_LIBS = $(HARD_LOCALE_LIB) $(LIBPTHREAD) $(LIBTHREAD) $(LTLIBC32CONV) $(LTLIBINTL) $(LTLIBICONV) $(LTLIBUNISTRING) $(MBRTOWC_LIB) $(PTHREAD_ONCE_LIB) $(SETLOCALE_NULL_LIB)
 libtexinfo_la_LDFLAGS = -version-info 1:0:0 $(perl_conf_LIB_LDFLAGS) $(C_libtexinfo_LIBS)
 
-#libtexinfo_la_LDFLAGS = -version-info 1:0:0 -Wl,--no-undefined $(perl_conf_LIB_LDFLAGS) $(perl_conf_LIBS) $(LTLIBINTL) $(LTLIBICONV) $(LTLIBUNISTRING)
+#libtexinfo_la_LDFLAGS = -version-info 1:0:0 -Wl,--no-undefined $(perl_conf_LIB_LDFLAGS) $(perl_conf_LIBS) $(C_libtexinfo_LIBS)
 
 # static internal library without Perl at all
 libtexinfo_static_la_SOURCES = $(libtexinfo_la_SOURCES)
@@ -479,6 +479,8 @@
 C_libtexinfo_convert_sources = \
                        convert/converter.c \
                        convert/converter.h \
+                       convert/convert_indices.c \
+                       convert/convert_indices.h \
                        convert/cmd_converter.c \
                        convert/converters_options.c \
                        convert/converters_options.h \
diff --git a/tta/C/api_for_swig/swig_interface.c b/tta/C/api_for_swig/swig_interface.c
index def0d0d..b4f6b56 100644
--- a/tta/C/api_for_swig/swig_interface.c
+++ b/tta/C/api_for_swig/swig_interface.c
@@ -852,8 +852,8 @@
   const INDEX_SORTED_BY_INDEX *index_sorted = 0;
 
   COLLATION_INDICES_SORTED_BY_INDEX *collation_sorted_indices
-    = sorted_indices_by_index (document, &document->error_messages,
-                               document->options, 0, 0, use_unicode_collation,
+    = document_sorted_indices_by_index (document, &document->error_messages,
+                               document->options, 0, use_unicode_collation,
                                collation_language, collation_locale);
 
   INDEX_SORTED_BY_INDEX *indices_sorted_by_index
diff --git a/tta/C/convert/converter.c b/tta/C/convert/converter.c
index b5d56cd..b05c830 100644
--- a/tta/C/convert/converter.c
+++ b/tta/C/convert/converter.c
@@ -69,6 +69,7 @@
 #include "html_converter_api.h"
 #include "plaintexinfo_converter_api.h"
 #include "rawtext_converter_api.h"
+#include "convert_indices.h"
 #include "converter.h"
 
 /* table used to dispatch format specific functions.
@@ -584,6 +585,28 @@
   return 0;
 }
 
+static void
+destroy_converter_index_sorting (CONVERTER *converter)
+{
+  if (converter->indices_sort_strings)
+    {
+      destroy_index_entries_sort_strings (converter->indices_sort_strings);
+      converter->indices_sort_strings = 0;
+    }
+
+  if (converter->sorted_indices_by_index)
+    {
+      destroy_sorted_indices_by_index (converter->sorted_indices_by_index);
+      converter->sorted_indices_by_index = 0;
+    }
+
+  if (converter->sorted_indices_by_letter)
+    {
+      destroy_sorted_indices_by_letter (converter->sorted_indices_by_letter);
+      converter->sorted_indices_by_letter = 0;
+    }
+}
+
 void
 converter_set_document (CONVERTER *converter, DOCUMENT *document)
 {
@@ -613,6 +636,8 @@
       converter->document = 0;
     }
 
+  destroy_converter_index_sorting (converter);
+
   if (document)
     {
       converter->document = document;
@@ -859,6 +884,43 @@
 
 
 
+ELEMENT *
+element_cdt_tree (const char *string, const ELEMENT *element,
+                  CONVERTER *self,
+                  NAMED_STRING_ELEMENT_LIST *replaced_substrings,
+                  const char *translation_context)
+{
+  const LANG_TRANSLATION *lang_translation;
+  const OPTIONS *options;
+  int debug_level = 0;
+
+  if (self->format != COF_none
+      && converter_format_data[self->format].element_cdt_tree)
+    {
+      ELEMENT * (*element_cdt_tree_fn) (const char *string, const ELEMENT *element,
+                             CONVERTER *self,
+                             NAMED_STRING_ELEMENT_LIST *replaced_substrings,
+                             const char *translation_context)
+            = converter_format_data[self->format].element_cdt_tree;
+      return (*element_cdt_tree_fn) (string, element, self,
+                                     replaced_substrings,
+                                     translation_context);
+    }
+
+  lang_translation
+    = new_element_language_translation (&converters_translation_cache,
+                                        element, TXI_CONVERT_STRINGS_NR);
+  options = self->conf;
+  if (options && options->DEBUG.o.integer >= 0)
+    debug_level = options->DEBUG.o.integer;
+
+  return gdt_tree (string, self->document, lang_translation,
+                   replaced_substrings, debug_level, translation_context);
+}
+
+
+
+
 /* RESULT should be a char * array of dimension 5 */
 /* results to be freed by the caller */
 void
@@ -1541,6 +1603,96 @@
   return t_lang_sorting.text;
 }
 
+/* passed as a function reference */
+static char *
+converter_index_entry_element_sort_string (const INDEX_ENTRY *main_entry,
+                                 const ELEMENT *index_entry_element,
+                                 TEXT_OPTIONS *options, int in_code,
+                                 int prefer_reference_element,
+                                 int debug_level, CONVERTER *converter)
+{
+  char *sort_string;
+  ELEMENT *entry_tree_element;
+
+  if (!index_entry_element)
+    {
+      fatal ("converter_index_entry_element_sort_string: NULL element");
+    }
+
+  char *sortas = lookup_extra_string (index_entry_element, AI_key_sortas);
+  if (sortas)
+    return strdup (sortas);
+
+  entry_tree_element = converter_index_content_element (index_entry_element,
+                                                        converter,
+                                                  prefer_reference_element);
+
+  sort_string = entry_tree_element_sort_string (main_entry,
+                                entry_tree_element, options, in_code);
+
+  return sort_string;
+}
+
+static const INDICES_SORT_STRINGS *
+converter_indices_sort_strings (CONVERTER *converter)
+{
+  if (!converter->indices_sort_strings)
+    {
+      const MERGED_INDICES *merged_indices
+         = document_merged_indices (converter->document);
+
+      converter->indices_sort_strings
+       = setup_index_entries_sort_strings (&converter->error_messages,
+                        converter->conf,
+                        merged_indices, &converter->document->indices_info,
+                        0, converter,
+                        &converter_index_entry_element_sort_string);
+
+      /* document->modified_information |= F_DOCM_indices_sort_strings; */
+    }
+  return converter->indices_sort_strings;
+}
+
+static COLLATION_INDICES_SORTED_BY_INDEX *
+converter_sorted_indices_by_index (CONVERTER *converter,
+                         int use_unicode_collation,
+                         const char *input_lang_sorting_locale,
+                         const char *collation_locale)
+{
+  const char *lang_sorting_locale = 0;
+  COLLATIONS_INDICES_SORTED_BY_INDEX *collations;
+  COLLATION_INDICES_SORTED_BY_INDEX *collation_sorted_indices = 0;
+
+  if (!converter->sorted_indices_by_index)
+    converter->sorted_indices_by_index
+      = new_base_collations_sorted_indices_by_index ();
+
+  collations = converter->sorted_indices_by_index;
+
+  collation_sorted_indices
+    = get_collation_sorted_indices_by_index (collations,
+                                             use_unicode_collation,
+                                             input_lang_sorting_locale,
+                                             collation_locale,
+                                             &lang_sorting_locale);
+
+  if (!collation_sorted_indices->sorted_indices)
+    {
+      document_merged_indices (converter->document);
+
+      const INDICES_SORT_STRINGS *indices_sort_strings
+             = converter_indices_sort_strings (converter);
+
+      collation_sorted_indices->sorted_indices
+        = sort_indices_by_index (indices_sort_strings,
+                                 &converter->error_messages,
+                                 converter->conf,
+                                 use_unicode_collation, lang_sorting_locale,
+                                 collation_locale);
+    }
+  return collation_sorted_indices;
+}
+
 INDEX_SORTED_BY_INDEX *
 get_converter_indices_sorted_by_index (CONVERTER *self, char **language)
 {
@@ -1549,11 +1701,6 @@
     {
       COLLATION_INDICES_SORTED_BY_INDEX *collation_sorted_indices;
       char *lang_sorting_locale = 0;
-      ELEMENT * (*element_cdt_tree_fn) (const char *string, const ELEMENT *element,
-                             CONVERTER *self,
-                             NAMED_STRING_ELEMENT_LIST *replaced_substrings,
-                             const char *translation_context) = 0;
-      CONVERTER *converter_for_translations = 0;
 
       if (self->conf->USE_UNICODE_COLLATION.o.integer >= 0)
         {
@@ -1566,19 +1713,8 @@
                               (self->current_lang_translations->info);
         }
 
-      if (self->format != COF_none
-          && converter_format_data[self->format].element_cdt_tree)
-        {
-          converter_for_translations = self;
-          element_cdt_tree_fn
-            = converter_format_data[self->format].element_cdt_tree;
-        }
-
       collation_sorted_indices
-        = sorted_indices_by_index (self->document,
-                                   &self->error_messages, self->conf,
-                                   converter_for_translations,
-                                   element_cdt_tree_fn,
+        = converter_sorted_indices_by_index (self,
                                    self->conf->USE_UNICODE_COLLATION.o.integer,
                                    lang_sorting_locale,
                            self->conf->XS_STRXFRM_COLLATION_LOCALE.o.string);
@@ -1588,11 +1724,53 @@
 
       if (collation_sorted_indices->type != ctn_locale_collation)
         *language = collation_sorted_indices->language;
+
       return collation_sorted_indices->sorted_indices;
     }
   return 0;
 }
 
+static COLLATION_INDICES_SORTED_BY_LETTER *
+converter_sorted_indices_by_letter (CONVERTER *converter,
+                          int use_unicode_collation,
+                          const char *input_lang_sorting_locale,
+                          const char *collation_locale)
+{
+  const char *lang_sorting_locale = 0;
+  COLLATIONS_INDICES_SORTED_BY_LETTER *collations;
+  COLLATION_INDICES_SORTED_BY_LETTER *collation_sorted_indices = 0;
+
+  if (!converter->sorted_indices_by_letter)
+    {
+      converter->sorted_indices_by_letter
+        = new_base_collations_sorted_indices_by_letter ();
+    }
+
+  collations = converter->sorted_indices_by_letter;
+
+  collation_sorted_indices
+   = get_collation_sorted_indices_by_letter (collations,
+                                             use_unicode_collation,
+                                             input_lang_sorting_locale,
+                                             collation_locale,
+                                             &lang_sorting_locale);
+
+  if (!collation_sorted_indices->sorted_indices)
+    {
+      document_merged_indices (converter->document);
+
+      const INDICES_SORT_STRINGS *indices_sort_strings
+             = converter_indices_sort_strings (converter);
+
+      collation_sorted_indices->sorted_indices
+        = sort_indices_by_letter (indices_sort_strings,
+                                  &converter->error_messages, converter->conf,
+                                  use_unicode_collation, lang_sorting_locale,
+                                  collation_locale);
+    }
+  return collation_sorted_indices;
+}
+
 INDEX_SORTED_BY_LETTER *
 get_converter_indices_sorted_by_letter (CONVERTER *self, char **language)
 {
@@ -1601,11 +1779,6 @@
     {
       COLLATION_INDICES_SORTED_BY_LETTER *collation_sorted_indices;
       char *lang_sorting_locale = 0;
-      ELEMENT * (*element_cdt_tree_fn) (const char *string, const ELEMENT *element,
-                             CONVERTER *self,
-                             NAMED_STRING_ELEMENT_LIST *replaced_substrings,
-                             const char *translation_context) = 0;
-      CONVERTER *converter_for_translations = 0;
 
       if (self->conf->USE_UNICODE_COLLATION.o.integer >= 0)
         {
@@ -1618,19 +1791,8 @@
                               (self->current_lang_translations->info);
         }
 
-      if (self->format != COF_none
-          && converter_format_data[self->format].element_cdt_tree)
-        {
-          converter_for_translations = self;
-          element_cdt_tree_fn
-            = converter_format_data[self->format].element_cdt_tree;
-        }
-
       collation_sorted_indices
-        = sorted_indices_by_letter (self->document,
-                                    &self->error_messages, self->conf,
-                                    converter_for_translations,
-                                    element_cdt_tree_fn,
+        = converter_sorted_indices_by_letter (self,
                                     self->conf->USE_UNICODE_COLLATION.o.integer,
                                     lang_sorting_locale,
                             self->conf->XS_STRXFRM_COLLATION_LOCALE.o.string);
@@ -2000,6 +2162,8 @@
       free (self->conf);
     }
 
+  destroy_converter_index_sorting (self);
+
   if (self->convert_index_text_options)
     destroy_text_options (self->convert_index_text_options);
 
diff --git a/tta/C/convert/converter.h b/tta/C/convert/converter.h
index 6df3087..bc805ea 100644
--- a/tta/C/convert/converter.h
+++ b/tta/C/convert/converter.h
@@ -168,6 +168,11 @@
 void converter_remove_output_units (CONVERTER *converter);
 void destroy_converter (CONVERTER *converter);
 
+ELEMENT *element_cdt_tree (const char *string, const ELEMENT *element,
+                  CONVERTER *self,
+                  NAMED_STRING_ELEMENT_LIST *replaced_substrings,
+                  const char *translation_context);
+
 void determine_files_and_directory (CONVERTER *self, const char *output_format,
                                     char **result);
 int create_destination_directory (CONVERTER *self,
diff --git a/tta/C/convert/format_html.c b/tta/C/convert/format_html.c
index 5728ddd..c7bc836 100644
--- a/tta/C/convert/format_html.c
+++ b/tta/C/convert/format_html.c
@@ -64,8 +64,9 @@
 /* for unregister_document_merge_with_document
 #include "document.h"
  */
-#include "converter.h"
 #include "manipulate_tree.h"
+#include "converter.h"
+#include "convert_indices.h"
 /* for new_complete_menu_master_menu */
 #include "structuring.h"
 #include "api_to_perl.h"
@@ -10232,10 +10233,9 @@
           memset (new_normalized_entry_levels, 0,
                   sizeof (char *) * (SUBENTRIES_MAX_LEVEL +1));
 
-          entry_content_element = index_content_element (main_entry_element, 0,
-                                            self->document,
-                              (self->conf && self->conf->DEBUG.o.integer > 0),
-                               self, &html_element_cdt_tree);
+          entry_content_element
+            = converter_index_content_element (main_entry_element, self, 0);
+
           entry_index_nr
              = index_number_index_by_name (&self->sorted_index_names,
                                            index_entry_ref->index_name);
@@ -10834,10 +10834,7 @@
           if (first_entry)
             {
               INDEX_ENTRY_TEXT_OR_COMMAND *entry_text_or_command
-                = index_entry_first_letter_text_or_command (first_entry,
-                                            self->document,
-                              (self->conf && self->conf->DEBUG.o.integer > 0),
-                                            self, &html_element_cdt_tree);
+                = index_entry_first_letter_text_or_command (first_entry, self);
 
               if (entry_text_or_command)
                 {
@@ -13513,10 +13510,8 @@
 
                   /* Obtain term by converting to text */
                   entry_content_element
-                    = index_content_element (main_entry_element, 0,
-                                            self->document,
-                              (self->conf && self->conf->DEBUG.o.integer > 0),
-                               self, &html_element_cdt_tree);
+                    = converter_index_content_element (main_entry_element,
+                                                       self, 0);
 
                   entry_index_nr
                     = index_number_index_by_name (&self->sorted_index_names,
diff --git a/tta/C/convert/html_prepare_converter.c b/tta/C/convert/html_prepare_converter.c
index ff46990..af63a09 100644
--- a/tta/C/convert/html_prepare_converter.c
+++ b/tta/C/convert/html_prepare_converter.c
@@ -62,6 +62,7 @@
 /* no_brace_command_accent_upper_case
    xml_text_entity_no_arg_commands_formatting */
 #include "converter.h"
+#include "convert_indices.h"
 #include "call_html_perl_function.h"
 #include "hashmap.h"
 #include "format_html.h"
@@ -5089,10 +5090,7 @@
               region = lookup_extra_string (main_entry_element,
                                             AI_key_element_region);
               entry_reference_content_element
-               = index_content_element (main_entry_element, 1,
-                                            self->document,
-                              (self->conf && self->conf->DEBUG.o.integer > 0),
-                                        0, 0);
+               = converter_index_content_element (main_entry_element, self, 1);
         /* construct element to convert to a normalized identifier to use as
            hrefs target */
               normalize_index_element = new_element (ET_NONE);
diff --git a/tta/C/convert/texinfo.c b/tta/C/convert/texinfo.c
index b79beb8..4baac56 100644
--- a/tta/C/convert/texinfo.c
+++ b/tta/C/convert/texinfo.c
@@ -585,10 +585,13 @@
   if (flags & STTF_floats)
     number_floats (document);
 
+  /* FIXME remove that, now that index sorting is mainly done by converters
+     and call the function explicitely instead if needed (for tests
+     probably)
   if (flags & STTF_setup_index_entries_sort_strings)
     document_indices_sort_strings (document, &document->error_messages,
-                                   document->options, converter,
-                                   element_cdt_tree_fn);
+                                   document->options, converter);
+   */
 }
 
 /* In texi2any.pl, not in a separate function */
diff --git a/tta/C/main/build_perl_info.c b/tta/C/main/build_perl_info.c
index 977f4c3..6cabc51 100644
--- a/tta/C/main/build_perl_info.c
+++ b/tta/C/main/build_perl_info.c
@@ -3285,6 +3285,13 @@
       hv_store (converter_hv, "document", strlen ("document"),
                 newSVsv (document_in), 0);
     }
+
+  hv_delete (converter_hv, "sorted_indices_by_letter",
+             strlen ("sorted_indices_by_letter"), G_DISCARD);
+  hv_delete (converter_hv, "sorted_indices_by_index",
+             strlen ("sorted_indices_by_index"), G_DISCARD);
+  hv_delete (converter_hv, "index_entries_sort_strings",
+             strlen ("index_entries_sort_strings"), G_DISCARD);
 }
 
 void
diff --git a/tta/C/main/convert_utils.c b/tta/C/main/convert_utils.c
index bcf50fe..92dd3d7 100644
--- a/tta/C/main/convert_utils.c
+++ b/tta/C/main/convert_utils.c
@@ -824,6 +824,7 @@
   const char *def_cmdname;
   enum command_id def_command;
 
+  /* TODO is always true.  Remove condition, or add everywhere */
   if (current->e.c->contents.number > 0)
     {
       size_t i;
diff --git a/tta/C/main/converter_types.h b/tta/C/main/converter_types.h
index 6ab339a..35e5110 100644
--- a/tta/C/main/converter_types.h
+++ b/tta/C/main/converter_types.h
@@ -849,6 +849,10 @@
   /* associates deprecated directories and reference directories */
     DEPRECATED_DIRS_LIST deprecated_config_directories;
 
+    INDICES_SORT_STRINGS *indices_sort_strings;
+    COLLATIONS_INDICES_SORTED_BY_INDEX *sorted_indices_by_index;
+    COLLATIONS_INDICES_SORTED_BY_LETTER *sorted_indices_by_letter;
+
   /* HTML specific */
     /* set for a converter */
     int external_references_number; /* total number of external references
diff --git a/tta/C/main/document.c b/tta/C/main/document.c
index 4b52c49..2547099 100644
--- a/tta/C/main/document.c
+++ b/tta/C/main/document.c
@@ -330,13 +330,7 @@
 const INDICES_SORT_STRINGS *
 document_indices_sort_strings (DOCUMENT *document,
                                ERROR_MESSAGE_LIST *error_messages,
-                               OPTIONS *options,
-                               CONVERTER *converter,
-   ELEMENT * (*element_cdt_tree_fn) (const char *string, const ELEMENT *element,
-                             CONVERTER *self,
-                             NAMED_STRING_ELEMENT_LIST *replaced_substrings,
-                             const char *translation_context)
-                                 )
+                               OPTIONS *options)
 {
   if (!document->indices_sort_strings)
     {
@@ -346,68 +340,19 @@
       document->indices_sort_strings
        = setup_index_entries_sort_strings (error_messages, options,
                         merged_indices, &document->indices_info, 0,
-                        converter, element_cdt_tree_fn);
+                        0, 0);
 
       document->modified_information |= F_DOCM_indices_sort_strings;
     }
   return document->indices_sort_strings;
 }
 
-static COLLATION_INDICES_SORTED_BY_INDEX *
-new_collation_sorted_indices_by_index (
-            COLLATIONS_INDICES_SORTED_BY_INDEX *collations,
-            enum collation_type_name type,
-            const char *language)
-{
-  COLLATION_INDICES_SORTED_BY_INDEX *result = 0;
-  if (collations->number <= collations->space)
-    {
-      collations->collation_sorted_indices
-        = (COLLATION_INDICES_SORTED_BY_INDEX *) realloc
-           (collations->collation_sorted_indices,
-             (collations->space += 3)
-                * sizeof (COLLATION_INDICES_SORTED_BY_INDEX));
-      if (!collations->collation_sorted_indices)
-        fatal ("realloc failed");
-    }
-
-  result = &collations->collation_sorted_indices[collations->number];
-  memset (result, 0, sizeof (COLLATION_INDICES_SORTED_BY_INDEX));
-  result->type = type;
-  result->language = strdup (language);
-
-  collations->number++;
-
-  return result;
-}
-
+/* Used in tests and in SWIG interface */
 COLLATION_INDICES_SORTED_BY_INDEX *
-find_collation_sorted_indices_by_index (
-            COLLATIONS_INDICES_SORTED_BY_INDEX *collations,
-            enum collation_type_name type,
-            const char *language)
-{
-  size_t i;
-  for (i = 2; i < collations->number; i++)
-    {
-      COLLATION_INDICES_SORTED_BY_INDEX *collation_sorted_indices
-        = &collations->collation_sorted_indices[i];
-      if (collation_sorted_indices->type == type
-          && !strcmp (collation_sorted_indices->language, language))
-        return collation_sorted_indices;
-    }
-  return 0;
-}
-
-COLLATION_INDICES_SORTED_BY_INDEX *
-sorted_indices_by_index (DOCUMENT *document,
+document_sorted_indices_by_index (DOCUMENT *document,
                          ERROR_MESSAGE_LIST *error_messages,
                          OPTIONS *options,
                          CONVERTER *converter,
-   ELEMENT * (*element_cdt_tree_fn) (const char *string, const ELEMENT *element,
-                             CONVERTER *self,
-                             NAMED_STRING_ELEMENT_LIST *replaced_substrings,
-                             const char *translation_context),
                          int use_unicode_collation,
                          const char *input_lang_sorting_locale,
                          const char *collation_locale)
@@ -415,120 +360,43 @@
   const char *lang_sorting_locale = 0;
   COLLATIONS_INDICES_SORTED_BY_INDEX *collations;
   COLLATION_INDICES_SORTED_BY_INDEX *collation_sorted_indices = 0;
+
   if (!document->sorted_indices_by_index)
-    {
-      collations
-       = (COLLATIONS_INDICES_SORTED_BY_INDEX *)
-           malloc (sizeof (COLLATIONS_INDICES_SORTED_BY_INDEX));
-      memset (collations, 0,
-              sizeof (COLLATIONS_INDICES_SORTED_BY_INDEX));
-
-      /* order is important, to match enum */
-      new_collation_sorted_indices_by_index (collations, ctn_unicode, "-");
-      new_collation_sorted_indices_by_index (collations, ctn_no_unicode, "");
-
-      document->sorted_indices_by_index = collations;
-    }
+    document->sorted_indices_by_index
+      = new_base_collations_sorted_indices_by_index ();
 
   collations = document->sorted_indices_by_index;
 
-  if (use_unicode_collation == 0)
-    collation_sorted_indices
-      = &collations->collation_sorted_indices[ctn_no_unicode];
-  else if (!input_lang_sorting_locale && !collation_locale)
-    collation_sorted_indices
-      = &collations->collation_sorted_indices[ctn_unicode];
-  else
-    {
-      enum collation_type_name type;
-
-      if (input_lang_sorting_locale)
-        {
-          type = ctn_language_collation;
-          lang_sorting_locale = input_lang_sorting_locale;
-        }
-      else
-        {
-          type = ctn_locale_collation;
-          lang_sorting_locale = collation_locale;
-        }
-
-      collation_sorted_indices
-        = find_collation_sorted_indices_by_index (collations, type,
-                                                 lang_sorting_locale);
-      if (!collation_sorted_indices)
-        collation_sorted_indices
-          = new_collation_sorted_indices_by_index (collations,
-                                                   type, lang_sorting_locale);
-    }
+  collation_sorted_indices
+    = get_collation_sorted_indices_by_index (collations,
+                                             use_unicode_collation,
+                                             input_lang_sorting_locale,
+                                             collation_locale,
+                                             &lang_sorting_locale);
 
   if (!collation_sorted_indices->sorted_indices)
     {
       document_merged_indices (document);
+
+      const INDICES_SORT_STRINGS *indices_sort_strings
+             = document_indices_sort_strings (document,
+                                              error_messages, options);
+
       collation_sorted_indices->sorted_indices
-        = sort_indices_by_index (document, error_messages, options,
-                                 converter, element_cdt_tree_fn,
+        = sort_indices_by_index (indices_sort_strings, error_messages,
+                                 options,
                                  use_unicode_collation, lang_sorting_locale,
                                  collation_locale);
     }
   return collation_sorted_indices;
 }
 
-static COLLATION_INDICES_SORTED_BY_LETTER *
-new_collation_sorted_indices_by_letter (
-            COLLATIONS_INDICES_SORTED_BY_LETTER *collations,
-            enum collation_type_name type,
-            const char *language)
-{
-  COLLATION_INDICES_SORTED_BY_LETTER *result = 0;
-  if (collations->number <= collations->space)
-    {
-      collations->collation_sorted_indices
-        = (COLLATION_INDICES_SORTED_BY_LETTER *) realloc
-           (collations->collation_sorted_indices,
-             (collations->space += 3)
-                * sizeof (COLLATION_INDICES_SORTED_BY_LETTER));
-      if (!collations->collation_sorted_indices)
-        fatal ("realloc failed");
-    }
-
-  result = &collations->collation_sorted_indices[collations->number];
-  memset (result, 0, sizeof (COLLATION_INDICES_SORTED_BY_LETTER));
-  result->type = type;
-  result->language = strdup (language);
-
-  collations->number++;
-
-  return result;
-}
-
+/* Unused */
 COLLATION_INDICES_SORTED_BY_LETTER *
-find_collation_sorted_indices_by_letter (
-            COLLATIONS_INDICES_SORTED_BY_LETTER *collations,
-            enum collation_type_name type,
-            const char *language)
-{
-  size_t i;
-  for (i = 2; i < collations->number; i++)
-    {
-      COLLATION_INDICES_SORTED_BY_LETTER *collation_sorted_indices
-        = &collations->collation_sorted_indices[i];
-      if (collation_sorted_indices->type == type
-          && !strcmp (collation_sorted_indices->language, language))
-        return collation_sorted_indices;
-    }
-  return 0;
-}
-
-COLLATION_INDICES_SORTED_BY_LETTER *
-sorted_indices_by_letter (DOCUMENT *document,
+document_sorted_indices_by_letter (DOCUMENT *document,
                           ERROR_MESSAGE_LIST *error_messages,
                           OPTIONS *options,
                           CONVERTER *converter,
-   ELEMENT * (*element_cdt_tree_fn) (const char *string, const ELEMENT *element,
-                             CONVERTER *self,
-                             NAMED_STRING_ELEMENT_LIST *replaced_substrings,
-                             const char *translation_context),
                           int use_unicode_collation,
                           const char *input_lang_sorting_locale,
                           const char *collation_locale)
@@ -538,57 +406,30 @@
   COLLATION_INDICES_SORTED_BY_LETTER *collation_sorted_indices = 0;
   if (!document->sorted_indices_by_letter)
     {
-      collations
-       = (COLLATIONS_INDICES_SORTED_BY_LETTER *)
-           malloc (sizeof (COLLATIONS_INDICES_SORTED_BY_LETTER));
-      memset (collations, 0,
-              sizeof (COLLATIONS_INDICES_SORTED_BY_LETTER));
-
-      /* order is important, to match enum */
-      new_collation_sorted_indices_by_letter (collations, ctn_unicode, "-");
-      new_collation_sorted_indices_by_letter (collations, ctn_no_unicode, "");
-
-      document->sorted_indices_by_letter = collations;
+      document->sorted_indices_by_letter
+        = new_base_collations_sorted_indices_by_letter ();
     }
 
   collations = document->sorted_indices_by_letter;
 
-  if (use_unicode_collation == 0)
-    collation_sorted_indices
-      = &collations->collation_sorted_indices[ctn_no_unicode];
-  else if (!input_lang_sorting_locale && !collation_locale)
-    collation_sorted_indices
-      = &collations->collation_sorted_indices[ctn_unicode];
-  else
-    {
-      enum collation_type_name type;
-
-      if (input_lang_sorting_locale)
-        {
-          type = ctn_language_collation;
-          lang_sorting_locale = input_lang_sorting_locale;
-        }
-      else
-        {
-          type = ctn_locale_collation;
-          lang_sorting_locale = collation_locale;
-        }
-
-      collation_sorted_indices
-        = find_collation_sorted_indices_by_letter (collations, type,
-                                                   lang_sorting_locale);
-      if (!collation_sorted_indices)
-        collation_sorted_indices
-          = new_collation_sorted_indices_by_letter (collations,
-                                                    type, lang_sorting_locale);
-    }
+  collation_sorted_indices
+   = get_collation_sorted_indices_by_letter (collations,
+                                             use_unicode_collation,
+                                             input_lang_sorting_locale,
+                                             collation_locale,
+                                             &lang_sorting_locale);
 
   if (!collation_sorted_indices->sorted_indices)
     {
       document_merged_indices (document);
+
+      const INDICES_SORT_STRINGS *indices_sort_strings
+             = document_indices_sort_strings (document,
+                                              error_messages, options);
+
       collation_sorted_indices->sorted_indices
-        = sort_indices_by_letter (document, error_messages, options,
-                                  converter, element_cdt_tree_fn,
+        = sort_indices_by_letter (indices_sort_strings, error_messages,
+                                  options,
                                   use_unicode_collation, lang_sorting_locale,
                                   collation_locale);
     }
@@ -633,42 +474,8 @@
     destroy_merged_indices (document->merged_indices);
   if (document->indices_sort_strings)
     destroy_index_entries_sort_strings (document->indices_sort_strings);
-  if (document->sorted_indices_by_index)
-    {
-      if (document->sorted_indices_by_index->number > 0)
-        {
-          size_t i;
-          for (i = 0; i < document->sorted_indices_by_index->number; i++)
-            {
-              COLLATION_INDICES_SORTED_BY_INDEX *collation_sorted_indices
-        = &document->sorted_indices_by_index->collation_sorted_indices[i];
-              free (collation_sorted_indices->language);
-              if (collation_sorted_indices->sorted_indices)
-                destroy_indices_sorted_by_index (
-                                collation_sorted_indices->sorted_indices);
-            }
-        }
-      free (document->sorted_indices_by_index->collation_sorted_indices);
-      free (document->sorted_indices_by_index);
-    }
-  if (document->sorted_indices_by_letter)
-    {
-      if (document->sorted_indices_by_letter->number > 0)
-        {
-          size_t i;
-          for (i = 0; i < document->sorted_indices_by_letter->number; i++)
-            {
-              COLLATION_INDICES_SORTED_BY_LETTER *collation_sorted_indices
-        = &document->sorted_indices_by_letter->collation_sorted_indices[i];
-              free (collation_sorted_indices->language);
-              if (collation_sorted_indices->sorted_indices)
-                destroy_indices_sorted_by_letter (
-                                collation_sorted_indices->sorted_indices);
-            }
-        }
-      free (document->sorted_indices_by_letter->collation_sorted_indices);
-      free (document->sorted_indices_by_letter);
-    }
+  destroy_sorted_indices_by_index (document->sorted_indices_by_index);
+  destroy_sorted_indices_by_letter (document->sorted_indices_by_letter);
 }
 
 void
@@ -915,12 +722,7 @@
 }
 
 char *
-print_document_indices_sort_strings (DOCUMENT *document, CONVERTER *converter,
-   ELEMENT * (*element_cdt_tree_fn) (const char *string, const ELEMENT *element,
-                             CONVERTER *self,
-                             NAMED_STRING_ELEMENT_LIST *replaced_substrings,
-                             const char *translation_context)
-                                 )
+print_document_indices_sort_strings (DOCUMENT *document, CONVERTER *converter)
 {
   size_t i;
   const MERGED_INDICES *merged_indices;
@@ -951,15 +753,14 @@
     }
 
   indices_sort_strings = document_indices_sort_strings (document,
-                            &document->error_messages, document->options,
-                            converter, element_cdt_tree_fn);
+                            &document->error_messages, document->options);
 
   collation_sorted_index_entries
-   = sorted_indices_by_index (document, &document->error_messages,
-                              document->options,
-                              converter, element_cdt_tree_fn,
-                              use_unicode_collation,
-                              lang_sorting_locale, 0);
+   = document_sorted_indices_by_index (document, &document->error_messages,
+                                       document->options,
+                                       converter,
+                                       use_unicode_collation,
+                                       lang_sorting_locale, 0);
 
   memset (&indices_sort_strings_n_nr, 0, sizeof (NAME_NUMBER_LIST));
 
diff --git a/tta/C/main/document.h b/tta/C/main/document.h
index 1b72b67..d38b625 100644
--- a/tta/C/main/document.h
+++ b/tta/C/main/document.h
@@ -54,35 +54,21 @@
 const INDICES_SORT_STRINGS *document_indices_sort_strings (
                                DOCUMENT *document,
                                ERROR_MESSAGE_LIST *error_messages,
-                               OPTIONS *options,
-                               CONVERTER *converter,
-   ELEMENT * (*element_cdt_tree_fn) (const char *string, const ELEMENT *element,
-                             CONVERTER *self,
-                             NAMED_STRING_ELEMENT_LIST *replaced_substrings,
-                             const char *translation_context)
-                                 );
+                               OPTIONS *options);
 
-COLLATION_INDICES_SORTED_BY_INDEX *sorted_indices_by_index (
+COLLATION_INDICES_SORTED_BY_INDEX *document_sorted_indices_by_index (
                          DOCUMENT *document,
                          ERROR_MESSAGE_LIST *error_messages,
                          OPTIONS *options,
                          CONVERTER *converter,
-   ELEMENT * (*element_cdt_tree_fn) (const char *string, const ELEMENT *element,
-                             CONVERTER *self,
-                             NAMED_STRING_ELEMENT_LIST *replaced_substrings,
-                             const char *translation_context),
                          int use_unicode_collation,
                          const char *input_lang_sorting_locale,
                          const char *collation_locale);
-COLLATION_INDICES_SORTED_BY_LETTER *sorted_indices_by_letter (
+COLLATION_INDICES_SORTED_BY_LETTER *document_sorted_indices_by_letter (
                           DOCUMENT *document,
                           ERROR_MESSAGE_LIST *error_messages,
                           OPTIONS *options,
                           CONVERTER *converter,
-   ELEMENT * (*element_cdt_tree_fn) (const char *string, const ELEMENT *element,
-                             CONVERTER *self,
-                             NAMED_STRING_ELEMENT_LIST *replaced_substrings,
-                             const char *translation_context),
                           int use_unicode_collation,
                           const char *input_lang_sorting_locale,
                           const char *collation_locale);
@@ -101,11 +87,7 @@
 
 char *print_document_listoffloats (DOCUMENT *document);
 char *print_document_indices_information (DOCUMENT *document);
-char *print_document_indices_sort_strings (DOCUMENT *document, CONVERTER *converter,
-   ELEMENT * (*element_cdt_tree_fn) (const char *string, const ELEMENT *element,
-                             CONVERTER *self,
-                             NAMED_STRING_ELEMENT_LIST *replaced_substrings,
-                             const char *translation_context)
-                                 );
+char *print_document_indices_sort_strings (DOCUMENT *document,
+                                           CONVERTER *converter);
 
 #endif
diff --git a/tta/C/main/manipulate_indices.c b/tta/C/main/manipulate_indices.c
index 4b6c7cf..855f49a 100644
--- a/tta/C/main/manipulate_indices.c
+++ b/tta/C/main/manipulate_indices.c
@@ -47,8 +47,8 @@
 #include "convert_to_texinfo.h"
 #include "call_perl_function.h"
 #include "api_to_perl.h"
-#include "manipulate_indices.h"
 #include "unicode-collation/collation_key.h"
+#include "manipulate_indices.h"
 
 /* corresponding perl code in Texinfo::Indices */
 
@@ -213,23 +213,30 @@
   free (msg);
 }
 
-static ELEMENT *
-def_command_index_entry (ELEMENT *main_entry_element,
-                         int prefer_reference_element, DOCUMENT *document,
-                         int debug_level,
-                         CONVERTER *converter,
-   ELEMENT * (*element_cdt_tree_fn) (const char *string, const ELEMENT *element,
-                             CONVERTER *self,
-                             NAMED_STRING_ELEMENT_LIST *replaced_substrings,
-                             const char *translation_context)
-                      )
+/* return index content element if there is no need for translation,
+   otherwise return information for translation in DEF_COMMAND_OUT,
+   NAME_COPY_OUT and CLASS_COPY_OUT.
+ */
+ELEMENT *
+get_index_content_info_element (const ELEMENT *element,
+                                int prefer_reference_element,
+                                enum command_id *def_command_out,
+                                ELEMENT **name_copy_out,
+                                ELEMENT **class_copy_out)
 {
   ELEMENT *name = 0;
   ELEMENT *class = 0;
-  ELEMENT *def_l_e = main_entry_element->e.c->contents.list[0];
-  const char *def_cmdname
-    = lookup_extra_string (main_entry_element, AI_key_def_command);
+  const char *def_cmdname = lookup_extra_string (element, AI_key_def_command);
+  ELEMENT *def_l_e;
 
+  if (!def_cmdname)
+    {
+      ELEMENT *element_copy
+        = copy_element_tree (element->e.c->contents.list[0], 0);
+      return element_copy;
+    }
+
+  def_l_e = element->e.c->contents.list[0];
   if (def_l_e->e.c->contents.number > 0)
     {
       size_t ic;
@@ -255,9 +262,12 @@
       remove_def_types (name_copy);
       if (!(builtin_command_data[def_command].flags & CF_def_class_method)
           && !(builtin_command_data[def_command].flags
-                                       & CF_def_class_variable)) {
+                                       & CF_def_class_variable))
+        {
           return name_copy;
-      } else {
+        }
+      else
+        {
           ELEMENT *class_copy = copy_element_tree (class, 0);
           remove_def_types (class_copy);
 
@@ -284,73 +294,16 @@
             }
           else
             {
-              const LANG_TRANSLATION *element_lang_translations;
-              ELEMENT *index_entry;
-              NAMED_STRING_ELEMENT_LIST *substrings
-                       = new_named_string_element_list ();
-
-              add_element_to_named_string_element_list (substrings,
-                                             "name", name_copy);
-              add_element_to_named_string_element_list (substrings,
-                                             "class", class_copy);
-
-              if (converter && element_cdt_tree_fn)
-                {
-                  if (builtin_command_data[def_command].flags
-                                                 & CF_def_class_method)
-                    {
-                      index_entry = element_cdt_tree_fn ("{name} on {class}",
-                                      main_entry_element, converter,
-                                      substrings, 0);
-                    }
-                  else if (builtin_command_data[def_command].flags
-                                              & CF_def_class_variable)
-                    {
-                      index_entry = element_cdt_tree_fn ("{name} of {class}",
-                                      main_entry_element, converter,
-                                      substrings, 0);
-                    }
-           /* should not be possible, still considered for more robust code */
-                  else
-                    unexpected_def_name_class_message (def_command);
-                }
-              else
-                {
-                  element_lang_translations
-                    = new_element_language_translation (
-                       &converters_translation_cache, main_entry_element,
-                       TXI_CONVERT_STRINGS_NR);
-
-                  if (builtin_command_data[def_command].flags
-                                                 & CF_def_class_method)
-                    {
-                      index_entry = gdt_tree ("{name} on {class}",
-                                document, element_lang_translations,
-                                substrings, debug_level, 0);
-                    }
-                  else if (builtin_command_data[def_command].flags
-                                              & CF_def_class_variable)
-                    {
-                      index_entry = gdt_tree ("{name} of {class}",
-                                document, element_lang_translations,
-                                substrings, debug_level, 0);
-
-                    }
-           /* should not be possible, still considered for more robust code */
-                  else
-                    unexpected_def_name_class_message (def_command);
-                }
-
-              destroy_named_string_element_list (substrings);
-
-                      /*
-         prefer a type-less container rather than 'root_line' returned by gdt
-                       */
-              index_entry->type = ET_NONE;
-              return index_entry;
+              *name_copy_out = name_copy;
+              *class_copy_out = class_copy;
+              *def_command_out = def_command;
+              return 0;
             }
         }
     }
+  *name_copy_out = 0;
+  *class_copy_out = 0;
+  *def_command_out = CM_NONE;
   return 0;
 }
 
@@ -359,36 +312,58 @@
    elements are put in arrays of non-const elements, even though they are not
    modified */
 ELEMENT *
-index_content_element (const ELEMENT *element, int prefer_reference_element,
-                       DOCUMENT *document, int debug_level,
-                       CONVERTER *converter,
-   ELEMENT * (*element_cdt_tree_fn) (const char *string, const ELEMENT *element,
-                             CONVERTER *self,
-                             NAMED_STRING_ELEMENT_LIST *replaced_substrings,
-                             const char *translation_context)
-                      )
+document_index_content_element (const ELEMENT *element,
+                                int prefer_reference_element,
+                                DOCUMENT *document, int debug_level)
 {
-  const char *def_command = lookup_extra_string (element, AI_key_def_command);
+  enum command_id def_command;
+  ELEMENT *class_copy;
+  ELEMENT *name_copy;
+  NAMED_STRING_ELEMENT_LIST *substrings;
+  const LANG_TRANSLATION *element_lang_translations;
 
-  if (def_command)
+  ELEMENT *index_element
+    = get_index_content_info_element (element, prefer_reference_element,
+                                      &def_command, &name_copy, &class_copy);
+
+  if (index_element || !class_copy)
+    return index_element;
+
+  substrings = new_named_string_element_list ();
+  add_element_to_named_string_element_list (substrings,
+                                            "name", name_copy);
+  add_element_to_named_string_element_list (substrings,
+                                            "class", class_copy);
+
+  element_lang_translations
+    = new_element_language_translation (&converters_translation_cache,
+                                        element, TXI_CONVERT_STRINGS_NR);
+
+  if (builtin_command_data[def_command].flags & CF_def_class_method)
     {
-      ELEMENT *def_index_element
-        = def_command_index_entry ((ELEMENT *) element,
-                                   prefer_reference_element, document,
-                                   debug_level, converter,
-                                   element_cdt_tree_fn);
-
-      return def_index_element;
+      index_element = gdt_tree ("{name} on {class}",
+                document, element_lang_translations,
+                substrings, debug_level, 0);
     }
+  else if (builtin_command_data[def_command].flags & CF_def_class_variable)
+    {
+      index_element = gdt_tree ("{name} of {class}",
+                document, element_lang_translations,
+                substrings, debug_level, 0);
+    }
+  /* should not be possible, still considered for more robust code */
   else
-    {
-      ELEMENT *element_copy
-        = copy_element_tree (element->e.c->contents.list[0], 0);
-      return element_copy;
-    }
+    unexpected_def_name_class_message (def_command);
+
+  destroy_named_string_element_list (substrings);
+
+  /* prefer a type-less container rather than 'root_line' returned by gdt */
+  index_element->type = ET_NONE;
+
+  return index_element;
 }
 
-static char *
+char *
 strip_index_ignore_chars (const char *string, const char *index_ignore_chars)
 {
   TEXT result_text;
@@ -421,42 +396,12 @@
 /* corresponding perl code in Texinfo::Indices */
 
 char *
-index_entry_element_sort_string (const INDEX_ENTRY *main_entry,
-                                 const ELEMENT *index_entry_element,
-                                 TEXT_OPTIONS *options, int in_code,
-                                 int prefer_reference_element,
-                                 int debug_level,
-                                 CONVERTER *converter,
-   ELEMENT * (*element_cdt_tree_fn) (const char *string, const ELEMENT *element,
-                             CONVERTER *self,
-                             NAMED_STRING_ELEMENT_LIST *replaced_substrings,
-                             const char *translation_context)
-                                 )
+entry_tree_element_sort_string (const INDEX_ENTRY *main_entry,
+                                ELEMENT *entry_tree_element,
+                                TEXT_OPTIONS *options, int in_code)
 {
   char *sort_string;
-  char *index_ignore_chars;
-  ELEMENT *entry_tree_element;
-  int used_debug_level;
-
-  if (!index_entry_element)
-    {
-      fatal ("index_entry_element_sort_string: NULL element");
-    }
-
-  char *sortas = lookup_extra_string (index_entry_element, AI_key_sortas);
-  if (sortas)
-    return strdup (sortas);
-
-  if (debug_level < 0)
-    used_debug_level = options->DEBUG;
-  else
-    used_debug_level = debug_level;
-
-  entry_tree_element = index_content_element (index_entry_element,
-                                          prefer_reference_element,
-                                          options->document,
-                                          used_debug_level, converter,
-                                          element_cdt_tree_fn);
+  const char *index_ignore_chars;
 
   if (in_code)
     options->code_state++;
@@ -479,6 +424,46 @@
   return sort_string;
 }
 
+/* FIXME taking the document from options is not intuitive.  Pass
+   and explicit document?  Similarly, make sure that a correctly 
+   set debug_level is set, instead of using options->DEBUG? */
+char *
+index_entry_element_sort_string (const INDEX_ENTRY *main_entry,
+                                 const ELEMENT *index_entry_element,
+                                 TEXT_OPTIONS *options, int in_code,
+                                 int prefer_reference_element,
+                                 int debug_level, CONVERTER *converter)
+{
+  char *sort_string;
+  ELEMENT *entry_tree_element;
+  int used_debug_level;
+
+  if (!index_entry_element)
+    {
+      fatal ("index_entry_element_sort_string: NULL element");
+    }
+
+  char *sortas = lookup_extra_string (index_entry_element, AI_key_sortas);
+  if (sortas)
+    return strdup (sortas);
+
+  if (debug_level < 0)
+    used_debug_level = options->DEBUG;
+  else
+    used_debug_level = debug_level;
+
+  entry_tree_element = document_index_content_element (index_entry_element,
+                                          prefer_reference_element,
+                                          options->document,
+                                          used_debug_level);
+
+  sort_string = entry_tree_element_sort_string (main_entry,
+                                entry_tree_element, options, in_code);
+
+  return sort_string;
+}
+
+
 typedef struct INDEX_COLLATOR {
     enum collation_type_name type;
     union {
@@ -590,16 +575,20 @@
                     INDEX_LIST *indices_information,
                     int prefer_reference_element,
                     CONVERTER *converter,
-   ELEMENT * (*element_cdt_tree_fn) (const char *string, const ELEMENT *element,
-                             CONVERTER *self,
-                             NAMED_STRING_ELEMENT_LIST *replaced_substrings,
-                             const char *translation_context)
-                                 )
+   char *(*index_entry_element_sort_string_fn) (const INDEX_ENTRY *main_entry,
+                                 const ELEMENT *index_entry_element,
+                                 TEXT_OPTIONS *options, int in_code,
+                                 int prefer_reference_element,
+                                 int debug_level, CONVERTER *converter)
+                    )
 {
   size_t i;
   TEXT_OPTIONS *convert_text_options;
   CONST_ELEMENT_LIST subentries_list;
 
+  if (index_entry_element_sort_string_fn == 0)
+    index_entry_element_sort_string_fn = &index_entry_element_sort_string;
+
   if (merged_indices->number <= 0)
     return 0;
 
@@ -656,11 +645,11 @@
                                               index_entry->index_name);
 
               sort_string
-               = index_entry_element_sort_string (index_entry,
+               = (*index_entry_element_sort_string_fn) (index_entry,
                                      main_entry_element, convert_text_options,
                                      entry_index->in_code,
                                      prefer_reference_element, -1,
-                                     converter, element_cdt_tree_fn);
+                                     converter);
 
               entry_sort_string.entry = index_entry;
               entry_sort_string.subentries_number = 1;
@@ -718,10 +707,10 @@
                           entry_sort_string.subentries_number -1];
 
                   sort_string
-                    = index_entry_element_sort_string (index_entry,
+                    = (*index_entry_element_sort_string_fn) (index_entry,
                                      subentry, convert_text_options,
                                      entry_index->in_code, 0, -1,
-                                     converter, element_cdt_tree_fn);
+                                     converter);
 
                   if (sort_string[strspn
                      (sort_string, whitespace_chars)] == '\0')
@@ -918,26 +907,17 @@
 
 
 static INDICES_SORTABLE_ENTRIES *
-setup_sort_sortable_strings_collator (DOCUMENT *document,
+setup_sort_sortable_strings_collator (
+                      const INDICES_SORT_STRINGS *indices_sort_strings,
                       ERROR_MESSAGE_LIST *error_messages,
                       OPTIONS *options,
-                      CONVERTER *converter,
-   ELEMENT * (*element_cdt_tree_fn) (const char *string, const ELEMENT *element,
-                             CONVERTER *self,
-                             NAMED_STRING_ELEMENT_LIST *replaced_substrings,
-                             const char *translation_context),
                       int use_unicode_collation,
                       const char *collation_language,
                       const char *collation_locale,
                       INDEX_COLLATOR **collator)
 {
-  const INDICES_SORT_STRINGS *indices_sort_strings;
   INDICES_SORTABLE_ENTRIES *index_sortable_index_entries;
 
-  indices_sort_strings = document_indices_sort_strings (document,
-                                              error_messages, options,
-                                              converter, element_cdt_tree_fn);
-
   *collator = setup_collator (use_unicode_collation, collation_language,
                               collation_locale, error_messages, options);
 
@@ -1134,13 +1114,9 @@
 }
 
 INDEX_SORTED_BY_INDEX *
-sort_indices_by_index (DOCUMENT *document, ERROR_MESSAGE_LIST *error_messages,
+sort_indices_by_index (const INDICES_SORT_STRINGS *indices_sort_strings,
+                       ERROR_MESSAGE_LIST *error_messages,
                        OPTIONS *options,
-                       CONVERTER *converter,
-   ELEMENT * (*element_cdt_tree_fn) (const char *string, const ELEMENT *element,
-                             CONVERTER *self,
-                             NAMED_STRING_ELEMENT_LIST *replaced_substrings,
-                             const char *translation_context),
                        int use_unicode_collation,
                        const char *collation_language,
                        const char *collation_locale)
@@ -1150,8 +1126,8 @@
   INDEX_COLLATOR *collator;
 
   INDICES_SORTABLE_ENTRIES *indices_sortable_entries
-    = setup_sort_sortable_strings_collator (document, error_messages, options,
-                                    converter, element_cdt_tree_fn,
+    = setup_sort_sortable_strings_collator (indices_sort_strings,
+                                            error_messages, options,
                                     use_unicode_collation, collation_language,
                                     collation_locale, &collator);
 
@@ -1214,13 +1190,9 @@
 
 
 INDEX_SORTED_BY_LETTER *
-sort_indices_by_letter (DOCUMENT *document, ERROR_MESSAGE_LIST *error_messages,
+sort_indices_by_letter (const INDICES_SORT_STRINGS *indices_sort_strings,
+                        ERROR_MESSAGE_LIST *error_messages,
                         OPTIONS *options,
-                        CONVERTER *converter,
-   ELEMENT * (*element_cdt_tree_fn) (const char *string, const ELEMENT *element,
-                             CONVERTER *self,
-                             NAMED_STRING_ELEMENT_LIST *replaced_substrings,
-                             const char *translation_context),
                         int use_unicode_collation,
                         const char *collation_language,
                         const char *collation_locale)
@@ -1231,8 +1203,8 @@
   INDEX_COLLATOR *collator;
 
   INDICES_SORTABLE_ENTRIES *indices_sortable_entries
-    = setup_sort_sortable_strings_collator (document, error_messages, options,
-                                    converter, element_cdt_tree_fn,
+    = setup_sort_sortable_strings_collator (indices_sort_strings,
+                                            error_messages, options,
                                     use_unicode_collation, collation_language,
                                     collation_locale, &collator);
 
@@ -1472,187 +1444,263 @@
   return sorted_index_entries;
 }
 
-
-
-/* representation of index entries letter */
-
-static INDEX_ENTRY_TEXT_OR_COMMAND *
-new_index_entry_text_or_command (const char *text, ELEMENT *command)
+static COLLATION_INDICES_SORTED_BY_INDEX *
+new_collation_sorted_indices_by_index (
+            COLLATIONS_INDICES_SORTED_BY_INDEX *collations,
+            enum collation_type_name type,
+            const char *language)
 {
-  INDEX_ENTRY_TEXT_OR_COMMAND *result = (INDEX_ENTRY_TEXT_OR_COMMAND *)
-     malloc (sizeof (INDEX_ENTRY_TEXT_OR_COMMAND));
+  COLLATION_INDICES_SORTED_BY_INDEX *result = 0;
+  if (collations->number <= collations->space)
+    {
+      collations->collation_sorted_indices
+        = (COLLATION_INDICES_SORTED_BY_INDEX *) realloc
+           (collations->collation_sorted_indices,
+             (collations->space += 3)
+                * sizeof (COLLATION_INDICES_SORTED_BY_INDEX));
+      if (!collations->collation_sorted_indices)
+        fatal ("realloc failed");
+    }
 
-  if (text)
-    result->text = strdup (text);
-  else
-    result->text = 0;
-  result->command = command;
+  result = &collations->collation_sorted_indices[collations->number];
+  memset (result, 0, sizeof (COLLATION_INDICES_SORTED_BY_INDEX));
+  result->type = type;
+  result->language = strdup (language);
+
+  collations->number++;
 
   return result;
 }
 
-/* Return the first non empty text or textual @-command.
-   To be freed by caller.
-   NOTE quotes and dash are not handled especially and it is not known
-   if the text was in code or not. */
-static INDEX_ENTRY_TEXT_OR_COMMAND *
-idx_leading_text_or_command (ELEMENT *tree, const char *ignore_chars)
+COLLATIONS_INDICES_SORTED_BY_INDEX *
+new_base_collations_sorted_indices_by_index (void)
 {
-  size_t i;
+  COLLATIONS_INDICES_SORTED_BY_INDEX *collations
+       = (COLLATIONS_INDICES_SORTED_BY_INDEX *)
+           malloc (sizeof (COLLATIONS_INDICES_SORTED_BY_INDEX));
+  memset (collations, 0,
+              sizeof (COLLATIONS_INDICES_SORTED_BY_INDEX));
 
-  if (tree->e.c->contents.number <= 0)
-    return new_index_entry_text_or_command (0, 0);
+  /* order is important, to match enum */
+  new_collation_sorted_indices_by_index (collations, ctn_unicode, "-");
+  new_collation_sorted_indices_by_index (collations, ctn_no_unicode, "");
 
-  for (i = 0; i < tree->e.c->contents.number; i++)
-    {
-      ELEMENT *content = tree->e.c->contents.list[i];
-
-      if (type_data[content->type].flags & TF_text)
-        {
-          if (content->e.text->end > 0
-              && content->e.text->text[strspn
-                           (content->e.text->text, whitespace_chars)] != '\0')
-            {
-              char *p = content->e.text->text;
-              p += strspn (p, whitespace_chars);
-              if (ignore_chars)
-                {
-                  char *text = strip_index_ignore_chars (p, ignore_chars);
-                  INDEX_ENTRY_TEXT_OR_COMMAND *result = 0;
-
-                  if (text[strspn (text, whitespace_chars)] != '\0')
-                    result = new_index_entry_text_or_command (text, 0);
-
-                  free (text);
-
-                  if (result)
-                    return result;
-                  else
-                    continue;
-                }
-              else
-                return new_index_entry_text_or_command (p, 0);
-            }
-          else
-            continue;
-        }
-
-      if (content->e.c->cmd)
-        {
-          enum command_id data_cmd = element_builtin_data_cmd (content);
-
-          if (builtin_command_data[data_cmd].other_flags & CF_formatted_nobrace)
-            {
-              if (ignore_chars && data_cmd == CM_AT_SIGN
-                  && strchr (ignore_chars, '@'))
-                continue;
-              ELEMENT *copy = copy_element_tree (content, 0);
-              return new_index_entry_text_or_command (0, copy);
-            }
-          else
-            {
-              if (builtin_command_data[data_cmd].flags & CF_brace)
-                {
-                  int brace_command_type = builtin_command_data[data_cmd].data;
-
-                  if ((builtin_command_data[data_cmd].other_flags
-                       & CF_non_formatted_brace)
-                      || data_cmd == CM_footnote
-                      || data_cmd == CM_dmn
-                      || data_cmd == CM_value
-                      || (builtin_command_data[data_cmd].other_flags
-                          & CF_in_index))
-                    continue;
-                  else if (brace_command_type == BRACE_accent
-                           || brace_command_type == BRACE_noarg
-                           || data_cmd == CM_U)
-                    {
-                      ELEMENT *copy = copy_element_tree (content, 0);
-                      return new_index_entry_text_or_command (0, copy);
-                    }
-                  else if (brace_command_type != BRACE_inline)
-                    {
-                      if (content->e.c->contents.number > 0)
-                        {
-                          return idx_leading_text_or_command (
-                                               content->e.c->contents.list[0],
-                                                              ignore_chars);
-                        }
-                    }
-                  else
-                    {
-                      int status;
-                      int expand_index
-                       = lookup_extra_integer (content, AI_key_expand_index,
-                                               &status);
-                      if (expand_index > 0)
-                        return idx_leading_text_or_command (
-                                   content->e.c->contents.list[expand_index],
-                                                            ignore_chars);
-                    }
-                }
-              else if ((builtin_command_data[data_cmd].other_flags
-                        & CF_formatted_line)
-                       && data_cmd != CM_page)
-                {
-                   return idx_leading_text_or_command (
-                                           content->e.c->contents.list[0],
-                                                              ignore_chars);
-                }
-            }
-        }
-      else if (content->e.c->contents.number > 0)
-        return idx_leading_text_or_command (content, ignore_chars);
-    }
-  return new_index_entry_text_or_command (0, 0);
+  return collations;
 }
 
-/* Return the leading text or textual command that could be used
-   for sorting.
-   To be freed by caller.
-*/
-INDEX_ENTRY_TEXT_OR_COMMAND *
-index_entry_first_letter_text_or_command (const INDEX_ENTRY *index_entry,
-                                          DOCUMENT *document, int debug_level,
-                                          CONVERTER *converter,
-   ELEMENT * (*element_cdt_tree_fn) (const char *string, const ELEMENT *element,
-                             CONVERTER *self,
-                             NAMED_STRING_ELEMENT_LIST *replaced_substrings,
-                             const char *translation_context)
-                                         )
+static COLLATION_INDICES_SORTED_BY_INDEX *
+find_collation_sorted_indices_by_index (
+            COLLATIONS_INDICES_SORTED_BY_INDEX *collations,
+            enum collation_type_name type,
+            const char *language)
 {
-  ELEMENT *index_entry_element = index_entry->entry_element;
-  char *sortas = lookup_extra_string (index_entry_element, AI_key_sortas);
-
-  INDEX_ENTRY_TEXT_OR_COMMAND *result;
-
-  if (sortas)
+  size_t i;
+  for (i = 2; i < collations->number; i++)
     {
-      return new_index_entry_text_or_command (sortas, 0);
+      COLLATION_INDICES_SORTED_BY_INDEX *collation_sorted_indices
+        = &collations->collation_sorted_indices[i];
+      if (collation_sorted_indices->type == type
+          && !strcmp (collation_sorted_indices->language, language))
+        return collation_sorted_indices;
     }
+  return 0;
+}
+
+COLLATION_INDICES_SORTED_BY_INDEX *
+get_collation_sorted_indices_by_index (
+                              COLLATIONS_INDICES_SORTED_BY_INDEX *collations,
+                                       int use_unicode_collation,
+                                       const char *input_lang_sorting_locale,
+                                       const char *collation_locale,
+                                       const char **lang_sorting_locale_out)
+{
+  const char *lang_sorting_locale = 0;
+  COLLATION_INDICES_SORTED_BY_INDEX *collation_sorted_indices = 0;
+
+  if (use_unicode_collation == 0)
+    collation_sorted_indices
+      = &collations->collation_sorted_indices[ctn_no_unicode];
+  else if (!input_lang_sorting_locale && !collation_locale)
+    collation_sorted_indices
+      = &collations->collation_sorted_indices[ctn_unicode];
   else
     {
-      ELEMENT *entry_tree_element
-         = index_content_element (index_entry_element, 0, document,
-                                  debug_level, converter, element_cdt_tree_fn);
-      char *index_ignore_chars = lookup_extra_string (index_entry_element,
-                                                  AI_key_index_ignore_chars);
-      ELEMENT *parsed_element;
+      enum collation_type_name type;
 
-      if (entry_tree_element->e.c->contents.number <= 0)
+      if (input_lang_sorting_locale)
         {
-          parsed_element = new_element (ET_NONE);
-          add_to_contents_as_array (parsed_element, index_entry_element);
+          type = ctn_language_collation;
+          lang_sorting_locale = input_lang_sorting_locale;
         }
       else
-        parsed_element = entry_tree_element;
+        {
+          type = ctn_locale_collation;
+          lang_sorting_locale = collation_locale;
+        }
 
-      result = idx_leading_text_or_command (parsed_element, index_ignore_chars);
+      collation_sorted_indices
+        = find_collation_sorted_indices_by_index (collations, type,
+                                                 lang_sorting_locale);
+      if (!collation_sorted_indices)
+        collation_sorted_indices
+          = new_collation_sorted_indices_by_index (collations,
+                                                   type, lang_sorting_locale);
+    }
 
-      if (parsed_element != entry_tree_element)
-        destroy_element (parsed_element);
+  *lang_sorting_locale_out = lang_sorting_locale;
+  return collation_sorted_indices;
+}
 
-      return result;
+static COLLATION_INDICES_SORTED_BY_LETTER *
+new_collation_sorted_indices_by_letter (
+            COLLATIONS_INDICES_SORTED_BY_LETTER *collations,
+            enum collation_type_name type,
+            const char *language)
+{
+  COLLATION_INDICES_SORTED_BY_LETTER *result = 0;
+  if (collations->number <= collations->space)
+    {
+      collations->collation_sorted_indices
+        = (COLLATION_INDICES_SORTED_BY_LETTER *) realloc
+           (collations->collation_sorted_indices,
+             (collations->space += 3)
+                * sizeof (COLLATION_INDICES_SORTED_BY_LETTER));
+      if (!collations->collation_sorted_indices)
+        fatal ("realloc failed");
+    }
+
+  result = &collations->collation_sorted_indices[collations->number];
+  memset (result, 0, sizeof (COLLATION_INDICES_SORTED_BY_LETTER));
+  result->type = type;
+  result->language = strdup (language);
+
+  collations->number++;
+
+  return result;
+}
+
+static COLLATION_INDICES_SORTED_BY_LETTER *
+find_collation_sorted_indices_by_letter (
+            COLLATIONS_INDICES_SORTED_BY_LETTER *collations,
+            enum collation_type_name type,
+            const char *language)
+{
+  size_t i;
+  for (i = 2; i < collations->number; i++)
+    {
+      COLLATION_INDICES_SORTED_BY_LETTER *collation_sorted_indices
+        = &collations->collation_sorted_indices[i];
+      if (collation_sorted_indices->type == type
+          && !strcmp (collation_sorted_indices->language, language))
+        return collation_sorted_indices;
+    }
+  return 0;
+}
+
+COLLATIONS_INDICES_SORTED_BY_LETTER *
+new_base_collations_sorted_indices_by_letter (void)
+{
+  COLLATIONS_INDICES_SORTED_BY_LETTER *collations
+      = (COLLATIONS_INDICES_SORTED_BY_LETTER *)
+           malloc (sizeof (COLLATIONS_INDICES_SORTED_BY_LETTER));
+  memset (collations, 0,
+              sizeof (COLLATIONS_INDICES_SORTED_BY_LETTER));
+
+    /* order is important, to match enum */
+  new_collation_sorted_indices_by_letter (collations, ctn_unicode, "-");
+  new_collation_sorted_indices_by_letter (collations, ctn_no_unicode, "");
+
+  return collations;
+}
+
+COLLATION_INDICES_SORTED_BY_LETTER *
+get_collation_sorted_indices_by_letter (
+                          COLLATIONS_INDICES_SORTED_BY_LETTER *collations,
+                                       int use_unicode_collation,
+                                       const char *input_lang_sorting_locale,
+                                       const char *collation_locale,
+                                       const char **lang_sorting_locale_out)
+{
+  const char *lang_sorting_locale = 0;
+  COLLATION_INDICES_SORTED_BY_LETTER *collation_sorted_indices = 0;
+
+  if (use_unicode_collation == 0)
+    collation_sorted_indices
+      = &collations->collation_sorted_indices[ctn_no_unicode];
+  else if (!input_lang_sorting_locale && !collation_locale)
+    collation_sorted_indices
+      = &collations->collation_sorted_indices[ctn_unicode];
+  else
+    {
+      enum collation_type_name type;
+
+      if (input_lang_sorting_locale)
+        {
+          type = ctn_language_collation;
+          lang_sorting_locale = input_lang_sorting_locale;
+        }
+      else
+        {
+          type = ctn_locale_collation;
+          lang_sorting_locale = collation_locale;
+        }
+
+      collation_sorted_indices
+        = find_collation_sorted_indices_by_letter (collations, type,
+                                                   lang_sorting_locale);
+      if (!collation_sorted_indices)
+        collation_sorted_indices
+          = new_collation_sorted_indices_by_letter (collations,
+                                                    type, lang_sorting_locale);
+    }
+
+  *lang_sorting_locale_out = lang_sorting_locale;
+  return collation_sorted_indices;
+}
+
+void
+destroy_sorted_indices_by_index (COLLATIONS_INDICES_SORTED_BY_INDEX *collations)
+{
+  if (collations)
+    {
+      if (collations->number > 0)
+        {
+          size_t i;
+          for (i = 0; i < collations->number; i++)
+            {
+              COLLATION_INDICES_SORTED_BY_INDEX *collation_sorted_indices
+                = &collations->collation_sorted_indices[i];
+              free (collation_sorted_indices->language);
+              if (collation_sorted_indices->sorted_indices)
+                destroy_indices_sorted_by_index (
+                                collation_sorted_indices->sorted_indices);
+            }
+        }
+      free (collations->collation_sorted_indices);
+      free (collations);
+    }
+}
+
+void
+destroy_sorted_indices_by_letter (COLLATIONS_INDICES_SORTED_BY_LETTER *collations)
+{
+  if (collations)
+    {
+      if (collations->number > 0)
+        {
+          size_t i;
+          for (i = 0; i < collations->number; i++)
+            {
+              COLLATION_INDICES_SORTED_BY_LETTER *collation_sorted_indices
+                 = &collations->collation_sorted_indices[i];
+              free (collation_sorted_indices->language);
+              if (collation_sorted_indices->sorted_indices)
+                destroy_indices_sorted_by_letter (
+                                collation_sorted_indices->sorted_indices);
+            }
+        }
+      free (collations->collation_sorted_indices);
+      free (collations);
     }
 }
 
diff --git a/tta/C/main/manipulate_indices.h b/tta/C/main/manipulate_indices.h
index ecf68e2..b06cb9e 100644
--- a/tta/C/main/manipulate_indices.h
+++ b/tta/C/main/manipulate_indices.h
@@ -38,11 +38,6 @@
     INDEX_SORTABLE_ENTRIES *indices;
 } INDICES_SORTABLE_ENTRIES;
 
-typedef struct INDEX_ENTRY_TEXT_OR_COMMAND {
-    char *text;
-    ELEMENT *command;
-} INDEX_ENTRY_TEXT_OR_COMMAND;
-
 MERGED_INDICES *merge_indices (INDEX_LIST *indices_information);
 void destroy_merged_indices (MERGED_INDICES *merged_indices);
 
@@ -51,27 +46,46 @@
 void destroy_indices_sorted_by_letter (
          INDEX_SORTED_BY_LETTER *indices_entries_by_letter);
 
-ELEMENT *index_content_element (const ELEMENT *element,
-                       int prefer_reference_element,
-                       DOCUMENT *document, int debug_level,
-                       CONVERTER *converter,
-   ELEMENT * (*element_cdt_tree_fn) (const char *string, const ELEMENT *element,
-                             CONVERTER *self,
-                             NAMED_STRING_ELEMENT_LIST *replaced_substrings,
-                             const char *translation_context)
-                      );
+ELEMENT *get_index_content_info_element (const ELEMENT *element,
+                                         int prefer_reference_element,
+                                         enum command_id *def_command_out,
+                                         ELEMENT **name_copy_out,
+                                         ELEMENT **class_copy_out);
+ELEMENT *document_index_content_element (const ELEMENT *element,
+                                int prefer_reference_element,
+                                DOCUMENT *document, int debug_level);
+
+char *strip_index_ignore_chars (const char *string,
+                                const char *index_ignore_chars);
 
 char *index_entry_element_sort_string (const INDEX_ENTRY *main_entry,
                                  const ELEMENT *index_entry_element,
                                  struct TEXT_OPTIONS *options, int in_code,
                                  int prefer_reference_element,
-                                 int debug_level,
-                                 CONVERTER *converter,
-   ELEMENT * (*element_cdt_tree_fn) (const char *string, const ELEMENT *element,
-                             CONVERTER *self,
-                             NAMED_STRING_ELEMENT_LIST *replaced_substrings,
-                             const char *translation_context)
-                                 );
+                                 int debug_level, CONVERTER *converter);
+char *entry_tree_element_sort_string (const INDEX_ENTRY *main_entry,
+                                      ELEMENT *entry_tree_element,
+                                      struct TEXT_OPTIONS *options,
+                                      int in_code);
+
+COLLATIONS_INDICES_SORTED_BY_INDEX *
+new_base_collations_sorted_indices_by_index (void);
+COLLATION_INDICES_SORTED_BY_INDEX *
+get_collation_sorted_indices_by_index (
+                             COLLATIONS_INDICES_SORTED_BY_INDEX *collations,
+                                       int use_unicode_collation,
+                                       const char *input_lang_sorting_locale,
+                                       const char *collation_locale,
+                                       const char **lang_sorting_locale_out);
+COLLATIONS_INDICES_SORTED_BY_LETTER *
+new_base_collations_sorted_indices_by_letter (void);
+COLLATION_INDICES_SORTED_BY_LETTER *
+get_collation_sorted_indices_by_letter (
+                          COLLATIONS_INDICES_SORTED_BY_LETTER *collations,
+                                       int use_unicode_collation,
+                                       const char *input_lang_sorting_locale,
+                                       const char *collation_locale,
+                                       const char **lang_sorting_locale_out);
 
 void destroy_index_entries_sort_strings (
                           INDICES_SORT_STRINGS *indices_sort_strings);
@@ -81,45 +95,33 @@
                     INDEX_LIST *indices_information,
                     int prefer_reference_element,
                     CONVERTER *converter,
-   ELEMENT * (*element_cdt_tree_fn) (const char *string, const ELEMENT *element,
-                             CONVERTER *self,
-                             NAMED_STRING_ELEMENT_LIST *replaced_substrings,
-                             const char *translation_context)
-                                 );
+   char *(*index_entry_element_sort_string_fn) (const INDEX_ENTRY *main_entry,
+                                 const ELEMENT *index_entry_element,
+                                 struct TEXT_OPTIONS *options, int in_code,
+                                 int prefer_reference_element,
+                                 int debug_level, CONVERTER *converter)
+);
+
+void destroy_sorted_indices_by_index (
+                       COLLATIONS_INDICES_SORTED_BY_INDEX *collations);
+void destroy_sorted_indices_by_letter (
+                       COLLATIONS_INDICES_SORTED_BY_LETTER *collations);
 
 INDEX_SORTED_BY_INDEX *sort_indices_by_index (
-                       DOCUMENT *document, ERROR_MESSAGE_LIST *error_messages,
+                       const INDICES_SORT_STRINGS *indices_sort_strings,
+                       ERROR_MESSAGE_LIST *error_messages,
                        OPTIONS *options,
-                       CONVERTER *converter,
-   ELEMENT * (*element_cdt_tree_fn) (const char *string, const ELEMENT *element,
-                             CONVERTER *self,
-                             NAMED_STRING_ELEMENT_LIST *replaced_substrings,
-                             const char *translation_context),
                        int use_unicode_collation,
                        const char *collation_language,
                        const char *collation_locale);
 
 INDEX_SORTED_BY_LETTER *sort_indices_by_letter (
-                        DOCUMENT *document, ERROR_MESSAGE_LIST *error_messages,
-                        OPTIONS *options,
-                        CONVERTER *converter,
-   ELEMENT * (*element_cdt_tree_fn) (const char *string, const ELEMENT *element,
-                             CONVERTER *self,
-                             NAMED_STRING_ELEMENT_LIST *replaced_substrings,
-                             const char *translation_context),
-                        int use_unicode_collation,
-                        const char *collation_language,
-                        const char *collation_locale);
-
-INDEX_ENTRY_TEXT_OR_COMMAND *index_entry_first_letter_text_or_command (
-                                          const INDEX_ENTRY *index_entry,
-                                          DOCUMENT *document, int debug_level,
-                                          CONVERTER *converter,
-   ELEMENT * (*element_cdt_tree_fn) (const char *string, const ELEMENT *element,
-                             CONVERTER *self,
-                             NAMED_STRING_ELEMENT_LIST *replaced_substrings,
-                             const char *translation_context)
-                                         );
+                       const INDICES_SORT_STRINGS *indices_sort_strings,
+                       ERROR_MESSAGE_LIST *error_messages,
+                       OPTIONS *options,
+                       int use_unicode_collation,
+                       const char *collation_language,
+                       const char *collation_locale);
 
 const INDEX **sort_index_names (INDEX_LIST *indices_info);
 char *print_indices_information (INDEX_LIST *indices_info);
diff --git a/tta/perl/Texinfo/Convert/Converter.pm b/tta/perl/Texinfo/Convert/Converter.pm
index f6d237e..aeaab91 100644
--- a/tta/perl/Texinfo/Convert/Converter.pm
+++ b/tta/perl/Texinfo/Convert/Converter.pm
@@ -150,9 +150,7 @@
 sub conversion_initialization($;$) {
   my ($converter, $document) = @_;
 
-  if (defined($document)) {
-    $converter->set_document($document);
-  }
+  $converter->set_document($document);
 }
 
 sub conversion_finalization($) {
@@ -418,6 +416,10 @@
     delete $self->{'index_formatting_text_options'}->{'converter'};
   }
 
+  delete $self->{'sorted_indices_by_letter'};
+  delete $self->{'sorted_indices_by_index'};
+  delete $self->{'index_entries_sort_strings'};
+
   # common translations cache
   delete $self->{'current_lang_translations'};
 }
@@ -926,6 +928,90 @@
 # useful methods for Converters.
 # First methods are also used in this module.
 
+sub converter_indices_sort_strings($) {
+  my $converter = shift;
+
+  if (!exists($converter->{'index_entries_sort_strings'})) {
+    my $document = $converter->{'document'};
+    my $indices_sort_strings
+      = Texinfo::Indices::setup_index_entries_sort_strings(undef,
+              $converter, $document->merged_indices(),
+              $document->indices_information(), 0);
+    $converter->{'index_entries_sort_strings'} = $indices_sort_strings;
+  }
+  return $converter->{'index_entries_sort_strings'};
+}
+
+# calls Texinfo::Indices::sort_indices_by_letter and caches the result.
+# No XS override, as there is no reason to call this function directly
+# outside of tests, Texinfo::Convert::Converter
+# get_converter_indices_sorted_by_letter should be called directly.
+sub _converter_sorted_indices_by_letter($$$) {
+  my ($converter, $use_unicode_collation, $lang_sorting_locale) = @_;
+
+  my $lang_key;
+  if (!$use_unicode_collation) {
+    $lang_key = '';
+  } elsif (!defined($lang_sorting_locale)) {
+    # special name corresponding to Unicode Collation with 'Non-Ignorable'
+    # set for variable collation elements
+    $lang_key = '-';
+  } else {
+    $lang_key = $lang_sorting_locale;
+  }
+
+  $converter->{'sorted_indices_by_letter'} = {}
+    if (!exists($converter->{'sorted_indices_by_letter'}));
+
+  if (!exists($converter->{'sorted_indices_by_letter'}->{$lang_key})) {
+    $converter->{'document'}->merged_indices();
+
+    my $indices_sort_strings = converter_indices_sort_strings($converter);
+
+    $converter->{'sorted_indices_by_letter'}->{$lang_key}
+      = Texinfo::Indices::sort_indices_by_letter(
+                     $indices_sort_strings,
+                     $use_unicode_collation, $lang_sorting_locale);
+  }
+  return $converter->{'sorted_indices_by_letter'}->{$lang_key};
+}
+
+# calls Texinfo::Indices::sort_indices_by_index and caches the result.
+# No XS override, as there is no reason to call this function directly
+# outside of tests, Texinfo::Convert::Converter
+# get_converter_indices_sorted_by_index should be called directly.
+# In general a CONVERTER argument is given, but if not the DOCUMENT is
+# used instead to register error messages.
+sub _converter_sorted_indices_by_index($$$) {
+  my ($converter, $use_unicode_collation, $lang_sorting_locale) = @_;
+
+  my $lang_key;
+  if (!$use_unicode_collation) {
+    $lang_key = '';
+  } elsif (!defined($lang_sorting_locale)) {
+    # special name corresponding to Unicode Collation with 'Non-Ignorable'
+    # set for variable collation elements
+    $lang_key = '-';
+  } else {
+    $lang_key = $lang_sorting_locale;
+  }
+
+  $converter->{'sorted_indices_by_index'} = {}
+    if (!exists($converter->{'sorted_indices_by_index'}));
+
+  if (!exists($converter->{'sorted_indices_by_index'}->{$lang_key})) {
+    $converter->{'document'}->merged_indices();
+
+    my $indices_sort_strings = converter_indices_sort_strings($converter);
+
+    $converter->{'sorted_indices_by_index'}->{$lang_key}
+      = Texinfo::Indices::sort_indices_by_index(
+                       $indices_sort_strings,
+                       $use_unicode_collation, $lang_sorting_locale);
+  }
+  return $converter->{'sorted_indices_by_index'}->{$lang_key};
+}
+
 # Generic/overall document methods
 
 sub create_destination_directory($$$) {
@@ -1885,12 +1971,9 @@
   }
 
   sub conversion_initialization($;$) {
-    my $self = shift;
-    my $document = shift;
+    my ($self, $document) = @_;
 
-    if ($document) {
-      $self->set_document($document);
-    }
+    $self->set_document($document);
 
     $self->set_global_document_commands('before', \@global_commands);
     ...
@@ -1908,8 +1991,7 @@
   }
 
   sub convert($$) {
-    my $self = shift;
-    my $document = shift;
+    my ($self, $document) = @_;
 
     $self->conversion_initialization($document);
 
@@ -1918,8 +2000,7 @@
   }
 
   sub output($$) {
-    my $self = shift;
-    my $document = shift;
+    my ($self, $document) = @_;
 
     $self->conversion_initialization($document);
 
@@ -2107,8 +2188,10 @@
 
 Associate I<$document> to I<$converter>.  Also set the encoding related customization
 options based on I<$converter> customization information and information on
-document encoding, and setup converter hash C<convert_text_options> value that
+document encoding, setup converter hash C<convert_text_options> value that
 can be used to call L<C<Texinfo::Convert::Text::convert_to_text>|Texinfo::Convert::Text/$result = convert_to_text($tree, $text_options)>.
+Also resets generic converter information that is invalidated by
+a new document.
 
 =back
 
diff --git a/tta/perl/Texinfo/Convert/ConverterNonXS.pm b/tta/perl/Texinfo/Convert/ConverterNonXS.pm
index f8e4e23..6cacea9 100644
--- a/tta/perl/Texinfo/Convert/ConverterNonXS.pm
+++ b/tta/perl/Texinfo/Convert/ConverterNonXS.pm
@@ -91,10 +91,16 @@
     $converter->{'document'} = $document;
 
     Texinfo::Common::set_output_encoding($converter, $document);
+  } else {
+    delete $converter->{'document'};
   }
 
   $converter->{'convert_text_options'}
      = Texinfo::Convert::Text::copy_options_for_convert_text($converter);
+
+  delete $converter->{'sorted_indices_by_letter'};
+  delete $converter->{'sorted_indices_by_index'};
+  delete $converter->{'index_entries_sort_strings'};
 }
 
 # initialization either in generic XS converter or in Perl
@@ -451,8 +457,8 @@
         }
       }
 
-      return Texinfo::Document::sorted_indices_by_letter($self->{'document'},
-                        $self, $use_unicode_collation, $lang_sorting_locale);
+      return _converter_sorted_indices_by_letter($self,
+                               $use_unicode_collation, $lang_sorting_locale);
     }
   }
   return undef;
@@ -485,8 +491,8 @@
         }
       }
 
-      return Texinfo::Document::sorted_indices_by_index($self->{'document'},
-                        $self, $use_unicode_collation, $lang_sorting_locale);
+      return _converter_sorted_indices_by_index($self,
+                                $use_unicode_collation, $lang_sorting_locale);
     }
   }
   return undef;
diff --git a/tta/perl/Texinfo/Convert/DocBook.pm b/tta/perl/Texinfo/Convert/DocBook.pm
index 26c405c..a69c4b8 100644
--- a/tta/perl/Texinfo/Convert/DocBook.pm
+++ b/tta/perl/Texinfo/Convert/DocBook.pm
@@ -324,9 +324,7 @@
 sub conversion_initialization($;$) {
   my ($self, $document) = @_;
 
-  if (defined($document)) {
-    $self->set_document($document);
-  }
+  $self->set_document($document);
 
   $self->{'document_context'} = [];
   _new_document_context($self);
@@ -698,8 +696,8 @@
       if ($index_info->{'in_code'});
     $result .= "<primary>";
     my $index_element = Texinfo::Common::non_leading_trailing_tree(
-                         Texinfo::Indices::index_content_element($element,
-                                                                 0, $self));
+           Texinfo::Indices::converter_index_content_element(
+                                            $element, $self, 0));
     $result .= $self->_convert($index_element);
     $result .= "</primary>";
 
diff --git a/tta/perl/Texinfo/Convert/HTML.pm b/tta/perl/Texinfo/Convert/HTML.pm
index 49428e9..aaec5a9 100644
--- a/tta/perl/Texinfo/Convert/HTML.pm
+++ b/tta/perl/Texinfo/Convert/HTML.pm
@@ -4804,8 +4804,8 @@
                                 $index_entry_ref, $formatted_index_entry_nr);
 
       my $entry_content_element
-        = Texinfo::Indices::index_content_element($main_entry_element, 0,
-                                                  $self);
+        = Texinfo::Indices::converter_index_content_element(
+                                         $main_entry_element, $self, 0);
 
       my $entry_index_name = $index_entry_ref->{'index_name'};
       my $in_code = 0;
diff --git a/tta/perl/Texinfo/Convert/HTMLNonXS.pm b/tta/perl/Texinfo/Convert/HTMLNonXS.pm
index c41d829..3406a30 100644
--- a/tta/perl/Texinfo/Convert/HTMLNonXS.pm
+++ b/tta/perl/Texinfo/Convert/HTMLNonXS.pm
@@ -3740,8 +3740,8 @@
         $region = "$main_entry_element->{'extra'}->{'element_region'}-"
           if (defined($main_entry_element->{'extra'}->{'element_region'}));
         my $entry_reference_content_element
-          = Texinfo::Indices::index_content_element($main_entry_element, 1,
-                                                    $self);
+          = Texinfo::Indices::converter_index_content_element(
+                                   $main_entry_element, $self, 1);
         # construct element to convert to a normalized identifier to use as
         # hrefs target
         my $normalize_index_element = Texinfo::TreeElement::new(
@@ -5586,8 +5586,8 @@
                                           $self->{'convert_text_options'});
           }
           my $entry_reference_content_element
-            = Texinfo::Indices::index_content_element($main_entry_element,
-                                                      0, $self);
+            = Texinfo::Indices::converter_index_content_element(
+                                       $main_entry_element, $self, 0);
           my @contents = ($entry_reference_content_element);
           my $subentries_tree
             = Texinfo::Convert::Utils::comma_index_subentries_tree(
diff --git a/tta/perl/Texinfo/Convert/LaTeX.pm b/tta/perl/Texinfo/Convert/LaTeX.pm
index 6ed018e..eac9e9b 100644
--- a/tta/perl/Texinfo/Convert/LaTeX.pm
+++ b/tta/perl/Texinfo/Convert/LaTeX.pm
@@ -891,9 +891,7 @@
 sub conversion_initialization($;$) {
   my ($self, $document) = @_;
 
-  if (defined($document)) {
-    $self->set_document($document);
-  }
+  $self->set_document($document);
 
   # note that we use Texinfo::Common::document_settable_at_commands and not
   # informative_commands as in informative_commands set and clear have
@@ -2649,8 +2647,8 @@
     my @result;
     foreach my $subindex_command (@subindex_commands) {
       my $content
-         = Texinfo::Indices::index_content_element($subindex_command, 1,
-                                                   $self);
+        = Texinfo::Indices::converter_index_content_element(
+                                      $subindex_command, $self, 1);
       if ($in_code) {
         push @{$self->{'formatting_context'}->[-1]->{'code'}}, 1;
       }
diff --git a/tta/perl/Texinfo/Convert/Plaintext.pm b/tta/perl/Texinfo/Convert/Plaintext.pm
index cc27c24..565a832 100644
--- a/tta/perl/Texinfo/Convert/Plaintext.pm
+++ b/tta/perl/Texinfo/Convert/Plaintext.pm
@@ -441,9 +441,7 @@
 sub conversion_initialization($;$) {
   my ($self, $document) = @_;
 
-  if (defined($document)) {
-    $self->set_document($document);
-  }
+  $self->set_document($document);
 
   $self->set_global_document_commands('before', \@informative_global_commands);
   $self->set_global_document_commands('before', \@contents_commands);
@@ -1945,8 +1943,8 @@
     my $main_entry_element = $entry->{'entry_element'};
     my $entry_index_name = $entry->{'index_name'};
     my $entry_content_element
-      = Texinfo::Indices::index_content_element($main_entry_element, 0,
-                                                $self);
+      = Texinfo::Indices::converter_index_content_element(
+                                       $main_entry_element, $self, 0);
     my $entry_tree
      = Texinfo::TreeElement::new({'contents' => [$entry_content_element]});
     my $subentries_tree
diff --git a/tta/perl/Texinfo/Document.pm b/tta/perl/Texinfo/Document.pm
index da9ecc5..6655c15 100644
--- a/tta/perl/Texinfo/Document.pm
+++ b/tta/perl/Texinfo/Document.pm
@@ -318,8 +318,8 @@
 # get_converter_indices_sorted_by_letter should be called directly.
 # In general a CONVERTER argument is given, but if not the DOCUMENT is
 # used instead to register error messages.
-sub sorted_indices_by_letter($$$$) {
-  my ($document, $converter, $use_unicode_collation, $lang_sorting_locale) = @_;
+sub sorted_indices_by_letter($$$) {
+  my ($document, $use_unicode_collation, $lang_sorting_locale) = @_;
 
   my $lang_key;
   if (!$use_unicode_collation) {
@@ -337,9 +337,13 @@
 
   if (!exists($document->{'sorted_indices_by_letter'}->{$lang_key})) {
     $document->merged_indices();
+
+    my $indices_sort_strings
+      = document_indices_sort_strings($document);
+
     $document->{'sorted_indices_by_letter'}->{$lang_key}
-      = Texinfo::Indices::sort_indices_by_letter
-                    ($document, $converter,
+      = Texinfo::Indices::sort_indices_by_letter(
+                     $indices_sort_strings,
                      $use_unicode_collation, $lang_sorting_locale);
   }
   return $document->{'sorted_indices_by_letter'}->{$lang_key};
@@ -351,8 +355,8 @@
 # get_converter_indices_sorted_by_index should be called directly.
 # In general a CONVERTER argument is given, but if not the DOCUMENT is
 # used instead to register error messages.
-sub sorted_indices_by_index($$$$) {
-  my ($document, $converter, $use_unicode_collation, $lang_sorting_locale) = @_;
+sub sorted_indices_by_index($$$) {
+  my ($document, $use_unicode_collation, $lang_sorting_locale) = @_;
 
   my $lang_key;
   if (!$use_unicode_collation) {
@@ -370,9 +374,12 @@
 
   if (!exists($document->{'sorted_indices_by_index'}->{$lang_key})) {
     $document->merged_indices();
+
+    my $indices_sort_strings
+      = document_indices_sort_strings($document);
+
     $document->{'sorted_indices_by_index'}->{$lang_key}
-      = Texinfo::Indices::sort_indices_by_index
-                      ($document, $converter,
+      = Texinfo::Indices::sort_indices_by_index($indices_sort_strings,
                        $use_unicode_collation, $lang_sorting_locale);
   }
   return $document->{'sorted_indices_by_index'}->{$lang_key};
diff --git a/tta/perl/Texinfo/DocumentNonXS.pm b/tta/perl/Texinfo/DocumentNonXS.pm
index 9476eb0..e5a50b9 100644
--- a/tta/perl/Texinfo/DocumentNonXS.pm
+++ b/tta/perl/Texinfo/DocumentNonXS.pm
@@ -198,10 +198,10 @@
 # to Perl when only setup_indices_sort_strings is called.  It is thus possible
 # to call setup_indices_sort_strings but delay building Perl data until
 # the indices_sort_strings function is called.
-sub indices_sort_strings($$) {
-  my ($document, $converter) = @_;
+sub document_indices_sort_strings($) {
+  my $document = shift;
 
-  setup_indices_sort_strings($document, $converter);
+  setup_indices_sort_strings($document, undef);
   return $document->{'index_entries_sort_strings'};
 }
 
@@ -245,14 +245,14 @@
     my $lang_sorting_locale = $document->get_conf('COLLATION_LANGUAGE');
   }
 
-  my $indices_sort_strings = indices_sort_strings($document, $converter);
+  my $indices_sort_strings = document_indices_sort_strings($document);
 
   my $index_entries_sort_strings
    = Texinfo::Indices::format_index_entries_sort_strings(
                                                      $indices_sort_strings);
 
   my $sorted_index_entries
-       = sorted_indices_by_index($document, undef,
+       = sorted_indices_by_index($document,
                             $use_unicode_collation, $lang_sorting_locale);
 
   my $idx_sort_strings_str = '';
diff --git a/tta/perl/Texinfo/Example/IXIN.pm b/tta/perl/Texinfo/Example/IXIN.pm
index f9c1317..73ab7b7 100644
--- a/tta/perl/Texinfo/Example/IXIN.pm
+++ b/tta/perl/Texinfo/Example/IXIN.pm
@@ -726,7 +726,8 @@
         my $associated_node_id = $main_entry_element->{'extra'}->{'element_node'};
         $associated_node_id = -1 if (!defined($associated_node_id));
         my $entry_content_element
-          = Texinfo::Indices::index_content_element($main_entry_element);
+          = Texinfo::Indices::converter_index_content_element($self,
+                                                       $main_entry_element);
         my $entry = $self->convert_tree($entry_content_element);
         $dts_text_result .= $self->ixin_open_element('dtsentry',
                                                 [['nodeid', $associated_node_id]]);
diff --git a/tta/perl/Texinfo/Example/ReadDocBook.pm b/tta/perl/Texinfo/Example/ReadDocBook.pm
index 5ecf54c..95e68c8 100644
--- a/tta/perl/Texinfo/Example/ReadDocBook.pm
+++ b/tta/perl/Texinfo/Example/ReadDocBook.pm
@@ -360,9 +360,7 @@
   my $self = shift;
   my $document = shift;
 
-  if ($document) {
-    $self->set_document($document);
-  }
+  $self->set_document($document);
 
   $self->{'document_context'} = [];
   _new_document_context($self);
@@ -823,7 +821,7 @@
   if ($index_entry) {
     $result .= $index_entry_text;
     $result .= $self->convert_tree(
-      Texinfo::Indices::index_content_element($element));
+      Texinfo::Indices::converter_index_content_element($element, $self));
     $result .= _end_index_entry($self, $element);
   }
   _new_document_context($self);
@@ -1003,7 +1001,8 @@
             if ($index_entry) {
               $result_text .= $index_entry_text;
               $result_text .= $self->convert_tree(
-                    Texinfo::Indices::index_content_element($element));
+                Texinfo::Indices::converter_index_content_element($element,
+                                                                  $self));
               $result_text .= _end_index_entry($self, $element);
             }
             if (exists($element->{'contents'}->[0]->{'contents'})) {
diff --git a/tta/perl/Texinfo/Example/TexinfoMarkup.pm b/tta/perl/Texinfo/Example/TexinfoMarkup.pm
index 24863aa..5d3fa7d 100644
--- a/tta/perl/Texinfo/Example/TexinfoMarkup.pm
+++ b/tta/perl/Texinfo/Example/TexinfoMarkup.pm
@@ -291,9 +291,7 @@
 sub conversion_initialization($;$) {
   my ($self, $document) = @_;
 
-  if ($document) {
-    $self->set_document($document);
-  }
+  $self->set_document($document);
 
   $self->{'document_context'} = [{'monospace' => [0]}];
 }
@@ -376,7 +374,7 @@
     $self->{'document_context'}->[-1]->{'monospace'}->[-1] = 1
       if ($in_code);
     my $index_element = Texinfo::Common::non_leading_trailing_tree(
-                   Texinfo::Indices::index_content_element($element));
+       Texinfo::Indices::converter_index_content_element($element, $self));
     $result .= $self->_convert($index_element);
     pop @{$self->{'document_context'}};
     $result .= $self->txi_markup_close_element('indexterm');
diff --git a/tta/perl/Texinfo/Indices.pm b/tta/perl/Texinfo/Indices.pm
index da93c07..578cae6 100644
--- a/tta/perl/Texinfo/Indices.pm
+++ b/tta/perl/Texinfo/Indices.pm
@@ -175,6 +175,77 @@
   }
 }
 
+sub get_index_content_info_element($;$) {
+  my ($element, $prefer_reference_element) = @_;
+
+  if (!exists($element->{'extra'})
+      or !exists($element->{'extra'}->{'def_command'})) {
+    # the copy is not strictly needed, but we want to obtain the same
+    # result as with C and the result is different with anchors
+    # in index entries.
+    my $copy = Texinfo::ManipulateTree::copy_element_tree(
+                                           $element->{'contents'}->[0]);
+    return $copy, undef, undef;
+  }
+
+  my ($name, $class);
+  if (exists($element->{'contents'}->[0]->{'contents'})) {
+    foreach my $arg (@{$element->{'contents'}->[0]->{'contents'}}) {
+      my $type = $arg->{'type'};
+      if ($type eq 'def_name') {
+        $name = $arg;
+      } elsif ($type eq 'def_class') {
+        $class = $arg;
+      } elsif ($type eq 'def_arg' or $type eq 'def_typearg'
+               or $type eq 'delimiter') {
+        last;
+      }
+    }
+  }
+
+  if (defined($name)) {
+    my $def_command = $element->{'extra'}->{'def_command'};
+    my $name_copy = Texinfo::ManipulateTree::copy_element_tree($name);
+
+    if (!exists($Texinfo::Commands::def_class_variable_commands{
+                                                         $def_command})
+        and !exists($Texinfo::Commands::def_class_method_commands{
+                                           $def_command})) {
+      _remove_def_types($name_copy);
+      return $name_copy, undef, undef;
+    }
+
+    if (defined($class)) {
+      my $class_copy = Texinfo::ManipulateTree::copy_element_tree($class);
+
+      foreach my $element_copy ($class_copy, $name_copy) {
+        _remove_def_types($element_copy);
+      }
+
+      if ($prefer_reference_element) {
+        my $text_element;
+        my $index_entry_normalized = Texinfo::TreeElement::new({});
+
+        if (exists($Texinfo::Commands::def_class_method_commands{
+                                                   $def_command})) {
+          $text_element = Texinfo::TreeElement::new({'text' => ' on '});
+        } elsif (exists($Texinfo::Commands::def_class_variable_commands{
+                                                       $def_command})) {
+          $text_element = Texinfo::TreeElement::new({'text' => ' of '});
+        }
+
+        $index_entry_normalized->{'contents'}
+          = [$name_copy, $text_element, $class_copy];
+
+        return $index_entry_normalized, undef, undef;
+      } else {
+        return undef, $name_copy, $class_copy;
+      }
+    }
+  }
+  return undef, undef, undef;
+}
+
 # generate a Texinfo tree corresponding to a def command index entry.
 # If $PREFER_REFRENCE_ELEMENT is set do not translate.  If there is
 # no translation, $CONVERTER and $DEBUG_LEVEL are not actually used.
@@ -291,21 +362,82 @@
 
 # ALTIMP C/main/manipulate_indices.c
 # if $PREFER_REFERENCE_ELEMENT is set, prefer an untranslated element.
-sub index_content_element($;$$$) {
-  my ($element, $prefer_reference_element, $converter, $debug_level) = @_;
+sub document_index_content_element($;$$) {
+  my ($element, $prefer_reference_element, $debug_level) = @_;
 
-  if (exists($element->{'extra'})
-      and exists($element->{'extra'}->{'def_command'})) {
-    return _def_command_index_entry($element, $prefer_reference_element,
-                                    $converter, $debug_level);
-  } else {
-    # the copy is not strictly needed, but we want to obtain the same
-    # result as with C and the result is different with anchors
-    # in index entries.
-    my $copy = Texinfo::ManipulateTree::copy_element_tree(
-                                           $element->{'contents'}->[0]);
-    return $copy;
+  my ($index_element, $name_copy, $class_copy)
+   = get_index_content_info_element($element, $prefer_reference_element);
+
+  if (defined($index_element) or !defined($class_copy)) {
+    return $index_element;
   }
+
+  # Use the language information that was current when the command was
+  # used for getting the translation.
+  my $substrings = {'name' => $name_copy, 'class' => $class_copy};
+  my $def_command = $element->{'extra'}->{'def_command'};
+
+  my $element_lang_translations
+    = Texinfo::Translations::new_element_language_translation(
+            $Texinfo::Translations::converters_translation_cache,
+                    $element);
+
+  if (exists($Texinfo::Commands::def_class_method_commands{
+                                                   $def_command})) {
+  # TRANSLATORS: association of a method or operation name with a class
+  # in descriptions of object-oriented programming methods or operations.
+    $index_element
+      = Texinfo::Translations::gdt('{name} on {class}',
+                   $element_lang_translations, $substrings,
+                   $debug_level);
+  } elsif (exists($Texinfo::Commands::def_class_variable_commands{
+                                                            $def_command})) {
+  # TRANSLATORS: association of a variable or instance variable with
+  # a class in descriptions of object-oriented programming variables or
+  # instance variable.
+    $index_element = Texinfo::Translations::gdt('{name} of {class}',
+                   $element_lang_translations, $substrings,
+                   $debug_level);
+  }
+
+  # prefer a type-less container rather than 'root_line' returned by gdt
+  delete $index_element->{'type'};
+
+  return $index_element;
+}
+
+sub converter_index_content_element($$;$) {
+  my ($element, $converter, $prefer_reference_element) = @_;
+
+  my ($index_element, $name_copy, $class_copy)
+   = get_index_content_info_element($element, $prefer_reference_element);
+
+  if (defined($index_element) or !defined($class_copy)) {
+    return $index_element;
+  }
+
+  my $substrings = {'name' => $name_copy, 'class' => $class_copy};
+  my $def_command = $element->{'extra'}->{'def_command'};
+
+  if (exists($Texinfo::Commands::def_class_method_commands{
+                                                   $def_command})) {
+  # TRANSLATORS: association of a method or operation name with a class
+  # in descriptions of object-oriented programming methods or operations.
+    $index_element = $converter->element_cdt('{name} on {class}',
+                                    $element, $substrings);
+  } elsif (exists($Texinfo::Commands::def_class_variable_commands{
+                                                           $def_command})) {
+  # TRANSLATORS: association of a variable or instance variable with
+  # a class in descriptions of object-oriented programming variables or
+  # instance variable.
+    $index_element = $converter->element_cdt('{name} of {class}',
+                                  $element, $substrings);
+  }
+
+  # prefer a type-less container rather than 'root_line' returned by gdt
+  delete $index_element->{'type'};
+
+  return $index_element;
 }
 
 # 'Non-Ignorable' for 'variable' collation characters means that they are
@@ -558,14 +690,9 @@
   return $index_sortable_index_entries;
 }
 
-sub _setup_sort_sortable_strings_collator($$$$) {
-  my ($document, $converter, $use_unicode_collation, $lang_sorting_locale) = @_;
-
-  # call a simple wrapper around setup_index_entries_sort_strings that
-  # caches the result.  With XS, it is also an interface to native Document
-  # data through sort strings.
-  my $indices_sort_strings
-    = Texinfo::Document::indices_sort_strings($document, $converter);
+sub _setup_sort_sortable_strings_collator($$$) {
+  my ($indices_sort_strings, $use_unicode_collation,
+      $lang_sorting_locale) = @_;
 
   my $collator = _setup_collator($use_unicode_collation, $lang_sorting_locale);
 
@@ -576,13 +703,13 @@
 }
 
 # Normally called through Texinfo::Document::sorted_indices_by_index only
-sub sort_indices_by_index($$;$$) {
-  my ($document, $converter, $use_unicode_collation, $lang_sorting_locale) = @_;
+sub sort_indices_by_index($;$$) {
+  my ($indices_sort_strings, $use_unicode_collation, $lang_sorting_locale) = @_;
 
   my ($index_sortable_index_entries, $collator)
-     = _setup_sort_sortable_strings_collator($document,
-                       $converter, $use_unicode_collation,
-                       $lang_sorting_locale);
+     = _setup_sort_sortable_strings_collator($indices_sort_strings,
+                                             $use_unicode_collation,
+                                             $lang_sorting_locale);
 
   if (!defined($index_sortable_index_entries)) {
     return undef;
@@ -681,8 +808,9 @@
       and defined($index_entry_element->{'extra'}->{'sortas'})) {
     return ($index_entry_element->{'extra'}->{'sortas'}, undef);
   } else {
-    my $entry_tree_element = index_content_element($index_entry_element, 0,
-                                                   $converter, $debug_level);
+    my $entry_tree_element
+         = converter_index_content_element($index_entry_element, 0,
+                                           $converter);
     my $ignore_chars;
     if (exists($index_entry_element->{'extra'})
         and defined($index_entry_element->{'extra'}
@@ -705,13 +833,13 @@
 }
 
 # Normally called through Texinfo::Document::sorted_indices_by_letter only
-sub sort_indices_by_letter($$;$$) {
-  my ($document, $converter, $use_unicode_collation, $lang_sorting_locale) = @_;
+sub sort_indices_by_letter($;$$) {
+  my ($indices_sort_strings, $use_unicode_collation, $lang_sorting_locale) = @_;
 
   my ($index_sortable_index_entries, $collator)
-     = _setup_sort_sortable_strings_collator($document,
-                       $converter, $use_unicode_collation,
-                       $lang_sorting_locale);
+     = _setup_sort_sortable_strings_collator($indices_sort_strings,
+                                             $use_unicode_collation,
+                                             $lang_sorting_locale);
 
   if (!defined($index_sortable_index_entries)) {
     return undef;
@@ -828,16 +956,16 @@
   my $merged_index_entries
      = Texinfo::Indices::merge_indices($indices_information);
 
-  # $converter is a converter object
+  my $indices_sort_strings
+    = Texinfo::Document::indices_sort_strings($document, undef);
+
   my $index_entries_sorted;
   if ($sort_by_letter) {
     $index_entries_sorted
-      = Texinfo::Indices::sort_indices_by_letter($document,
-                                                 $converter);
+      = Texinfo::Indices::sort_indices_by_letter($indices_sort_strings);
   } else {
     $index_entries_sorted
-      = Texinfo::Indices::sort_indices_by_index($document,
-                                                $converter);
+      = Texinfo::Indices::sort_indices_by_index($indices_sort_strings);
   }
 
 
@@ -983,6 +1111,8 @@
 
 =item $entry_content_element = index_content_element($element, $prefer_reference_element, $converter, $debug_level)
 
+FIXME incorrect, does not exist anymore, converter and document variants.
+
 Return a Texinfo tree element corresponding to the content of the index
 entry associated to I<$element>.  If I<$prefer_reference_element> is set,
 prefer an untranslated element.  If the element is an index command like
diff --git a/tta/perl/Texinfo/IndicesNonXS.pm b/tta/perl/Texinfo/IndicesNonXS.pm
index 71a8816..dd723a5 100644
--- a/tta/perl/Texinfo/IndicesNonXS.pm
+++ b/tta/perl/Texinfo/IndicesNonXS.pm
@@ -86,9 +86,16 @@
       and exists($index_entry_element->{'extra'}->{'sortas'})) {
     $sort_string = $index_entry_element->{'extra'}->{'sortas'};
   } else {
-    my $entry_tree_element
-      = index_content_element($index_entry_element, $prefer_reference_element,
-                              $converter, $debug_level);
+    my $entry_tree_element;
+    if (defined($converter)) {
+      $entry_tree_element
+        = converter_index_content_element($index_entry_element, $converter,
+                                $prefer_reference_element);
+    } else {
+      $entry_tree_element
+        = document_index_content_element($index_entry_element,
+                                   $prefer_reference_element, $debug_level);
+    }
     $sort_string = Texinfo::Convert::Text::convert_to_text(
                               $entry_tree_element, $options);
     # Not done for @sortas, in particular to be able to still sort using
diff --git a/tta/perl/XSTexinfo/parser_document/DocumentXS.xs b/tta/perl/XSTexinfo/parser_document/DocumentXS.xs
index 731538c..327e00d 100644
--- a/tta/perl/XSTexinfo/parser_document/DocumentXS.xs
+++ b/tta/perl/XSTexinfo/parser_document/DocumentXS.xs
@@ -391,29 +391,18 @@
                                              "setup_indices_sort_strings");
         if (document)
           {
-            CONVERTER *self = 0;
+            /* CONVERTER *self = 0;
             if (converter_in && SvOK (converter_in))
               self = get_sv_converter (converter_in, 0);
-            CONVERTER *converter_for_translations = 0;
-            ELEMENT * (*element_cdt_tree_fn) (const char *string, const ELEMENT *element,
-                            CONVERTER *self,
-                            NAMED_STRING_ELEMENT_LIST *replaced_substrings,
-                            const char *translation_context) = 0;
+             */
 
-            if (self && self->format == COF_html)
-              {
-                converter_for_translations = self;
-                element_cdt_tree_fn = &html_element_cdt_tree;
-              }
             document_indices_sort_strings (document,
                                            &document->error_messages,
-                                           document->options,
-                                           converter_for_translations,
-                                           element_cdt_tree_fn);
+                                           document->options);
           }
 
 SV *
-indices_sort_strings (SV *document_in, SV *converter_in)
+document_indices_sort_strings (SV *document_in)
     PREINIT:
         DOCUMENT *document = 0;
         const INDICES_SORT_STRINGS *indices_sort_strings = 0;
@@ -424,26 +413,15 @@
                                              "indices_sort_strings");
         if (document)
           {
+            /*
             CONVERTER *self = 0;
             if (converter_in && SvOK (converter_in))
-              self = get_sv_converter (converter_in, 0);
-            CONVERTER *converter_for_translations = 0;
-            ELEMENT * (*element_cdt_tree_fn) (const char *string, const ELEMENT *element,
-                            CONVERTER *self,
-                            NAMED_STRING_ELEMENT_LIST *replaced_substrings,
-                            const char *translation_context) = 0;
+              self = get_sv_converter (converter_in, 0); */
 
-            if (self && self->format == COF_html)
-              {
-                converter_for_translations = self;
-                element_cdt_tree_fn = &html_element_cdt_tree;
-              }
             indices_sort_strings
              = document_indices_sort_strings (document,
                                               &document->error_messages,
-                                              document->options,
-                                              converter_for_translations,
-                                              element_cdt_tree_fn);
+                                              document->options);
           }
 
         if (indices_sort_strings)
@@ -524,20 +502,9 @@
             if (converter_in && SvOK (converter_in))
               self = get_sv_converter (converter_in, 0);
             char *indices_sort_strings_str;
-            CONVERTER *converter_for_translations = 0;
-            ELEMENT * (*element_cdt_tree_fn) (const char *string, const ELEMENT *element,
-                            CONVERTER *self,
-                            NAMED_STRING_ELEMENT_LIST *replaced_substrings,
-                            const char *translation_context) = 0;
 
-            if (self && self->format == COF_html)
-              {
-                converter_for_translations = self;
-                element_cdt_tree_fn = &html_element_cdt_tree;
-              }
             indices_sort_strings_str
-              = print_document_indices_sort_strings (document,
-                          converter_for_translations, element_cdt_tree_fn);
+              = print_document_indices_sort_strings (document, self);
             if (indices_sort_strings_str)
               {
                 RETVAL = newSVpv_utf8 (indices_sort_strings_str, 0);
diff --git a/tta/perl/XSTexinfo/parser_document/IndicesXS.xs b/tta/perl/XSTexinfo/parser_document/IndicesXS.xs
index 4db1df3..e73a49b 100644
--- a/tta/perl/XSTexinfo/parser_document/IndicesXS.xs
+++ b/tta/perl/XSTexinfo/parser_document/IndicesXS.xs
@@ -149,7 +149,7 @@
 
             sort_string = index_entry_element_sort_string (main_entry,
                           element, convert_index_text_options, in_code,
-                          prefer_reference_element, debug_level, 0, 0);
+                          prefer_reference_element, debug_level, 0);
             if (allocated_text_options)
               destroy_text_options (convert_index_text_options);
           }
diff --git a/tta/perl/init/chm.pm b/tta/perl/init/chm.pm
index 2ce1290..eeb4579 100644
--- a/tta/perl/init/chm.pm
+++ b/tta/perl/init/chm.pm
@@ -271,8 +271,8 @@
 
         my $origin_href = $self->command_href($main_entry_element, '');
         my $entry_content_element
-          = Texinfo::Indices::index_content_element($main_entry_element,
-                                                    0, $self);
+          = Texinfo::Indices::converter_index_content_element(
+                                  $main_entry_element, $self, 0);
         my $index_name = $index_entry_ref->{'index_name'};
         my $in_code = 0;
         $in_code = 1
diff --git a/tta/perl/t/results/indices/double_seeentry_seealso.pl b/tta/perl/t/results/indices/double_seeentry_seealso.pl
index 9c88080..7db253b 100644
--- a/tta/perl/t/results/indices/double_seeentry_seealso.pl
+++ b/tta/perl/t/results/indices/double_seeentry_seealso.pl
Binary files differ
diff --git a/tta/perl/t/results/indices/empty_string_index_entry.pl b/tta/perl/t/results/indices/empty_string_index_entry.pl
index 3d76d0d..53c1023 100644
--- a/tta/perl/t/results/indices/empty_string_index_entry.pl
+++ b/tta/perl/t/results/indices/empty_string_index_entry.pl
@@ -221,6 +221,20 @@
 End:
 ';
 
+$result_converted_errors{'info'}->{'empty_string_index_entry'} = '* W l4|empty index key in @findex
+ warning: empty index key in @findex
+
+* W l7|empty index key in @item
+ warning: empty index key in @item
+
+* W l10|empty index key in @defun
+ warning: empty index key in @defun
+
+* W l11|empty index key in @defunx
+ warning: empty index key in @defunx
+
+';
+
 
 $result_converted{'plaintext'}->{'empty_string_index_entry'} = '‘’
 
@@ -229,6 +243,20 @@
 
 ';
 
+$result_converted_errors{'plaintext'}->{'empty_string_index_entry'} = '* W l4|empty index key in @findex
+ warning: empty index key in @findex
+
+* W l7|empty index key in @item
+ warning: empty index key in @item
+
+* W l10|empty index key in @defun
+ warning: empty index key in @defun
+
+* W l11|empty index key in @defunx
+ warning: empty index key in @defunx
+
+';
+
 
 $result_converted{'html_text'}->{'empty_string_index_entry'} = '<a class="node-id" id="Top"></a><p class="nav-panel">
 <span class="nav-button">[<a href="#chap" title="Index" rel="index">Index</a>]</span></p>
@@ -251,6 +279,20 @@
 
 ';
 
+$result_converted_errors{'html_text'}->{'empty_string_index_entry'} = '* W l4|empty index key in @findex
+ warning: empty index key in @findex
+
+* W l7|empty index key in @item
+ warning: empty index key in @item
+
+* W l10|empty index key in @defun
+ warning: empty index key in @defun
+
+* W l11|empty index key in @defunx
+ warning: empty index key in @defunx
+
+';
+
 
 $result_converted{'xml'}->{'empty_string_index_entry'} = '<node identifier="Top"><nodename> Top</nodename><nodenext automatic="on"> chap</nodenext></node>
 <node identifier="chap"><nodename> chap</nodename><nodeprev automatic="on"> Top</nodeprev></node>
diff --git a/tta/perl/t/results/indices/ignored_sort_char_empty_entries.pl b/tta/perl/t/results/indices/ignored_sort_char_empty_entries.pl
index 405f52f..26636a1 100644
--- a/tta/perl/t/results/indices/ignored_sort_char_empty_entries.pl
+++ b/tta/perl/t/results/indices/ignored_sort_char_empty_entries.pl
Binary files differ
diff --git a/tta/perl/t/results/indices/sorted_subentries.pl b/tta/perl/t/results/indices/sorted_subentries.pl
index 9b14a8a..dcc96a8 100644
--- a/tta/perl/t/results/indices/sorted_subentries.pl
+++ b/tta/perl/t/results/indices/sorted_subentries.pl
Binary files differ
diff --git a/tta/perl/t/results/init_files_tests/customize_definition_index_translations.pl b/tta/perl/t/results/init_files_tests/customize_definition_index_translations.pl
index 7981564..c325c78 100644
--- a/tta/perl/t/results/init_files_tests/customize_definition_index_translations.pl
+++ b/tta/perl/t/results/init_files_tests/customize_definition_index_translations.pl
@@ -675,14 +675,14 @@
 $result_headings_list{'customize_definition_index_translations'} = '';
 
 $result_indices_sort_strings{'customize_definition_index_translations'} = 'fn:
+ de in op class de
+ de von cv class de
  deAT in op class deAT
+ deAT von cv class deAT
  default of cv class default
  default on op class default
- La méthode fr pour la op class fr
- La variable fr de cv class fr
- Name de der op class de
- Variable de der cv class de
- Variable(AT) deAT der cv class deAT
+ fr de cv class fr
+ fr de op class fr
 ';
 
 1;
diff --git a/tta/perl/t/results/init_files_tests/translation_in_parser_in_translation.pl b/tta/perl/t/results/init_files_tests/translation_in_parser_in_translation.pl
index 020e923..707da54 100644
--- a/tta/perl/t/results/init_files_tests/translation_in_parser_in_translation.pl
+++ b/tta/perl/t/results/init_files_tests/translation_in_parser_in_translation.pl
@@ -169,17 +169,7 @@
 $result_headings_list{'translation_in_parser_in_translation'} = '';
 
 $result_indices_sort_strings{'translation_in_parser_in_translation'} = 'fn:
- m on n: o p q r
-CC
-
-
-Méthode de s: t u v w x
-DD
-
- entry
-
-
-
+ dd de db
 ';
 
 1;
diff --git a/tta/perl/t/test_utils.pl b/tta/perl/t/test_utils.pl
index 26c2636..b95ec2f 100644
--- a/tta/perl/t/test_utils.pl
+++ b/tta/perl/t/test_utils.pl
@@ -1091,6 +1091,10 @@
   # function for translations, as it impacts the sort strings for
   # object oriented definition commands.  Therefore, if init files
   # were read, we sort index strings using HTML converter functions.
+  # FIXME now the converter is not really used in
+  # print_document_indices_sort_strings call, so there is no point
+  # using a converter.  It could be interesting to show the result
+  # of indices sort strings for each of the converter.
   if ($loaded_init_files and !$doing_epub) {
     my $format_converter_options = {%$converter_options,
                                     %$init_files_options};
diff --git a/tta/perl/t/z_misc/test_sort.t b/tta/perl/t/z_misc/test_sort.t
index 595f092..d9877fc 100644
--- a/tta/perl/t/z_misc/test_sort.t
+++ b/tta/perl/t/z_misc/test_sort.t
@@ -51,7 +51,7 @@
 Texinfo::Config::GNUT_initialize_customization(undef, {}, {});
 
 # To set $indices_sort_strings, calling
-# Texinfo::Document::indices_sort_strings is more natural, but we want
+# Texinfo::Document::document_indices_sort_strings is more natural, but we want
 # to test direct call of Texinfo::Indices::setup_index_entries_sort_strings.
 my $indices_information = $document->indices_information();
 my $index_entries = $document->merged_indices();
@@ -65,8 +65,11 @@
 my $index_entries_sort_strings
   = Texinfo::Indices::format_index_entries_sort_strings($indices_sort_strings);
 
+#my $indices_sort_strings
+# = Texinfo::Document::document_indices_sort_strings($document);
+
 my $sorted_index_entries
-  = Texinfo::Indices::sort_indices_by_index($document, undef);
+  = Texinfo::Indices::sort_indices_by_index($indices_sort_strings);
 
 my @entries = ();
 foreach my $entry (@{$sorted_index_entries->{'cp'}}) {
@@ -81,7 +84,7 @@
 cmp_deeply (\@entries, \@entries_ref, 'sorted index entries');
 
 my $sorted_index_entries_by_letter
- = Texinfo::Indices::sort_indices_by_letter($document, undef);
+ = Texinfo::Indices::sort_indices_by_letter($indices_sort_strings);
 
 my @letter_entries_ref = (
    {'!' => [ '!' ]},
@@ -136,12 +139,12 @@
 
 $document->register_document_options($document_options);
 $indices_sort_strings
-  = Texinfo::Document::indices_sort_strings($document, undef);
+  = Texinfo::Document::document_indices_sort_strings($document);
 $index_entries_sort_strings
   = Texinfo::Indices::format_index_entries_sort_strings($indices_sort_strings);
 
 $sorted_index_entries
-  = Texinfo::Indices::sort_indices_by_index($document, undef);
+  = Texinfo::Indices::sort_indices_by_index($indices_sort_strings);
 
 @entries = ();
 foreach my $entry (@{$sorted_index_entries->{'cp'}}) {
diff --git a/tta/perl/texi2any.pl b/tta/perl/texi2any.pl
index 3d7a86c..448fe65 100755
--- a/tta/perl/texi2any.pl
+++ b/tta/perl/texi2any.pl
@@ -2092,9 +2092,9 @@
   }
 
   # do it now to get error messages here
-  if (exists($formats_table{$converted_format}->{'setup_index_entries_sort_strings'})) {
-    Texinfo::Document::setup_indices_sort_strings($document, $converter);
-  }
+  #if (exists($formats_table{$converted_format}->{'setup_index_entries_sort_strings'})) {
+  #  Texinfo::Document::setup_indices_sort_strings($document, $converter);
+  #}
 
   #Texinfo::Document::rebuild_document($document);
 
diff --git a/tta/swig/perl/t/20index_sort.t b/tta/swig/perl/t/20index_sort.t
index e724827..6b9c8d3 100644
--- a/tta/swig/perl/t/20index_sort.t
+++ b/tta/swig/perl/t/20index_sort.t
@@ -125,14 +125,14 @@
     $label = 'no language';
   }
   my $sorted_indices
-     = Texinfo::Document::sorted_indices_by_index($doc, undef, 1, $lang);
+     = Texinfo::Document::sorted_indices_by_index($doc, 1, $lang);
   my $sorted_entries = $sorted_indices->{$index_name};
   my @reference_index_entries_texi;
   foreach my $index_entry (@$sorted_entries) {
     #print STDERR join('|', sort(keys(%{$index_entry})))."\n";
     my $main_entry_element = $index_entry->{'entry_element'};
     my $entry_content_element
-       = Texinfo::Indices::index_content_element($main_entry_element);
+       = Texinfo::Indices::document_index_content_element($main_entry_element);
     push @reference_index_entries_texi,
       Texinfo::Convert::Texinfo::convert_to_texinfo($entry_content_element);
   }
diff --git a/tta/swig/texinfo.i b/tta/swig/texinfo.i
index 5492218..cd6dccf 100644
--- a/tta/swig/texinfo.i
+++ b/tta/swig/texinfo.i
@@ -771,6 +771,7 @@
 
 // manipulate_indices.h
 // used in a test
+// FIXME remove to avoid needing translations in the interface?
 %rename(index_content_element) txi_ext_inline_index_content_element;
 ELEMENT *txi_ext_inline_index_content_element (const ELEMENT *element,
                                 DOCUMENT *document,
@@ -791,14 +792,12 @@
                                 int prefer_reference_element,
                                 int debug_level)
 {
-  return index_content_element (element, prefer_reference_element,
-                                document, debug_level, 0, 0);
+  return document_index_content_element (element, prefer_reference_element,
+                                         document, debug_level);
 }
 %}
 
 
-
-
 // TODO add a wrapper around new_complete_menu_master_menu?
 
 // utils.h
diff --git a/tta/tests/coverage/res_parser/formatting_epub/formatting.2 b/tta/tests/coverage/res_parser/formatting_epub/formatting.2
index d5da207..d1f6752 100644
--- a/tta/tests/coverage/res_parser/formatting_epub/formatting.2
+++ b/tta/tests/coverage/res_parser/formatting_epub/formatting.2
@@ -331,7 +331,6 @@
 formatting.texi:93: @ref reference to nonexistent node `node' (possibly involving @mymacro)
 formatting.texi:93: @ref reference to nonexistent node `node' (possibly involving @mymacro)
 formatting.texi:93: @ref reference to nonexistent node `node' (possibly involving @mymacro)
-formatting.texi:134: warning: empty index key in @findex
 formatting.texi:34: warning: no HTML cross-references entry found for `file n---ame@' (possibly involving @mymacro)
 formatting.texi:34: warning: no HTML cross-references entry found for `file name' (possibly involving @mymacro)
 formatting.texi:34: warning: no HTML cross-references entry found for `a comma, in file' (possibly involving @mymacro)
@@ -396,3 +395,4 @@
 texi2any: @image file `f--ile@.' can not be copied
 formatting.texi:93: warning: @image file `filejk _" %@' (for HTML) not found, using `filejk _" %@.jpg' (possibly involving @mymacro)
 texi2any: @image file `filejk _" %@' can not be copied
+formatting.texi:134: warning: empty index key in @findex
diff --git a/tta/tests/coverage/res_parser/formatting_html32/formatting.2 b/tta/tests/coverage/res_parser/formatting_html32/formatting.2
index d09e0b9..3a06c11 100644
--- a/tta/tests/coverage/res_parser/formatting_html32/formatting.2
+++ b/tta/tests/coverage/res_parser/formatting_html32/formatting.2
@@ -332,7 +332,6 @@
 formatting.texi:93: @ref reference to nonexistent node `node' (possibly involving @mymacro)
 formatting.texi:93: @ref reference to nonexistent node `node' (possibly involving @mymacro)
 formatting.texi:232: warning: node `node with xrefname' not in menu
-formatting.texi:134: warning: empty index key in @findex
 formatting.texi:34: warning: no HTML cross-references entry found for `file n---ame@' (possibly involving @mymacro)
 formatting.texi:34: warning: no HTML cross-references entry found for `file name' (possibly involving @mymacro)
 formatting.texi:34: warning: no HTML cross-references entry found for `a comma, in file' (possibly involving @mymacro)
@@ -377,3 +376,4 @@
 formatting.texi:93: warning: @image file `f-ile' (for HTML) not found, using `f-ile.jpg' (possibly involving @mymacro)
 formatting.texi:93: warning: @image file `f--ile@.' (for HTML) not found, using `f--ile@..file ext e--xt}' (possibly involving @mymacro)
 formatting.texi:93: warning: @image file `filejk _" %@' (for HTML) not found, using `filejk _" %@.jpg' (possibly involving @mymacro)
+formatting.texi:134: warning: empty index key in @findex
diff --git a/tta/tests/coverage/res_parser/formatting_html_no_split/formatting.2 b/tta/tests/coverage/res_parser/formatting_html_no_split/formatting.2
index cdc2ec9..111e159 100644
--- a/tta/tests/coverage/res_parser/formatting_html_no_split/formatting.2
+++ b/tta/tests/coverage/res_parser/formatting_html_no_split/formatting.2
@@ -331,7 +331,6 @@
 formatting.texi:93: @ref reference to nonexistent node `node' (possibly involving @mymacro)
 formatting.texi:93: @ref reference to nonexistent node `node' (possibly involving @mymacro)
 formatting.texi:93: @ref reference to nonexistent node `node' (possibly involving @mymacro)
-formatting.texi:134: warning: empty index key in @findex
 formatting.texi:24: warning: no HTML cross-references entry found for `file n---ame@' (possibly involving @mymacro)
 formatting.texi:24: warning: no HTML cross-references entry found for `file name' (possibly involving @mymacro)
 formatting.texi:24: warning: no HTML cross-references entry found for `a comma, in file' (possibly involving @mymacro)
@@ -362,3 +361,4 @@
 formatting.texi:93: warning: @image file `f-ile' (for HTML) not found, using `f-ile.jpg' (possibly involving @mymacro)
 formatting.texi:93: warning: @image file `f--ile@.' (for HTML) not found, using `f--ile@..file ext e--xt}' (possibly involving @mymacro)
 formatting.texi:93: warning: @image file `filejk _" %@' (for HTML) not found, using `filejk _" %@.jpg' (possibly involving @mymacro)
+formatting.texi:134: warning: empty index key in @findex
diff --git a/tta/tests/coverage/res_parser/formatting_info/formatting.2 b/tta/tests/coverage/res_parser/formatting_info/formatting.2
index 9df3a94..76ccdd4 100644
--- a/tta/tests/coverage/res_parser/formatting_info/formatting.2
+++ b/tta/tests/coverage/res_parser/formatting_info/formatting.2
@@ -332,7 +332,6 @@
 formatting.texi:93: @ref reference to nonexistent node `node' (possibly involving @mymacro)
 formatting.texi:93: @ref reference to nonexistent node `node' (possibly involving @mymacro)
 formatting.texi:232: warning: node `node with xrefname' not in menu
-formatting.texi:134: warning: empty index key in @findex
 formatting.texi:24: warning: @ref node name should not contain `,' (possibly involving @mymacro)
 formatting.texi:24: warning: @inforef node name should not contain `,' (possibly involving @mymacro)
 formatting.texi:24: warning: @ref cross-reference name should not contain `:' (possibly involving @mymacro)
@@ -349,4 +348,5 @@
 formatting.texi:93: warning: @inforef node name should not contain `,' (possibly involving @mymacro)
 formatting.texi:93: warning: @ref cross-reference name should not contain `:' (possibly involving @mymacro)
 formatting.texi:93: warning: @ref cross-reference name should not contain `:' (possibly involving @mymacro)
+formatting.texi:134: warning: empty index key in @findex
 formatting.texi:205: warning: @node name should not contain `,': s--ect,ion
diff --git a/tta/tests/coverage/res_parser/formatting_xhtml/formatting.2 b/tta/tests/coverage/res_parser/formatting_xhtml/formatting.2
index a597689..1a7f5f1 100644
--- a/tta/tests/coverage/res_parser/formatting_xhtml/formatting.2
+++ b/tta/tests/coverage/res_parser/formatting_xhtml/formatting.2
@@ -331,7 +331,6 @@
 formatting.texi:93: @ref reference to nonexistent node `node' (possibly involving @mymacro)
 formatting.texi:93: @ref reference to nonexistent node `node' (possibly involving @mymacro)
 formatting.texi:93: @ref reference to nonexistent node `node' (possibly involving @mymacro)
-formatting.texi:134: warning: empty index key in @findex
 formatting.texi:34: warning: no HTML cross-references entry found for `file n---ame@' (possibly involving @mymacro)
 formatting.texi:34: warning: no HTML cross-references entry found for `file name' (possibly involving @mymacro)
 formatting.texi:34: warning: no HTML cross-references entry found for `a comma, in file' (possibly involving @mymacro)
@@ -376,3 +375,4 @@
 formatting.texi:93: warning: @image file `f-ile' (for HTML) not found, using `f-ile.jpg' (possibly involving @mymacro)
 formatting.texi:93: warning: @image file `f--ile@.' (for HTML) not found, using `f--ile@..file ext e--xt}' (possibly involving @mymacro)
 formatting.texi:93: warning: @image file `filejk _" %@' (for HTML) not found, using `filejk _" %@.jpg' (possibly involving @mymacro)
+formatting.texi:134: warning: empty index key in @findex
diff --git a/tta/tests/layout/res_parser/formatting_enable_encoding/formatting.2 b/tta/tests/layout/res_parser/formatting_enable_encoding/formatting.2
index d09e0b9..3a06c11 100644
--- a/tta/tests/layout/res_parser/formatting_enable_encoding/formatting.2
+++ b/tta/tests/layout/res_parser/formatting_enable_encoding/formatting.2
@@ -332,7 +332,6 @@
 formatting.texi:93: @ref reference to nonexistent node `node' (possibly involving @mymacro)
 formatting.texi:93: @ref reference to nonexistent node `node' (possibly involving @mymacro)
 formatting.texi:232: warning: node `node with xrefname' not in menu
-formatting.texi:134: warning: empty index key in @findex
 formatting.texi:34: warning: no HTML cross-references entry found for `file n---ame@' (possibly involving @mymacro)
 formatting.texi:34: warning: no HTML cross-references entry found for `file name' (possibly involving @mymacro)
 formatting.texi:34: warning: no HTML cross-references entry found for `a comma, in file' (possibly involving @mymacro)
@@ -377,3 +376,4 @@
 formatting.texi:93: warning: @image file `f-ile' (for HTML) not found, using `f-ile.jpg' (possibly involving @mymacro)
 formatting.texi:93: warning: @image file `f--ile@.' (for HTML) not found, using `f--ile@..file ext e--xt}' (possibly involving @mymacro)
 formatting.texi:93: warning: @image file `filejk _" %@' (for HTML) not found, using `filejk _" %@.jpg' (possibly involving @mymacro)
+formatting.texi:134: warning: empty index key in @findex
diff --git a/tta/tests/layout/res_parser/formatting_epub_nodes/formatting.2 b/tta/tests/layout/res_parser/formatting_epub_nodes/formatting.2
index d5da207..d1f6752 100644
--- a/tta/tests/layout/res_parser/formatting_epub_nodes/formatting.2
+++ b/tta/tests/layout/res_parser/formatting_epub_nodes/formatting.2
@@ -331,7 +331,6 @@
 formatting.texi:93: @ref reference to nonexistent node `node' (possibly involving @mymacro)
 formatting.texi:93: @ref reference to nonexistent node `node' (possibly involving @mymacro)
 formatting.texi:93: @ref reference to nonexistent node `node' (possibly involving @mymacro)
-formatting.texi:134: warning: empty index key in @findex
 formatting.texi:34: warning: no HTML cross-references entry found for `file n---ame@' (possibly involving @mymacro)
 formatting.texi:34: warning: no HTML cross-references entry found for `file name' (possibly involving @mymacro)
 formatting.texi:34: warning: no HTML cross-references entry found for `a comma, in file' (possibly involving @mymacro)
@@ -396,3 +395,4 @@
 texi2any: @image file `f--ile@.' can not be copied
 formatting.texi:93: warning: @image file `filejk _" %@' (for HTML) not found, using `filejk _" %@.jpg' (possibly involving @mymacro)
 texi2any: @image file `filejk _" %@' can not be copied
+formatting.texi:134: warning: empty index key in @findex
diff --git a/tta/tests/layout/res_parser/formatting_exotic/formatting.2 b/tta/tests/layout/res_parser/formatting_exotic/formatting.2
index cdc2ec9..111e159 100644
--- a/tta/tests/layout/res_parser/formatting_exotic/formatting.2
+++ b/tta/tests/layout/res_parser/formatting_exotic/formatting.2
@@ -331,7 +331,6 @@
 formatting.texi:93: @ref reference to nonexistent node `node' (possibly involving @mymacro)
 formatting.texi:93: @ref reference to nonexistent node `node' (possibly involving @mymacro)
 formatting.texi:93: @ref reference to nonexistent node `node' (possibly involving @mymacro)
-formatting.texi:134: warning: empty index key in @findex
 formatting.texi:24: warning: no HTML cross-references entry found for `file n---ame@' (possibly involving @mymacro)
 formatting.texi:24: warning: no HTML cross-references entry found for `file name' (possibly involving @mymacro)
 formatting.texi:24: warning: no HTML cross-references entry found for `a comma, in file' (possibly involving @mymacro)
@@ -362,3 +361,4 @@
 formatting.texi:93: warning: @image file `f-ile' (for HTML) not found, using `f-ile.jpg' (possibly involving @mymacro)
 formatting.texi:93: warning: @image file `f--ile@.' (for HTML) not found, using `f--ile@..file ext e--xt}' (possibly involving @mymacro)
 formatting.texi:93: warning: @image file `filejk _" %@' (for HTML) not found, using `filejk _" %@.jpg' (possibly involving @mymacro)
+formatting.texi:134: warning: empty index key in @findex
diff --git a/tta/tests/layout/res_parser/formatting_fr/formatting.2 b/tta/tests/layout/res_parser/formatting_fr/formatting.2
index d09e0b9..3a06c11 100644
--- a/tta/tests/layout/res_parser/formatting_fr/formatting.2
+++ b/tta/tests/layout/res_parser/formatting_fr/formatting.2
@@ -332,7 +332,6 @@
 formatting.texi:93: @ref reference to nonexistent node `node' (possibly involving @mymacro)
 formatting.texi:93: @ref reference to nonexistent node `node' (possibly involving @mymacro)
 formatting.texi:232: warning: node `node with xrefname' not in menu
-formatting.texi:134: warning: empty index key in @findex
 formatting.texi:34: warning: no HTML cross-references entry found for `file n---ame@' (possibly involving @mymacro)
 formatting.texi:34: warning: no HTML cross-references entry found for `file name' (possibly involving @mymacro)
 formatting.texi:34: warning: no HTML cross-references entry found for `a comma, in file' (possibly involving @mymacro)
@@ -377,3 +376,4 @@
 formatting.texi:93: warning: @image file `f-ile' (for HTML) not found, using `f-ile.jpg' (possibly involving @mymacro)
 formatting.texi:93: warning: @image file `f--ile@.' (for HTML) not found, using `f--ile@..file ext e--xt}' (possibly involving @mymacro)
 formatting.texi:93: warning: @image file `filejk _" %@' (for HTML) not found, using `filejk _" %@.jpg' (possibly involving @mymacro)
+formatting.texi:134: warning: empty index key in @findex
diff --git a/tta/tests/layout/res_parser/formatting_fr_icons/formatting.2 b/tta/tests/layout/res_parser/formatting_fr_icons/formatting.2
index d09e0b9..3a06c11 100644
--- a/tta/tests/layout/res_parser/formatting_fr_icons/formatting.2
+++ b/tta/tests/layout/res_parser/formatting_fr_icons/formatting.2
@@ -332,7 +332,6 @@
 formatting.texi:93: @ref reference to nonexistent node `node' (possibly involving @mymacro)
 formatting.texi:93: @ref reference to nonexistent node `node' (possibly involving @mymacro)
 formatting.texi:232: warning: node `node with xrefname' not in menu
-formatting.texi:134: warning: empty index key in @findex
 formatting.texi:34: warning: no HTML cross-references entry found for `file n---ame@' (possibly involving @mymacro)
 formatting.texi:34: warning: no HTML cross-references entry found for `file name' (possibly involving @mymacro)
 formatting.texi:34: warning: no HTML cross-references entry found for `a comma, in file' (possibly involving @mymacro)
@@ -377,3 +376,4 @@
 formatting.texi:93: warning: @image file `f-ile' (for HTML) not found, using `f-ile.jpg' (possibly involving @mymacro)
 formatting.texi:93: warning: @image file `f--ile@.' (for HTML) not found, using `f--ile@..file ext e--xt}' (possibly involving @mymacro)
 formatting.texi:93: warning: @image file `filejk _" %@' (for HTML) not found, using `filejk _" %@.jpg' (possibly involving @mymacro)
+formatting.texi:134: warning: empty index key in @findex
diff --git a/tta/tests/layout/res_parser/formatting_fr_info/formatting.2 b/tta/tests/layout/res_parser/formatting_fr_info/formatting.2
index 9df3a94..76ccdd4 100644
--- a/tta/tests/layout/res_parser/formatting_fr_info/formatting.2
+++ b/tta/tests/layout/res_parser/formatting_fr_info/formatting.2
@@ -332,7 +332,6 @@
 formatting.texi:93: @ref reference to nonexistent node `node' (possibly involving @mymacro)
 formatting.texi:93: @ref reference to nonexistent node `node' (possibly involving @mymacro)
 formatting.texi:232: warning: node `node with xrefname' not in menu
-formatting.texi:134: warning: empty index key in @findex
 formatting.texi:24: warning: @ref node name should not contain `,' (possibly involving @mymacro)
 formatting.texi:24: warning: @inforef node name should not contain `,' (possibly involving @mymacro)
 formatting.texi:24: warning: @ref cross-reference name should not contain `:' (possibly involving @mymacro)
@@ -349,4 +348,5 @@
 formatting.texi:93: warning: @inforef node name should not contain `,' (possibly involving @mymacro)
 formatting.texi:93: warning: @ref cross-reference name should not contain `:' (possibly involving @mymacro)
 formatting.texi:93: warning: @ref cross-reference name should not contain `:' (possibly involving @mymacro)
+formatting.texi:134: warning: empty index key in @findex
 formatting.texi:205: warning: @node name should not contain `,': s--ect,ion
diff --git a/tta/tests/layout/res_parser/formatting_info_ascii_punctuation/formatting.2 b/tta/tests/layout/res_parser/formatting_info_ascii_punctuation/formatting.2
index 9df3a94..76ccdd4 100644
--- a/tta/tests/layout/res_parser/formatting_info_ascii_punctuation/formatting.2
+++ b/tta/tests/layout/res_parser/formatting_info_ascii_punctuation/formatting.2
@@ -332,7 +332,6 @@
 formatting.texi:93: @ref reference to nonexistent node `node' (possibly involving @mymacro)
 formatting.texi:93: @ref reference to nonexistent node `node' (possibly involving @mymacro)
 formatting.texi:232: warning: node `node with xrefname' not in menu
-formatting.texi:134: warning: empty index key in @findex
 formatting.texi:24: warning: @ref node name should not contain `,' (possibly involving @mymacro)
 formatting.texi:24: warning: @inforef node name should not contain `,' (possibly involving @mymacro)
 formatting.texi:24: warning: @ref cross-reference name should not contain `:' (possibly involving @mymacro)
@@ -349,4 +348,5 @@
 formatting.texi:93: warning: @inforef node name should not contain `,' (possibly involving @mymacro)
 formatting.texi:93: warning: @ref cross-reference name should not contain `:' (possibly involving @mymacro)
 formatting.texi:93: warning: @ref cross-reference name should not contain `:' (possibly involving @mymacro)
+formatting.texi:134: warning: empty index key in @findex
 formatting.texi:205: warning: @node name should not contain `,': s--ect,ion
diff --git a/tta/tests/layout/res_parser/formatting_info_disable_encoding/formatting.2 b/tta/tests/layout/res_parser/formatting_info_disable_encoding/formatting.2
index 9df3a94..76ccdd4 100644
--- a/tta/tests/layout/res_parser/formatting_info_disable_encoding/formatting.2
+++ b/tta/tests/layout/res_parser/formatting_info_disable_encoding/formatting.2
@@ -332,7 +332,6 @@
 formatting.texi:93: @ref reference to nonexistent node `node' (possibly involving @mymacro)
 formatting.texi:93: @ref reference to nonexistent node `node' (possibly involving @mymacro)
 formatting.texi:232: warning: node `node with xrefname' not in menu
-formatting.texi:134: warning: empty index key in @findex
 formatting.texi:24: warning: @ref node name should not contain `,' (possibly involving @mymacro)
 formatting.texi:24: warning: @inforef node name should not contain `,' (possibly involving @mymacro)
 formatting.texi:24: warning: @ref cross-reference name should not contain `:' (possibly involving @mymacro)
@@ -349,4 +348,5 @@
 formatting.texi:93: warning: @inforef node name should not contain `,' (possibly involving @mymacro)
 formatting.texi:93: warning: @ref cross-reference name should not contain `:' (possibly involving @mymacro)
 formatting.texi:93: warning: @ref cross-reference name should not contain `:' (possibly involving @mymacro)
+formatting.texi:134: warning: empty index key in @findex
 formatting.texi:205: warning: @node name should not contain `,': s--ect,ion
diff --git a/tta/tests/layout/res_parser/formatting_inline_css/formatting.2 b/tta/tests/layout/res_parser/formatting_inline_css/formatting.2
index d09e0b9..3a06c11 100644
--- a/tta/tests/layout/res_parser/formatting_inline_css/formatting.2
+++ b/tta/tests/layout/res_parser/formatting_inline_css/formatting.2
@@ -332,7 +332,6 @@
 formatting.texi:93: @ref reference to nonexistent node `node' (possibly involving @mymacro)
 formatting.texi:93: @ref reference to nonexistent node `node' (possibly involving @mymacro)
 formatting.texi:232: warning: node `node with xrefname' not in menu
-formatting.texi:134: warning: empty index key in @findex
 formatting.texi:34: warning: no HTML cross-references entry found for `file n---ame@' (possibly involving @mymacro)
 formatting.texi:34: warning: no HTML cross-references entry found for `file name' (possibly involving @mymacro)
 formatting.texi:34: warning: no HTML cross-references entry found for `a comma, in file' (possibly involving @mymacro)
@@ -377,3 +376,4 @@
 formatting.texi:93: warning: @image file `f-ile' (for HTML) not found, using `f-ile.jpg' (possibly involving @mymacro)
 formatting.texi:93: warning: @image file `f--ile@.' (for HTML) not found, using `f--ile@..file ext e--xt}' (possibly involving @mymacro)
 formatting.texi:93: warning: @image file `filejk _" %@' (for HTML) not found, using `filejk _" %@.jpg' (possibly involving @mymacro)
+formatting.texi:134: warning: empty index key in @findex
diff --git a/tta/tests/layout/res_parser/formatting_mathjax/formatting.2 b/tta/tests/layout/res_parser/formatting_mathjax/formatting.2
index a597689..1a7f5f1 100644
--- a/tta/tests/layout/res_parser/formatting_mathjax/formatting.2
+++ b/tta/tests/layout/res_parser/formatting_mathjax/formatting.2
@@ -331,7 +331,6 @@
 formatting.texi:93: @ref reference to nonexistent node `node' (possibly involving @mymacro)
 formatting.texi:93: @ref reference to nonexistent node `node' (possibly involving @mymacro)
 formatting.texi:93: @ref reference to nonexistent node `node' (possibly involving @mymacro)
-formatting.texi:134: warning: empty index key in @findex
 formatting.texi:34: warning: no HTML cross-references entry found for `file n---ame@' (possibly involving @mymacro)
 formatting.texi:34: warning: no HTML cross-references entry found for `file name' (possibly involving @mymacro)
 formatting.texi:34: warning: no HTML cross-references entry found for `a comma, in file' (possibly involving @mymacro)
@@ -376,3 +375,4 @@
 formatting.texi:93: warning: @image file `f-ile' (for HTML) not found, using `f-ile.jpg' (possibly involving @mymacro)
 formatting.texi:93: warning: @image file `f--ile@.' (for HTML) not found, using `f--ile@..file ext e--xt}' (possibly involving @mymacro)
 formatting.texi:93: warning: @image file `filejk _" %@' (for HTML) not found, using `filejk _" %@.jpg' (possibly involving @mymacro)
+formatting.texi:134: warning: empty index key in @findex
diff --git a/tta/tests/layout/res_parser/formatting_numerical_entities/formatting.2 b/tta/tests/layout/res_parser/formatting_numerical_entities/formatting.2
index d09e0b9..3a06c11 100644
--- a/tta/tests/layout/res_parser/formatting_numerical_entities/formatting.2
+++ b/tta/tests/layout/res_parser/formatting_numerical_entities/formatting.2
@@ -332,7 +332,6 @@
 formatting.texi:93: @ref reference to nonexistent node `node' (possibly involving @mymacro)
 formatting.texi:93: @ref reference to nonexistent node `node' (possibly involving @mymacro)
 formatting.texi:232: warning: node `node with xrefname' not in menu
-formatting.texi:134: warning: empty index key in @findex
 formatting.texi:34: warning: no HTML cross-references entry found for `file n---ame@' (possibly involving @mymacro)
 formatting.texi:34: warning: no HTML cross-references entry found for `file name' (possibly involving @mymacro)
 formatting.texi:34: warning: no HTML cross-references entry found for `a comma, in file' (possibly involving @mymacro)
@@ -377,3 +376,4 @@
 formatting.texi:93: warning: @image file `f-ile' (for HTML) not found, using `f-ile.jpg' (possibly involving @mymacro)
 formatting.texi:93: warning: @image file `f--ile@.' (for HTML) not found, using `f--ile@..file ext e--xt}' (possibly involving @mymacro)
 formatting.texi:93: warning: @image file `filejk _" %@' (for HTML) not found, using `filejk _" %@.jpg' (possibly involving @mymacro)
+formatting.texi:134: warning: empty index key in @findex
diff --git a/tta/tests/layout/res_parser/formatting_sort_element_counts/formatting.2 b/tta/tests/layout/res_parser/formatting_sort_element_counts/formatting.2
index cdc2ec9..111e159 100644
--- a/tta/tests/layout/res_parser/formatting_sort_element_counts/formatting.2
+++ b/tta/tests/layout/res_parser/formatting_sort_element_counts/formatting.2
@@ -331,7 +331,6 @@
 formatting.texi:93: @ref reference to nonexistent node `node' (possibly involving @mymacro)
 formatting.texi:93: @ref reference to nonexistent node `node' (possibly involving @mymacro)
 formatting.texi:93: @ref reference to nonexistent node `node' (possibly involving @mymacro)
-formatting.texi:134: warning: empty index key in @findex
 formatting.texi:24: warning: no HTML cross-references entry found for `file n---ame@' (possibly involving @mymacro)
 formatting.texi:24: warning: no HTML cross-references entry found for `file name' (possibly involving @mymacro)
 formatting.texi:24: warning: no HTML cross-references entry found for `a comma, in file' (possibly involving @mymacro)
@@ -362,3 +361,4 @@
 formatting.texi:93: warning: @image file `f-ile' (for HTML) not found, using `f-ile.jpg' (possibly involving @mymacro)
 formatting.texi:93: warning: @image file `f--ile@.' (for HTML) not found, using `f--ile@..file ext e--xt}' (possibly involving @mymacro)
 formatting.texi:93: warning: @image file `filejk _" %@' (for HTML) not found, using `filejk _" %@.jpg' (possibly involving @mymacro)
+formatting.texi:134: warning: empty index key in @findex
diff --git a/tta/tests/layout/res_parser/formatting_texi2html/formatting.2 b/tta/tests/layout/res_parser/formatting_texi2html/formatting.2
index d09e0b9..3a06c11 100644
--- a/tta/tests/layout/res_parser/formatting_texi2html/formatting.2
+++ b/tta/tests/layout/res_parser/formatting_texi2html/formatting.2
@@ -332,7 +332,6 @@
 formatting.texi:93: @ref reference to nonexistent node `node' (possibly involving @mymacro)
 formatting.texi:93: @ref reference to nonexistent node `node' (possibly involving @mymacro)
 formatting.texi:232: warning: node `node with xrefname' not in menu
-formatting.texi:134: warning: empty index key in @findex
 formatting.texi:34: warning: no HTML cross-references entry found for `file n---ame@' (possibly involving @mymacro)
 formatting.texi:34: warning: no HTML cross-references entry found for `file name' (possibly involving @mymacro)
 formatting.texi:34: warning: no HTML cross-references entry found for `a comma, in file' (possibly involving @mymacro)
@@ -377,3 +376,4 @@
 formatting.texi:93: warning: @image file `f-ile' (for HTML) not found, using `f-ile.jpg' (possibly involving @mymacro)
 formatting.texi:93: warning: @image file `f--ile@.' (for HTML) not found, using `f--ile@..file ext e--xt}' (possibly involving @mymacro)
 formatting.texi:93: warning: @image file `filejk _" %@' (for HTML) not found, using `filejk _" %@.jpg' (possibly involving @mymacro)
+formatting.texi:134: warning: empty index key in @findex
diff --git a/tta/tests/layout/res_parser/formatting_texi2html_nodes/formatting.2 b/tta/tests/layout/res_parser/formatting_texi2html_nodes/formatting.2
index d09e0b9..3a06c11 100644
--- a/tta/tests/layout/res_parser/formatting_texi2html_nodes/formatting.2
+++ b/tta/tests/layout/res_parser/formatting_texi2html_nodes/formatting.2
@@ -332,7 +332,6 @@
 formatting.texi:93: @ref reference to nonexistent node `node' (possibly involving @mymacro)
 formatting.texi:93: @ref reference to nonexistent node `node' (possibly involving @mymacro)
 formatting.texi:232: warning: node `node with xrefname' not in menu
-formatting.texi:134: warning: empty index key in @findex
 formatting.texi:34: warning: no HTML cross-references entry found for `file n---ame@' (possibly involving @mymacro)
 formatting.texi:34: warning: no HTML cross-references entry found for `file name' (possibly involving @mymacro)
 formatting.texi:34: warning: no HTML cross-references entry found for `a comma, in file' (possibly involving @mymacro)
@@ -377,3 +376,4 @@
 formatting.texi:93: warning: @image file `f-ile' (for HTML) not found, using `f-ile.jpg' (possibly involving @mymacro)
 formatting.texi:93: warning: @image file `f--ile@.' (for HTML) not found, using `f--ile@..file ext e--xt}' (possibly involving @mymacro)
 formatting.texi:93: warning: @image file `filejk _" %@' (for HTML) not found, using `filejk _" %@.jpg' (possibly involving @mymacro)
+formatting.texi:134: warning: empty index key in @findex
diff --git a/tta/tests/layout/res_parser/formatting_weird_quotes/formatting.2 b/tta/tests/layout/res_parser/formatting_weird_quotes/formatting.2
index d09e0b9..3a06c11 100644
--- a/tta/tests/layout/res_parser/formatting_weird_quotes/formatting.2
+++ b/tta/tests/layout/res_parser/formatting_weird_quotes/formatting.2
@@ -332,7 +332,6 @@
 formatting.texi:93: @ref reference to nonexistent node `node' (possibly involving @mymacro)
 formatting.texi:93: @ref reference to nonexistent node `node' (possibly involving @mymacro)
 formatting.texi:232: warning: node `node with xrefname' not in menu
-formatting.texi:134: warning: empty index key in @findex
 formatting.texi:34: warning: no HTML cross-references entry found for `file n---ame@' (possibly involving @mymacro)
 formatting.texi:34: warning: no HTML cross-references entry found for `file name' (possibly involving @mymacro)
 formatting.texi:34: warning: no HTML cross-references entry found for `a comma, in file' (possibly involving @mymacro)
@@ -377,3 +376,4 @@
 formatting.texi:93: warning: @image file `f-ile' (for HTML) not found, using `f-ile.jpg' (possibly involving @mymacro)
 formatting.texi:93: warning: @image file `f--ile@.' (for HTML) not found, using `f--ile@..file ext e--xt}' (possibly involving @mymacro)
 formatting.texi:93: warning: @image file `filejk _" %@' (for HTML) not found, using `filejk _" %@.jpg' (possibly involving @mymacro)
+formatting.texi:134: warning: empty index key in @findex
diff --git a/tta/tests/tex_html/res_parser/formatting_singular/formatting.2 b/tta/tests/tex_html/res_parser/formatting_singular/formatting.2
index 6715652..26bab90 100644
--- a/tta/tests/tex_html/res_parser/formatting_singular/formatting.2
+++ b/tta/tests/tex_html/res_parser/formatting_singular/formatting.2
@@ -332,7 +332,6 @@
 formatting.texi:93: @ref reference to nonexistent node `node' (possibly involving @mymacro)
 formatting.texi:93: @ref reference to nonexistent node `node' (possibly involving @mymacro)
 formatting.texi:232: warning: node `node with xrefname' not in menu
-formatting.texi:134: warning: empty index key in @findex
 texexpand 
 formatting.texi:24: warning: no HTML cross-references entry found for `file n---ame@' (possibly involving @mymacro)
 formatting.texi:24: warning: no HTML cross-references entry found for `file name' (possibly involving @mymacro)
@@ -364,3 +363,4 @@
 formatting.texi:93: warning: @image file `f-ile' (for HTML) not found, using `f-ile.jpg' (possibly involving @mymacro)
 formatting.texi:93: warning: @image file `f--ile@.' (for HTML) not found, using `f--ile@..file ext e--xt}' (possibly involving @mymacro)
 formatting.texi:93: warning: @image file `filejk _" %@' (for HTML) not found, using `filejk _" %@.jpg' (possibly involving @mymacro)
+formatting.texi:134: warning: empty index key in @findex