texinfo-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[no subject]


From: Patrice Dumas
Date: Mon, 12 Feb 2024 18:07:19 -0500 (EST)

branch: master
commit fc1807d84addf5a2ddee2ae8c00306b51efe0b8a
Author: Patrice Dumas <pertusus@free.fr>
AuthorDate: Tue Feb 13 00:05:38 2024 +0100

    * tp/Texinfo/options_data.txt (DOCUMENTLANGUAGE_COLLATION)
    (XS_STRXFRM_COLLATION_LOCALE): add customization variables.
    
    * tp/Texinfo/XS/main/call_perl_function.c (call_setup_collator)
    (call_collator_getSortKey), tp/Texinfo/XS/main/document_types.h
    (BYTES_STRING, enum collation_type_name),
    tp/Texinfo/XS/main/manipulate_indices.c (INDEX_COLLATOR, get_sort_key)
    (setup_collator, compare_byte_strings, compare_index_letter)
    (compare_sortable_subentry_keys),
    tp/Texinfo/XS/main/manipulate_indices.h (SORTABLE_INDEX_SUBENTRY):
    add an enum for the types of collations, and a structure for a
    collator.  Add the possibility to call perl code to get a collator
    object and get Perl sort keys as a possibility for collation sort
    strings.  Use bytes strings with length through the BYTES_STRING
    structure, to be able to use strings with NUL within as collation
    string keys.  This is needed for collation keys coming from Perl and a
    logical structure in C for collation binary strings.  Use memcmp to
    compare.
    
    * tp/Texinfo/XS/main/document.c (document_indices_sort_strings)
    (destroy_document_information_except_tree),
    tp/Texinfo/XS/main/document_types.h (INDEX_SUBENTRY_SORT_STRING)
    (INDEX_ENTRY_SORT_STRING, INDEX_SORT_STRINGS, INDICES_SORT_STRINGS)
    (DOCUMENT), tp/Texinfo/XS/main/manipulate_indices.c
    (destroy_index_entries_sort_strings),
    tp/Texinfo/XS/main/manipulate_indices.c
    (setup_index_entries_sort_strings, setup_sortable_index_entries)
    (setup_sort_sortable_strings_collator, sort_indices_by_letter): add
    setup_index_entries_sort_strings based on setup_sortable_index_entries
    code and add setup_sort_sortable_strings_collator, as in Perl.  Add
    document_indices_sort_strings.
    
    * tp/Texinfo/XS/main/manipulate_indices.c
    (destroy_indices_sortable_entries): add.
    
    * tp/Texinfo/XS/main/document.c (new_collation_sorted_indices)
    (find_collation_sorted_indices, sorted_indices_by_letter)
    (destroy_document_information_except_tree),
    tp/Texinfo/XS/main/document_types.h
    (COLLATION_INDICES_SORTED_BY_LETTER)
    (COLLATIONS_INDICES_SORTED_BY_LETTER): add sorted_indices_by_letter
    as in Perl.
    
    * tp/Texinfo/XS/convert/converter.c
    (get_converter_indices_sorted_by_letter): call document
    sorted_indices_by_letter. Remove converter_sort_indices_by_letter.
    
    * tp/Texinfo/Convert/Converter.pm
    (get_converter_indices_sorted_by_letter),
    tp/Texinfo/XS/convert/ConvertXS.xs
    (get_converter_indices_sorted_by_letter): return index sorted by
    letter instead of caching it in the converter, it is already cached in
    the document.
    
    * tp/Texinfo/Document.pm (%XS_structure_overrides),
    tp/Texinfo/XS/main/DocumentXS.xs (indices_sort_strings),
    tp/Texinfo/XS/main/build_perl_info.c (build_document)
    (find_idx_name_entry_number_sv, build_indices_sort_strings)
    (build_sorted_indices_by_letter): add XS interface for
    indices_sort_strings and sorted_indices_by_letter.
    
    * tp/t/test_utils.pl (test), tp/texi2any.pl: call indices_sort_strings
    early such that error messages from XS can be collected.
---
 ChangeLog                                          |  66 +++
 tp/Texinfo/Convert/Converter.pm                    |  16 +-
 tp/Texinfo/Convert/LaTeX.pm                        |   3 +
 tp/Texinfo/Document.pm                             |   3 +-
 tp/Texinfo/Indices.pm                              |   7 +-
 tp/Texinfo/XS/convert/ConvertXS.xs                 |   2 +-
 tp/Texinfo/XS/convert/converter.c                  |  35 +-
 tp/Texinfo/XS/convert/converter.h                  |   1 -
 tp/Texinfo/XS/main/DocumentXS.xs                   |  34 ++
 tp/Texinfo/XS/main/IndicesXS.xs                    |   6 +-
 tp/Texinfo/XS/main/build_perl_info.c               | 216 ++++++--
 tp/Texinfo/XS/main/build_perl_info.h               |   5 +-
 tp/Texinfo/XS/main/call_perl_function.c            |  95 ++++
 tp/Texinfo/XS/main/call_perl_function.h            |   6 +
 tp/Texinfo/XS/main/converter_types.h               |  12 -
 tp/Texinfo/XS/main/document.c                      | 151 ++++++
 tp/Texinfo/XS/main/document.h                      |  10 +
 tp/Texinfo/XS/main/document_types.h                |  64 +++
 tp/Texinfo/XS/main/manipulate_indices.c            | 561 ++++++++++++++++-----
 tp/Texinfo/XS/main/manipulate_indices.h            |  15 +-
 tp/Texinfo/options_data.txt                        |   4 +
 tp/t/test_utils.pl                                 |   7 +-
 .../res_parser/formatting_epub/formatting.2        |   2 +-
 .../res_parser/formatting_html32/formatting.2      |   2 +-
 .../formatting_html_no_split/formatting.2          |   2 +-
 .../res_parser/formatting_info/formatting.2        |   2 +-
 .../res_parser/formatting_plaintext/formatting.2   |   2 +-
 .../res_parser/formatting_xhtml/formatting.2       |   2 +-
 .../formatting_enable_encoding/formatting.2        |   2 +-
 .../res_parser/formatting_epub_nodes/formatting.2  |   2 +-
 .../res_parser/formatting_exotic/formatting.2      |   2 +-
 .../layout/res_parser/formatting_fr/formatting.2   |   2 +-
 .../res_parser/formatting_fr_icons/formatting.2    |   2 +-
 .../res_parser/formatting_fr_info/formatting.2     |   2 +-
 .../formatting_info_ascii_punctuation/formatting.2 |   2 +-
 .../formatting_info_disable_encoding/formatting.2  |   2 +-
 .../res_parser/formatting_inline_css/formatting.2  |   2 +-
 .../res_parser/formatting_mathjax/formatting.2     |   2 +-
 .../formatting_numerical_entities/formatting.2     |   2 +-
 .../formatting.2                                   |   2 +-
 .../formatting_sort_element_counts/formatting.2    |   2 +-
 .../res_parser/formatting_texi2html/formatting.2   |   2 +-
 .../formatting_texi2html_nodes/formatting.2        |   2 +-
 .../formatting_weird_quotes/formatting.2           |   2 +-
 .../res_parser/formatting_singular/formatting.2    |   2 +-
 tp/texi2any.pl                                     |   9 +
 46 files changed, 1101 insertions(+), 273 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index b15334975e..d7fb177a5f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,69 @@
+2024-02-12  Patrice Dumas  <pertusus@free.fr>
+
+       * tp/Texinfo/options_data.txt (DOCUMENTLANGUAGE_COLLATION)
+       (XS_STRXFRM_COLLATION_LOCALE): add customization variables.
+
+       * tp/Texinfo/XS/main/call_perl_function.c (call_setup_collator)
+       (call_collator_getSortKey), tp/Texinfo/XS/main/document_types.h
+       (BYTES_STRING, enum collation_type_name),
+       tp/Texinfo/XS/main/manipulate_indices.c (INDEX_COLLATOR, get_sort_key)
+       (setup_collator, compare_byte_strings, compare_index_letter)
+       (compare_sortable_subentry_keys),
+       tp/Texinfo/XS/main/manipulate_indices.h (SORTABLE_INDEX_SUBENTRY):
+       add an enum for the types of collations, and a structure for a
+       collator.  Add the possibility to call perl code to get a collator
+       object and get Perl sort keys as a possibility for collation sort
+       strings.  Use bytes strings with length through the BYTES_STRING
+       structure, to be able to use strings with NUL within as collation
+       string keys.  This is needed for collation keys coming from Perl and a
+       logical structure in C for collation binary strings.  Use memcmp to
+       compare.
+
+       * tp/Texinfo/XS/main/document.c (document_indices_sort_strings)
+       (destroy_document_information_except_tree),
+       tp/Texinfo/XS/main/document_types.h (INDEX_SUBENTRY_SORT_STRING)
+       (INDEX_ENTRY_SORT_STRING, INDEX_SORT_STRINGS, INDICES_SORT_STRINGS)
+       (DOCUMENT), tp/Texinfo/XS/main/manipulate_indices.c
+       (destroy_index_entries_sort_strings),
+       tp/Texinfo/XS/main/manipulate_indices.c
+       (setup_index_entries_sort_strings, setup_sortable_index_entries)
+       (setup_sort_sortable_strings_collator, sort_indices_by_letter): add
+       setup_index_entries_sort_strings based on setup_sortable_index_entries
+       code and add setup_sort_sortable_strings_collator, as in Perl.  Add
+       document_indices_sort_strings.
+
+       * tp/Texinfo/XS/main/manipulate_indices.c
+       (destroy_indices_sortable_entries): add.
+
+       * tp/Texinfo/XS/main/document.c (new_collation_sorted_indices)
+       (find_collation_sorted_indices, sorted_indices_by_letter)
+       (destroy_document_information_except_tree),
+       tp/Texinfo/XS/main/document_types.h
+       (COLLATION_INDICES_SORTED_BY_LETTER)
+       (COLLATIONS_INDICES_SORTED_BY_LETTER): add sorted_indices_by_letter
+       as in Perl.
+
+       * tp/Texinfo/XS/convert/converter.c
+       (get_converter_indices_sorted_by_letter): call document
+       sorted_indices_by_letter. Remove converter_sort_indices_by_letter.
+
+       * tp/Texinfo/Convert/Converter.pm
+       (get_converter_indices_sorted_by_letter),
+       tp/Texinfo/XS/convert/ConvertXS.xs
+       (get_converter_indices_sorted_by_letter): return index sorted by
+       letter instead of caching it in the converter, it is already cached in
+       the document.
+
+       * tp/Texinfo/Document.pm (%XS_structure_overrides),
+       tp/Texinfo/XS/main/DocumentXS.xs (indices_sort_strings),
+       tp/Texinfo/XS/main/build_perl_info.c (build_document)
+       (find_idx_name_entry_number_sv, build_indices_sort_strings)
+       (build_sorted_indices_by_letter): add XS interface for
+       indices_sort_strings and sorted_indices_by_letter.
+
+       * tp/t/test_utils.pl (test), tp/texi2any.pl: call indices_sort_strings
+       early such that error messages from XS can be collected.
+
 2024-02-11  Gavin Smith <gavinsmith0123@gmail.com>
 
        * doc/texinfo.texi (Other Customization Variables)
diff --git a/tp/Texinfo/Convert/Converter.pm b/tp/Texinfo/Convert/Converter.pm
index 031d659c3c..afd07ca12a 100644
--- a/tp/Texinfo/Convert/Converter.pm
+++ b/tp/Texinfo/Convert/Converter.pm
@@ -1750,15 +1750,8 @@ sub get_converter_indices_sorted_by_letter($)
   }
 
   if ($indices_information) {
-    if (!$self->get_conf('TEST') and $self->{'converter_descriptor'}
-        and $XS_convert) {
-      # get from XS
-      if ($self->{'index_entries_by_letter'}) {
-        return $self->{'index_entries_by_letter'};
-      }
-
-      $self->{'index_entries_by_letter'}
-        = _XS_get_converter_indices_sorted_by_letter($self,
+    if (!$self->{'converter_descriptor'} and $XS_convert) {
+      return _XS_get_converter_indices_sorted_by_letter($self,
                                                      $indices_information);
     } else {
       my $use_unicode_collation
@@ -1768,13 +1761,12 @@ sub get_converter_indices_sorted_by_letter($)
         $locale_lang = $self->get_conf('COLLATION_LANGUAGE');
       }
 
-      $self->{'index_entries_by_letter'}
-        = Texinfo::Document::sorted_indices_by_letter(undef, $self,
+      return Texinfo::Document::sorted_indices_by_letter(undef, $self,
                                                  $self->{'document'},
                                    $use_unicode_collation, $locale_lang);
     }
   }
-  return $self->{'index_entries_by_letter'};
+  return {};
 }
 
 sub _count_converted_text($$)
diff --git a/tp/Texinfo/Convert/LaTeX.pm b/tp/Texinfo/Convert/LaTeX.pm
index 644cc6948d..0c1069e530 100644
--- a/tp/Texinfo/Convert/LaTeX.pm
+++ b/tp/Texinfo/Convert/LaTeX.pm
@@ -2504,6 +2504,9 @@ sub _index_entry($$)
         Texinfo::Convert::Text::set_options_code(
           $self->{'index_formatting_text_options'});
       }
+      # NOTE in XS code, the $self->{'index_formatting_text_options'}
+      # argument is ignored, instead the $self converter is used to find C
+      # text options data setup by setup_index_entry_keys_formatting.
       my $sort_string
            = Texinfo::Indices::index_entry_element_sort_string(
                                           $self, $entry,
diff --git a/tp/Texinfo/Document.pm b/tp/Texinfo/Document.pm
index 69f230a371..269a3ecabc 100644
--- a/tp/Texinfo/Document.pm
+++ b/tp/Texinfo/Document.pm
@@ -60,6 +60,8 @@ our %XS_structure_overrides = (
     => "Texinfo::DocumentXS::rebuild_document",
   "Texinfo::Document::rebuild_tree"
     => "Texinfo::DocumentXS::rebuild_tree",
+  "Texinfo::Document::indices_sort_strings"
+    => "Texinfo::DocumentXS::indices_sort_strings",
 );
 
 our $module_loaded = 0;
@@ -206,7 +208,6 @@ sub merged_indices($)
 
 # TODO document
 # call setup_index_entries_sort_strings and cache the result.
-# TODO XS override
 sub indices_sort_strings($$$;$)
 {
   my $registrar = shift;
diff --git a/tp/Texinfo/Indices.pm b/tp/Texinfo/Indices.pm
index 0b34434f25..9b524ddf87 100644
--- a/tp/Texinfo/Indices.pm
+++ b/tp/Texinfo/Indices.pm
@@ -333,7 +333,7 @@ sub setup_index_entries_sort_strings($$$$;$)
         Texinfo::Convert::Text::set_options_code($convert_text_options);
       }
       my $entry_sort_string
-        = index_entry_element_sort_string ($customization_information,
+        = index_entry_element_sort_string($customization_information,
                                $index_entry, $main_entry_element,
                            $convert_text_options, $prefer_reference_element);
       my $non_empty_index_subentries = 0;
@@ -476,6 +476,8 @@ sub _setup_sort_sortable_strings_collator($$$$;$$$)
 
   my $indices_sort_strings;
   if ($document) {
+    # simple wrapper around setup_index_entries_sort_strings that caches the
+    # result
     $indices_sort_strings = Texinfo::Document::indices_sort_strings($registrar,
                                    $customization_information, $document);
   } else {
@@ -638,7 +640,7 @@ sub index_entry_first_letter_text_or_command($;$)
   }
 }
 
-sub sort_indices_by_letter($$$$$$;$)
+sub sort_indices_by_letter($$$$;$$$)
 {
   my $registrar = shift;
   my $customization_information = shift;
@@ -665,7 +667,6 @@ sub sort_indices_by_letter($$$$$$;$)
     foreach my $sortable_entry (@{$sortable_index_entries}) {
       my $entry_key
         = $sortable_entry->{'entry_strings_alpha'}->[0]->{'sort_string'};
-
       # the following line leads to each accented letter being separate
       # $letter = uc(substr($entry_key, 0, 1));
       my $letter_string = uc(substr($entry_key, 0, 1));
diff --git a/tp/Texinfo/XS/convert/ConvertXS.xs 
b/tp/Texinfo/XS/convert/ConvertXS.xs
index 7bc035a4ba..e8b91de8dd 100644
--- a/tp/Texinfo/XS/convert/ConvertXS.xs
+++ b/tp/Texinfo/XS/convert/ConvertXS.xs
@@ -190,7 +190,7 @@ get_converter_indices_sorted_by_letter (SV *converter_sv, 
SV *indices_informatio
         if (self)
           {
             INDEX_SORTED_BY_LETTER *index_entries_by_letter
-              = converter_sort_indices_by_letter (self);
+              = get_converter_indices_sorted_by_letter (self);
             RETVAL
              = build_sorted_indices_by_letter (index_entries_by_letter,
                                                indices_information);
diff --git a/tp/Texinfo/XS/convert/converter.c 
b/tp/Texinfo/XS/convert/converter.c
index 59373fa38e..3c7285d1f9 100644
--- a/tp/Texinfo/XS/convert/converter.c
+++ b/tp/Texinfo/XS/convert/converter.c
@@ -637,39 +637,18 @@ free_comma_index_subentries_tree (ELEMENT_LIST 
*element_list)
   destroy_list (element_list);
 }
 
-INDEX_SORTED_BY_LETTER *
-converter_sort_indices_by_letter (CONVERTER *self)
-{
-  if (self->index_entries_by_letter)
-    return self->index_entries_by_letter;
-
-  const MERGED_INDICES *merged_indices
-    = document_merged_indices (self->document);
-
-  self->index_entries_by_letter
-    = sort_indices_by_letter (&self->error_messages, self->conf,
-                              merged_indices,
-                              self->document->index_names);
-  return self->index_entries_by_letter;
-}
-
 INDEX_SORTED_BY_LETTER *
 get_converter_indices_sorted_by_letter (CONVERTER *self)
 {
-  if (self->index_entries_by_letter)
-    return self->index_entries_by_letter;
-
-  if (self->document->index_names)
+  if (self->document)
     {
-      /* get Perl sorting for reproducible tests */
-      if (self->conf->TEST.integer > 0)
-        self->index_entries_by_letter
-         = get_call_index_entries_sorted_by_letter (self);
-      else /* sets self->index_entries_by_letter */
-        converter_sort_indices_by_letter (self);
+      return sorted_indices_by_letter (&self->error_messages, self->conf,
+                               self->document,
+                               self->conf->USE_UNICODE_COLLATION.integer,
+                               self->conf->COLLATION_LANGUAGE.string,
+                               self->conf->XS_STRXFRM_COLLATION_LOCALE.string);
     }
-
-  return self->index_entries_by_letter;
+  return 0;
 }
 
 /* to be freed by caller */
diff --git a/tp/Texinfo/XS/convert/converter.h 
b/tp/Texinfo/XS/convert/converter.h
index 63170a55fa..66915297e8 100644
--- a/tp/Texinfo/XS/convert/converter.h
+++ b/tp/Texinfo/XS/convert/converter.h
@@ -114,7 +114,6 @@ ELEMENT_LIST *comma_index_subentries_tree (const ELEMENT 
*current_entry,
                                            char *separator);
 void free_comma_index_subentries_tree (ELEMENT_LIST *element);
 
-INDEX_SORTED_BY_LETTER *converter_sort_indices_by_letter (CONVERTER *self);
 INDEX_SORTED_BY_LETTER *get_converter_indices_sorted_by_letter
                                                  (CONVERTER *self);
 
diff --git a/tp/Texinfo/XS/main/DocumentXS.xs b/tp/Texinfo/XS/main/DocumentXS.xs
index bed412bef4..3fc4e4e923 100644
--- a/tp/Texinfo/XS/main/DocumentXS.xs
+++ b/tp/Texinfo/XS/main/DocumentXS.xs
@@ -176,6 +176,40 @@ set_document_options (SV *sv_options_in, SV *document_in)
             register_document_options (document, options);
           }
 
+SV *
+indices_sort_strings (SV *registrar, SV *main_configuration, SV *document_in, 
int prefer_reference_element=0)
+    PREINIT:
+        DOCUMENT *document = 0;
+        const INDICES_SORT_STRINGS *indices_sort_strings = 0;
+        SV **indices_information_sv;
+        HV *document_hv;
+     CODE:
+        document = get_sv_document_document (document_in,
+                                             "indices_sort_strings");
+        if (document)
+          indices_sort_strings
+           = document_indices_sort_strings (document->error_messages,
+                                          document->options, document,
+                                             prefer_reference_element);
+
+        document_hv = (HV *) SvRV (document_in);
+        indices_information_sv
+          = hv_fetch (document_hv, "indices", strlen ("indices"), 0);
+
+        if (indices_sort_strings && indices_information_sv)
+          {
+            HV *indices_information_hv = (HV *) SvRV (*indices_information_sv);
+            HV *indices_sort_strings_hv
+              = build_indices_sort_strings (indices_sort_strings,
+                                            indices_information_hv);
+
+            RETVAL = newRV_inc ((SV *) indices_sort_strings_hv);
+          }
+        else
+          RETVAL = newSV (0);
+    OUTPUT:
+        RETVAL
+
 
 # Next correspond to XS interfaces that have no associated
 # .xs file.
diff --git a/tp/Texinfo/XS/main/IndicesXS.xs b/tp/Texinfo/XS/main/IndicesXS.xs
index 5cd20fb47d..e863ae2ea5 100644
--- a/tp/Texinfo/XS/main/IndicesXS.xs
+++ b/tp/Texinfo/XS/main/IndicesXS.xs
@@ -47,13 +47,13 @@ MODULE = Texinfo::IndicesXS PACKAGE = Texinfo::IndicesXS
 PROTOTYPES: ENABLE
 
 # This function triggers setting the information needed for calls
-# to index_entry_element_sort_string in C, either in a document
+# to index_entry_element_sort_string through XS, either in a document
 # or in a converter, depending whether index sorting is done with a converter
 # or without.
 # A returned hash reference is needed as some information is set in the
-# hash in perl afterwards, but this information is not used as the hash
+# hash in Perl afterwards, but this information is not used as the hash
 # is not used by any function not overriden, so there is no need to
-# return information corresponding to the text options for perl.  An empty
+# return information corresponding to the text options for Perl.  An empty
 # hash reference is therefore returned.
 SV *
 setup_index_entry_keys_formatting (SV *customization_info_sv)
diff --git a/tp/Texinfo/XS/main/build_perl_info.c 
b/tp/Texinfo/XS/main/build_perl_info.c
index 9ced638642..d53e17b64f 100644
--- a/tp/Texinfo/XS/main/build_perl_info.c
+++ b/tp/Texinfo/XS/main/build_perl_info.c
@@ -1216,6 +1216,7 @@ build_document (size_t document_descriptor, int no_store)
   HV *hv_commands_info;
   HV *hv_index_names;
   HV *hv_listoffloats_list;
+  HV *hv_indices_sort_strings = 0;
   AV *av_internal_xref;
   HV *hv_identifiers_target;
   AV *av_labels_list;
@@ -1267,6 +1268,11 @@ build_document (size_t document_descriptor, int no_store)
   if (document->sections_list)
     av_sections_list = build_elements_list (document->sections_list);
 
+  if (document->indices_sort_strings)
+    hv_indices_sort_strings = build_indices_sort_strings (
+                                      document->indices_sort_strings,
+                                      hv_index_names);
+
 #define STORE(key, value) hv_store (hv, key, strlen (key), newRV_inc ((SV *) 
value), 0)
 
   /* must be kept in sync with Texinfo::Document register keys */
@@ -1285,6 +1291,9 @@ build_document (size_t document_descriptor, int no_store)
 
   if (av_sections_list)
     STORE("sections_list", av_sections_list);
+
+  if (hv_indices_sort_strings)
+    STORE("index_entries_sort_strings", hv_indices_sort_strings);
 #undef STORE
 
   if (no_store)
@@ -1922,14 +1931,162 @@ build_expanded_formats (EXPANDED_FORMAT 
*expanded_formats)
   return newRV_noinc ((SV *)expanded_hv);
 }
 
+SV *
+find_idx_name_entry_number_sv (HV *indices_information_hv,
+                               const char* index_name, int entry_number,
+                               const char *message)
+{
+  SV **index_info_sv;
+  SV *index_entry_sv = 0;
+
+  dTHX;
+
+  index_info_sv = hv_fetch (indices_information_hv, index_name,
+                            strlen (index_name), 0);
+  if (!index_info_sv)
+    {
+      fprintf (stderr, "%s index %s not found\n", message, index_name);
+    }
+  else
+    {
+      HV *index_info_hv = (HV *) SvRV (*index_info_sv);
+      SV **index_info_index_entries_sv = hv_fetch (index_info_hv,
+             "index_entries", strlen ("index_entries"), 0);
+
+      if (!index_info_index_entries_sv)
+        {
+          fprintf (stderr, "%s index %s 'index_entries' not found\n",
+                           message, index_name);
+        }
+      else
+        {
+          AV *index_info_entries_av
+              = (AV *) SvRV (*index_info_index_entries_sv);
+
+          SV **index_entry_info_sv = av_fetch (index_info_entries_av,
+                                             entry_number -1, 0);
+
+          if (!index_entry_info_sv)
+            {
+              fprintf (stderr, "%s: %d in %s not found\n", message,
+                       entry_number, index_name);
+            }
+          else
+            index_entry_sv = *index_entry_info_sv;
+        }
+    }
+  return index_entry_sv;
+}
+
+HV *
+build_indices_sort_strings (const INDICES_SORT_STRINGS *indices_sort_strings,
+                            HV *indices_information_hv)
+{
+  HV *indices_sort_strings_hv;
+  size_t i;
+
+  dTHX;
+
+  if (!indices_sort_strings)
+    return 0;
+
+  indices_sort_strings_hv = newHV ();
+
+  for (i = 0; i < indices_sort_strings->number; i++)
+    {
+      INDEX_SORT_STRINGS *index_sort_strings
+         = &indices_sort_strings->indices[i];
+      char *index_name = index_sort_strings->index->name;
+
+      if (index_sort_strings->entries_number > 0)
+        {
+          size_t j;
+          AV *sort_string_entries_av = newAV ();
+
+          hv_store (indices_sort_strings_hv, index_name, strlen (index_name),
+                    newRV_noinc ((SV *)sort_string_entries_av), 0);
+
+          for (j = 0; j < index_sort_strings->entries_number; j++)
+            {
+              INDEX_ENTRY_SORT_STRING *index_entry_sort_string
+                = &index_sort_strings->sort_string_entries[j];
+              INDEX_ENTRY *entry = index_entry_sort_string->entry;
+              char *entry_index_name = entry->index_name;
+              int entry_number = entry->number;
+              char *message;
+              SV *index_entry_sv;
+              HV *index_entry_sort_string_hv;
+              AV *sort_string_subentries_av;
+              size_t k;
+
+              if (index_entry_sort_string->subentries_number <= 0)
+                {
+                  fprintf (stderr, "BUG: build_indices_sort_strings:"
+                   " %s: entry %zu: no subentries", index_name, j);
+                  continue;
+                }
+
+              xasprintf (&message, "BUG: build_indices_sort_strings:"
+                                   " %s: entry %zu", index_name, j);
+              index_entry_sv
+                = find_idx_name_entry_number_sv (indices_information_hv,
+                                                 entry_index_name, 
entry_number,
+                                                 message);
+              free (message);
+
+              /* probably not possible, unless there is a bug */
+              if (!index_entry_sv)
+                continue;
+
+              index_entry_sort_string_hv = newHV ();
+              av_push (sort_string_entries_av,
+                       newRV_noinc ((SV *) index_entry_sort_string_hv));
+
+              hv_store (index_entry_sort_string_hv, "index_name",
+                        strlen ("index_name"),
+                        newSVpv_utf8 (entry->index_name, 0), 0);
+              hv_store (index_entry_sort_string_hv, "number",
+                        strlen ("number"), newSViv (entry->number), 0);
+
+              SvREFCNT_inc (index_entry_sv);
+              hv_store (index_entry_sort_string_hv, "entry",
+                        strlen ("entry"), index_entry_sv, 0);
+
+              sort_string_subentries_av = newAV ();
+              hv_store (index_entry_sort_string_hv, "sort_strings",
+                        strlen ("sort_strings"),
+                        newRV_noinc ((SV *) sort_string_subentries_av), 0);
+
+              for (k = 0; k < index_entry_sort_string->subentries_number; k++)
+                {
+                  INDEX_SUBENTRY_SORT_STRING *subentry_sort_string
+                    = &index_entry_sort_string->sort_string_subentries[k];
+                  HV *subentry_sort_string_hv = newHV ();
+
+                  av_push (sort_string_subentries_av,
+                           newRV_noinc ((SV *) subentry_sort_string_hv));
+
+                  hv_store (subentry_sort_string_hv, "sort_string",
+                            strlen ("sort_string"),
+                     newSVpv_utf8 (subentry_sort_string->sort_string, 0), 0);
+                  hv_store (subentry_sort_string_hv, "alpha",
+                            strlen ("alpha"),
+                            newSViv (subentry_sort_string->alpha), 0);
+                }
+            }
+        }
+    }
+  return indices_sort_strings_hv;
+}
+
 SV *
 build_sorted_indices_by_letter (
-                      INDEX_SORTED_BY_LETTER *index_entries_by_letter,
+                      const INDEX_SORTED_BY_LETTER *index_entries_by_letter,
                       SV *indices_information)
 {
   HV *indices_hv;
   HV *indices_information_hv;
-  INDEX_SORTED_BY_LETTER *idx;
+  const INDEX_SORTED_BY_LETTER *idx;
 
   dTHX;
 
@@ -1973,51 +2130,16 @@ build_sorted_indices_by_letter (
               INDEX_ENTRY *entry = letter->entries[j];
               char *index_name = entry->index_name;
               int entry_number = entry->number;
-              SV **index_info_sv;
-              SV *index_entry_sv = 0;
-
-              index_info_sv = hv_fetch (indices_information_hv, index_name,
-                                        strlen (index_name), 0);
-              if (!index_info_sv)
-                {
-                  fprintf (stderr,
-                       "BUG: build_sorted_indices_by_letter: "
-                       "%s: %s: entry %zu index %s not found\n",
-                           idx->name, letter->letter, j, index_name);
-                }
-              else
-                {
-                  HV *index_info_hv = (HV *) SvRV (*index_info_sv);
-                  SV **index_info_index_entries_sv = hv_fetch (index_info_hv,
-                         "index_entries", strlen ("index_entries"), 0);
-
-                  if (!index_info_index_entries_sv)
-                    {
-                      fprintf (stderr,
-                       "BUG: build_sorted_indices_by_letter: "
-                 "%s: %s: entry %zu index %s 'index_entries' not found\n",
-                         idx->name, letter->letter, j, index_name);
-                    }
-                  else
-                    {
-                      AV *index_info_entries_av
-                          = (AV *) SvRV (*index_info_index_entries_sv);
-
-                      SV **index_entry_info_sv = av_fetch 
(index_info_entries_av,
-                                                         entry_number -1, 0);
-
-                      if (!index_entry_info_sv)
-                        {
-                          fprintf (stderr,
-                             "BUG: build_sorted_indices_by_letter: "
-                             "%s: %s: entry %zu: %d in %s not found\n",
-                                idx->name, letter->letter, j,
-                                entry_number, index_name);
-                        }
-                      else
-                        index_entry_sv = *index_entry_info_sv;
-                    }
-                }
+              char *message;
+              SV *index_entry_sv;
+              xasprintf (&message, "BUG: build_sorted_indices_by_letter:"
+                                   " %s: %s: entry %zu", idx->name,
+                                   letter->letter, j);
+              index_entry_sv
+                = find_idx_name_entry_number_sv (indices_information_hv,
+                                                 index_name, entry_number,
+                                                 message);
+              free (message);
 
               if (index_entry_sv)
                 {
diff --git a/tp/Texinfo/XS/main/build_perl_info.h 
b/tp/Texinfo/XS/main/build_perl_info.h
index 5941261d79..9cf6baed78 100644
--- a/tp/Texinfo/XS/main/build_perl_info.h
+++ b/tp/Texinfo/XS/main/build_perl_info.h
@@ -53,8 +53,11 @@ void pass_output_unit_files (SV *converter_sv,
 void build_output_files_information (SV *converter_sv,
                    OUTPUT_FILES_INFORMATION *output_files_information);
 
+HV *build_indices_sort_strings (
+                  const INDICES_SORT_STRINGS *indices_sort_strings,
+                            HV *indices_information_hv);
 SV *build_sorted_indices_by_letter (
-                      INDEX_SORTED_BY_LETTER *index_entries_by_letter,
+                      const INDEX_SORTED_BY_LETTER *index_entries_by_letter,
                       SV *indices_information);
 
 SV *html_build_direction_icons (CONVERTER *converter,
diff --git a/tp/Texinfo/XS/main/call_perl_function.c 
b/tp/Texinfo/XS/main/call_perl_function.c
index b270bff09a..7ddc0c8ef0 100644
--- a/tp/Texinfo/XS/main/call_perl_function.c
+++ b/tp/Texinfo/XS/main/call_perl_function.c
@@ -34,6 +34,7 @@
 
 #include "tree_types.h"
 #include "converter_types.h"
+#include "document_types.h"
 #include "build_perl_info.h"
 /* for get_sv_index_entries_sorted_by_letter */
 #include "get_perl_info.h"
@@ -208,3 +209,97 @@ get_call_index_entries_sorted_by_letter (CONVERTER *self)
   return result;
 }
 
+const void *
+call_setup_collator (int use_unicode_collation, const char *locale_lang)
+{
+  int count;
+  const void *result = 0;
+  SV *collator_sv = 0;
+
+  dTHX;
+
+  dSP;
+
+  ENTER;
+  SAVETMPS;
+
+  PUSHMARK(SP);
+  EXTEND(SP, 2);
+
+  PUSHs(sv_2mortal (newSViv (use_unicode_collation)));
+  PUSHs(sv_2mortal (newSVpv (locale_lang, 0)));
+
+  PUTBACK;
+
+  count = call_pv ("Texinfo::Indices::_setup_collator",
+                   G_SCALAR);
+
+  SPAGAIN;
+
+  if (count != 1)
+    croak("_setup_collator should return 1 item\n");
+
+  collator_sv = POPs;
+  if (SvOK (collator_sv))
+    {
+      SvREFCNT_inc (collator_sv);
+      result = (const void *) collator_sv;
+    }
+
+  PUTBACK;
+
+  FREETMPS;
+  LEAVE;
+
+  return result;
+}
+
+BYTES_STRING *
+call_collator_getSortKey (const void *collator_sv, const char *string)
+{
+  BYTES_STRING *result;
+  unsigned char *result_ret;
+  STRLEN len;
+  SV *result_sv;
+  int count;
+
+  dTHX;
+
+  result = malloc (sizeof (BYTES_STRING));
+  dSP;
+
+  ENTER;
+  SAVETMPS;
+
+  PUSHMARK(SP);
+  EXTEND(SP, 2);
+
+  PUSHs((SV *) collator_sv);
+  PUSHs(sv_2mortal (newSVpv_utf8 (string, 0)));
+
+  PUTBACK;
+
+  count = call_method ("getSortKey",
+                       G_SCALAR);
+
+  SPAGAIN;
+
+  if (count != 1)
+    croak("getSortKey should return 1 item\n");
+
+  result_sv = POPs;
+  result_ret = (unsigned char *)SvPVbyte (result_sv, len);
+  result->len = (size_t) len;
+  result->bytes = (unsigned char *)
+    malloc (sizeof (unsigned char) * len);
+  memcpy (result->bytes, result_ret, result->len);
+
+  PUTBACK;
+
+  FREETMPS;
+  LEAVE;
+
+  return result;
+}
+
+
diff --git a/tp/Texinfo/XS/main/call_perl_function.h 
b/tp/Texinfo/XS/main/call_perl_function.h
index cbeb404915..1aad256ea0 100644
--- a/tp/Texinfo/XS/main/call_perl_function.h
+++ b/tp/Texinfo/XS/main/call_perl_function.h
@@ -9,6 +9,12 @@ char *call_nodenamenormalization_unicode_to_transliterate 
(char *text);
 
 char *call_latex_convert_to_latex_math (CONVERTER *self, ELEMENT *element);
 
+const void *call_setup_collator (int use_unicode_collation,
+                                 const char *locale_lang);
+
+BYTES_STRING *call_collator_getSortKey (const void *collator_sv,
+                                        const char *string);
+
 INDEX_SORTED_BY_LETTER *get_call_index_entries_sorted_by_letter
                                                    (CONVERTER *self);
 #endif
diff --git a/tp/Texinfo/XS/main/converter_types.h 
b/tp/Texinfo/XS/main/converter_types.h
index a4b3f7084a..b475f85fe3 100644
--- a/tp/Texinfo/XS/main/converter_types.h
+++ b/tp/Texinfo/XS/main/converter_types.h
@@ -317,18 +317,6 @@ typedef struct HTML_SHARED_CONVERSION_STATE {
     /* formatted_nodedescriptions */
 } HTML_SHARED_CONVERSION_STATE;
 
-typedef struct LETTER_INDEX_ENTRIES {
-    char *letter;
-    INDEX_ENTRY **entries;
-    size_t entries_number;
-} LETTER_INDEX_ENTRIES;
-
-typedef struct INDEX_SORTED_BY_LETTER {
-    char *name;
-    LETTER_INDEX_ENTRIES *letter_entries;
-    size_t letter_number;
-} INDEX_SORTED_BY_LETTER;
-
 typedef struct HTML_COMMAND_CONVERSION {
     char *element;
     int quote; /* for style commands formatting only */
diff --git a/tp/Texinfo/XS/main/document.c b/tp/Texinfo/XS/main/document.c
index b1c58ae64e..c082a2695e 100644
--- a/tp/Texinfo/XS/main/document.c
+++ b/tp/Texinfo/XS/main/document.c
@@ -157,6 +157,137 @@ register_document_convert_index_text_options (DOCUMENT 
*document,
   document->convert_index_text_options = text_options;
 }
 
+const INDICES_SORT_STRINGS *
+document_indices_sort_strings (ERROR_MESSAGE_LIST *error_messages,
+                               OPTIONS *options, DOCUMENT *document,
+                               int prefer_reference_element)
+{
+  if (!document->indices_sort_strings)
+    {
+      const MERGED_INDICES *merged_indices
+         = document_merged_indices (document);
+
+      document->indices_sort_strings
+       = setup_index_entries_sort_strings (error_messages, options,
+                               merged_indices, document->index_names,
+                               prefer_reference_element);
+    }
+
+  return document->indices_sort_strings;
+}
+
+static COLLATION_INDICES_SORTED_BY_LETTER *
+new_collation_sorted_indices (
+            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;
+}
+
+COLLATION_INDICES_SORTED_BY_LETTER *
+find_collation_sorted_indices (
+            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;
+}
+
+INDEX_SORTED_BY_LETTER *
+sorted_indices_by_letter (ERROR_MESSAGE_LIST *error_messages,
+                          OPTIONS *options, DOCUMENT *document,
+                          int use_unicode_collation,
+                          const char *collation_language,
+                          const char *collation_locale)
+{
+  COLLATIONS_INDICES_SORTED_BY_LETTER *collations;
+  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 (collations, ctn_unicode, "-");
+      new_collation_sorted_indices (collations, ctn_no_unicode, "");
+
+      document->sorted_indices_by_letter = collations;
+    }
+
+  collations = document->sorted_indices_by_letter;
+
+  if (use_unicode_collation == 0)
+    collation_sorted_indices
+      = &collations->collation_sorted_indices[ctn_no_unicode];
+  else if (!collation_language && !collation_locale)
+    collation_sorted_indices
+      = &collations->collation_sorted_indices[ctn_unicode];
+  else
+    {
+      enum collation_type_name type;
+      const char *language;
+      if (collation_language)
+        {
+          type = ctn_language_collation;
+          language = collation_language;
+        }
+      else
+        {
+          type = ctn_locale_collation;
+          language = collation_locale;
+        }
+      collation_sorted_indices
+          = find_collation_sorted_indices (collations, type, language);
+      if (!collation_sorted_indices)
+        collation_sorted_indices = new_collation_sorted_indices (collations,
+                                                              type, language);
+    }
+
+  if (!collation_sorted_indices->sorted_indices)
+    {
+      const MERGED_INDICES *merged_indices
+         = document_merged_indices (document);
+      collation_sorted_indices->sorted_indices
+        = sort_indices_by_letter (error_messages, options,
+                                  use_unicode_collation, collation_language,
+                                  collation_locale, merged_indices,
+                                  document->index_names, document);
+    }
+  return collation_sorted_indices->sorted_indices;
+}
+
 void
 destroy_document_information_except_tree (DOCUMENT *document)
 {
@@ -191,6 +322,26 @@ destroy_document_information_except_tree (DOCUMENT 
*document)
         destroy_text_options (document->convert_index_text_options);
       if (document->merged_indices)
         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_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);
+        }
     }
 }
 
diff --git a/tp/Texinfo/XS/main/document.h b/tp/Texinfo/XS/main/document.h
index 3359b20c41..2682dd7e63 100644
--- a/tp/Texinfo/XS/main/document.h
+++ b/tp/Texinfo/XS/main/document.h
@@ -31,6 +31,16 @@ void register_document_convert_index_text_options (DOCUMENT 
*document,
                                          struct TEXT_OPTIONS *text_options);
 
 const MERGED_INDICES *document_merged_indices (DOCUMENT *document);
+const INDICES_SORT_STRINGS *document_indices_sort_strings (
+                               ERROR_MESSAGE_LIST *error_messages,
+                               OPTIONS *options, DOCUMENT *document,
+                               int prefer_reference_element);
+INDEX_SORTED_BY_LETTER *sorted_indices_by_letter (
+                          ERROR_MESSAGE_LIST *error_messages,
+                          OPTIONS *options, DOCUMENT *document,
+                          int use_unicode_collation,
+                          const char *collation_language,
+                          const char *collation_locale);
 
 void remove_document_descriptor (int document_descriptor);
 ELEMENT *unregister_document_merge_with_document (int document_descriptor,
diff --git a/tp/Texinfo/XS/main/document_types.h 
b/tp/Texinfo/XS/main/document_types.h
index 73c1b37fe7..7cd1c2ff4b 100644
--- a/tp/Texinfo/XS/main/document_types.h
+++ b/tp/Texinfo/XS/main/document_types.h
@@ -77,6 +77,68 @@ typedef struct MERGED_INDICES {
     MERGED_INDEX *indices;
 } MERGED_INDICES;
 
+/* not used in document, but used for indices for sort keys that can
+   contain NUL */
+typedef struct BYTES_STRING {
+    size_t len;
+    unsigned char *bytes;
+} BYTES_STRING;
+
+typedef struct INDEX_SUBENTRY_SORT_STRING {
+    char *sort_string;
+    int alpha;
+} INDEX_SUBENTRY_SORT_STRING;
+
+typedef struct INDEX_ENTRY_SORT_STRING {
+    INDEX_ENTRY *entry;
+    /* in perl 'index_name' => $index_entry->{'index_name'} */
+    /* in perl 'number' => $index_entry->{'entry_number'} */
+    size_t subentries_number;
+    INDEX_SUBENTRY_SORT_STRING *sort_string_subentries;
+} INDEX_ENTRY_SORT_STRING;
+
+typedef struct INDEX_SORT_STRINGS {
+    MERGED_INDEX *index;
+    size_t entries_number;
+    INDEX_ENTRY_SORT_STRING *sort_string_entries;
+} INDEX_SORT_STRINGS;
+
+typedef struct INDICES_SORT_STRINGS {
+    size_t number;
+    INDEX_SORT_STRINGS *indices;
+} INDICES_SORT_STRINGS;
+
+typedef struct LETTER_INDEX_ENTRIES {
+    char *letter;
+    INDEX_ENTRY **entries;
+    size_t entries_number;
+} LETTER_INDEX_ENTRIES;
+
+typedef struct INDEX_SORTED_BY_LETTER {
+    char *name;
+    LETTER_INDEX_ENTRIES *letter_entries;
+    size_t letter_number;
+} INDEX_SORTED_BY_LETTER;
+
+enum collation_type_name {
+   ctn_unicode, /* the default */
+   ctn_no_unicode,
+   ctn_language_collation,
+   ctn_locale_collation, /* experimental, to test strxfrm */
+};
+
+typedef struct COLLATION_INDICES_SORTED_BY_LETTER {
+    enum collation_type_name type;
+    char *language;
+    INDEX_SORTED_BY_LETTER *sorted_indices;
+} COLLATION_INDICES_SORTED_BY_LETTER;
+
+typedef struct COLLATIONS_INDICES_SORTED_BY_LETTER {
+    size_t number;
+    size_t space;
+    COLLATION_INDICES_SORTED_BY_LETTER *collation_sorted_indices;
+} COLLATIONS_INDICES_SORTED_BY_LETTER;
+
 typedef struct DOCUMENT {
     int descriptor;
     ELEMENT *tree;
@@ -96,6 +158,8 @@ typedef struct DOCUMENT {
     struct OPTIONS *options; /* for options used in structuring */
     struct TEXT_OPTIONS *convert_index_text_options; /* for index
                                        sorting without converter */
+    INDICES_SORT_STRINGS *indices_sort_strings;
+    COLLATIONS_INDICES_SORTED_BY_LETTER *sorted_indices_by_letter;
 } DOCUMENT;
 
 /* not in document, but used in parser */
diff --git a/tp/Texinfo/XS/main/manipulate_indices.c 
b/tp/Texinfo/XS/main/manipulate_indices.c
index 1296907f6c..450029a18c 100644
--- a/tp/Texinfo/XS/main/manipulate_indices.c
+++ b/tp/Texinfo/XS/main/manipulate_indices.c
@@ -34,6 +34,7 @@
 #include "unicode.h"
 #include "convert_to_text.h"
 #include "convert_to_texinfo.h"
+#include "call_perl_function.h"
 #include "manipulate_indices.h"
 
 /* corresponding perl code in Texinfo::Indices */
@@ -253,62 +254,121 @@ index_entry_element_sort_string (const INDEX_ENTRY 
*main_entry,
   return sort_string;
 }
 
-static void
-set_sort_key (locale_t collation_locale, const char *input_string,
-              char **result_key)
+typedef struct INDEX_COLLATOR {
+    enum collation_type_name type;
+    char *language;
+    union {
+      /* perl element. This should be SV *sv,
+         but we don't want to include the Perl headers everywhere; */
+      const void *sv;
+  #ifdef HAVE_NEWLOCALE
+      locale_t locale;
+  #endif
+    };
+} INDEX_COLLATOR;
+
+static BYTES_STRING *get_sort_key (INDEX_COLLATOR *collator,
+                                   const char *sort_string)
 {
-  if (collation_locale)
+  BYTES_STRING *sort_key;
+  switch (collator->type)
     {
-  #ifdef HAVE_STRXFRM_L
-      size_t len = strxfrm_l (0, input_string, 0, collation_locale);
-      size_t check_len;
-
-      *result_key
-        = (char *) malloc ((len +1) * sizeof (char));
-      check_len = strxfrm_l (*result_key, input_string, len+1,
-                             collation_locale);
-      if (check_len != len)
-        fatal ("strxfrm_l returns a different length");
-  #endif
+      case ctn_no_unicode:
+        sort_key = (BYTES_STRING *) malloc (sizeof (BYTES_STRING));
+        sort_key->len = strlen (sort_string);
+        sort_key->bytes = (unsigned char *)
+           malloc (sizeof (unsigned char) * sort_key->len);
+        memcpy (sort_key->bytes, (unsigned char *) sort_string, sort_key->len);
+        break;
+      #ifdef HAVE_STRXFRM_L
+      case ctn_locale_collation:
+        {
+          size_t check_len;
+          char *char_sort_key;
+          sort_key = (BYTES_STRING *) malloc (sizeof (BYTES_STRING));
+          sort_key->len
+            = strxfrm_l (0, sort_string, 0,
+                         collator->locale);
+          char_sort_key = (char *) malloc (sizeof (char) * sort_key->len);
+          check_len
+            = strxfrm_l (char_sort_key, sort_string, sort_key->len,
+                         collator->locale);
+          sort_key->bytes = (unsigned char *)
+           malloc (sizeof (unsigned char) * sort_key->len);
+          memcpy (sort_key->bytes, (unsigned char *) char_sort_key,
+                  sort_key->len);
+          free (char_sort_key);
+          if (check_len != sort_key->len)
+            fatal ("strxfrm_l returns a different length");
+        }
+        break;
+      #endif
+      case ctn_unicode:
+      case ctn_language_collation:
+      default: /* !HAVE_STRXFRM_L && ctn_locale_collation */
+        {
+          char *uc_sort_string
+            = to_upper_or_lower_multibyte (sort_string, 1);
+          sort_key = call_collator_getSortKey (collator->sv,
+                                               uc_sort_string);
+          free (uc_sort_string);
+        }
+        break;
     }
-  else
-    *result_key = strdup (input_string);
+  return sort_key;
 }
 
-typedef struct INDEX_SORT_STRING_KEY {
-    char *sort_string;
-    char *sort_key;
-} INDEX_SORT_STRING_KEY;
-
-static INDEX_SORT_STRING_KEY *
-index_entry_element_sort_string_key (const INDEX_ENTRY *main_entry,
-                                     const ELEMENT *index_entry_element,
-                                     TEXT_OPTIONS *options, int in_code,
-                                     locale_t collation_locale,
-                                     int prefer_reference_element)
+void
+destroy_index_entries_sort_strings (INDICES_SORT_STRINGS *indices_sort_strings)
 {
-  INDEX_SORT_STRING_KEY *sort_string_key = (INDEX_SORT_STRING_KEY *)
-    malloc (sizeof (INDEX_SORT_STRING_KEY));
-  sort_string_key->sort_string = index_entry_element_sort_string (main_entry,
-                                     index_entry_element, options, in_code,
-                                     prefer_reference_element);
-  set_sort_key (collation_locale, sort_string_key->sort_string,
-                &sort_string_key->sort_key);
-
-  return sort_string_key;
+  if (indices_sort_strings && indices_sort_strings->number)
+    {
+      size_t i;
+      for (i = 0; i < indices_sort_strings->number; i++)
+        {
+          INDEX_SORT_STRINGS *index_sort_strings
+            = &indices_sort_strings->indices[i];
+          if (index_sort_strings->entries_number > 0)
+            {
+              size_t j;
+              for (j = 0; j < index_sort_strings->entries_number; j++)
+                {
+                  INDEX_ENTRY_SORT_STRING *entry_sort_string
+                    = &index_sort_strings->sort_string_entries[j];
+                  if (entry_sort_string->subentries_number > 0)
+                    {
+                      size_t k;
+                      for (k = 0; k < entry_sort_string->subentries_number;
+                           k++)
+                        {
+                          free (entry_sort_string->sort_string_subentries[k]
+                                             .sort_string);
+                        }
+                      free (entry_sort_string->sort_string_subentries);
+                    }
+                }
+            }
+          free (index_sort_strings->sort_string_entries);
+        }
+      free (indices_sort_strings->indices);
+    }
+  free (indices_sort_strings);
 }
 
-INDICES_SORTABLE_ENTRIES *
-setup_sortable_index_entries (ERROR_MESSAGE_LIST *error_messages,
-                      OPTIONS *options, const MERGED_INDICES *merged_indices,
-                      INDEX **indices_information,
-                      locale_t *collation_locale)
+INDICES_SORT_STRINGS *
+setup_index_entries_sort_strings (ERROR_MESSAGE_LIST *error_messages,
+                    OPTIONS *options, const MERGED_INDICES *merged_indices,
+                    INDEX **indices_information, int prefer_reference_element)
 {
   size_t i;
+  TEXT_OPTIONS *convert_text_options;
+
+  if (merged_indices->number <= 0)
+    return 0;
 
   /* convert index entries to sort string using unicode when possible
      independently of input and output encodings */
-  TEXT_OPTIONS *convert_text_options = new_text_options ();
+  convert_text_options = new_text_options ();
   convert_text_options->encoding = strdup ("utf-8");
   /*  It could be possible to set INCLUDE_DIRECTORIES, but there is no
       point doing so, as it is only useful for @verbatiminclude, which
@@ -317,47 +377,37 @@ setup_sortable_index_entries (ERROR_MESSAGE_LIST 
*error_messages,
                 options->INCLUDE_DIRECTORIES.strlist);
    */
 
-  /* similar to using Unicode::Collate in Perl */
-  *collation_locale = 0;
-
-  #ifdef HAVE_STRXFRM_L
-  #ifdef HAVE_NEWLOCALE
-  if (!options->USE_UNICODE_COLLATION.integer == 0)
-    *collation_locale = newlocale (LC_COLLATE_MASK, "en_US.utf-8", 0);
-  #endif
-  #endif
-
-  if (merged_indices->number <= 0)
-    return 0;
-
-  INDICES_SORTABLE_ENTRIES *indices_sortable_entries
-    = (INDICES_SORTABLE_ENTRIES *) malloc (sizeof (INDICES_SORTABLE_ENTRIES));
+  INDICES_SORT_STRINGS *indices_sort_strings
+    = (INDICES_SORT_STRINGS *) malloc (sizeof (INDICES_SORT_STRINGS));
 
-  indices_sortable_entries->number = merged_indices->number;
-  indices_sortable_entries->indices = (INDEX_SORTABLE_ENTRIES *)
-    malloc (merged_indices->number * sizeof (INDEX_SORTABLE_ENTRIES));
-  memset (indices_sortable_entries->indices, 0,
-          merged_indices->number * sizeof (INDEX_SORTABLE_ENTRIES));
+  indices_sort_strings->number = merged_indices->number;
+  indices_sort_strings->indices = (INDEX_SORT_STRINGS *)
+    malloc (merged_indices->number * sizeof (INDEX_SORT_STRINGS));
+  memset (indices_sort_strings->indices, 0,
+          merged_indices->number * sizeof (INDEX_SORT_STRINGS));
 
   for (i = 0; i < merged_indices->number; i++)
     {
       MERGED_INDEX *index = &merged_indices->indices[i];
-      INDEX_SORTABLE_ENTRIES *sortable_index_entries
-        = &indices_sortable_entries->indices[i];
+      INDEX_SORT_STRINGS *index_sort_strings
+        = &indices_sort_strings->indices[i];
       if (index->entries_number > 0)
         {
           size_t j;
+          /* keep track of number of non empty index entries number */
+          size_t nr = 0;
 
-          sortable_index_entries->index = index;
-          sortable_index_entries->number = index->entries_number;
-          sortable_index_entries->sortable_entries = (SORTABLE_INDEX_ENTRY *)
-            malloc (index->entries_number * sizeof (SORTABLE_INDEX_ENTRY));
+          index_sort_strings->index = index;
+          index_sort_strings->sort_string_entries = (INDEX_ENTRY_SORT_STRING *)
+            malloc (index->entries_number * sizeof (INDEX_ENTRY_SORT_STRING));
 
           for (j = 0; j < index->entries_number; j++)
             {
               int non_empty_index_subentries = 0;
-              SORTABLE_INDEX_SUBENTRY *sortable_subentry;
+              char *sort_string;
+              INDEX_SUBENTRY_SORT_STRING *subentry_sort_string;
               INDEX_ENTRY *index_entry = &index->index_entries[j];
+              INDEX_ENTRY_SORT_STRING entry_sort_string;
 
               ELEMENT *main_entry_element = index_entry->entry_element;
               ELEMENT *subentry = main_entry_element;
@@ -366,30 +416,28 @@ setup_sortable_index_entries (ERROR_MESSAGE_LIST 
*error_messages,
                 = indices_info_index_by_name (indices_information,
                                               index_entry->index_name);
 
-              INDEX_SORT_STRING_KEY *sort_string_key
-                = index_entry_element_sort_string_key (index_entry,
-                            main_entry_element, convert_text_options,
-                            entry_index->in_code, *collation_locale, 0);
-
-              SORTABLE_INDEX_ENTRY *sortable_entry
-                = &sortable_index_entries->sortable_entries[j];
+              sort_string
+               = index_entry_element_sort_string (index_entry,
+                                     subentry, convert_text_options,
+                                     entry_index->in_code,
+                                     prefer_reference_element);
 
-              sortable_entry->entry = index_entry;
-              sortable_entry->subentries_number = 1;
-              sortable_entry->sortable_subentries = (SORTABLE_INDEX_SUBENTRY *)
-                malloc (sizeof (SORTABLE_INDEX_SUBENTRY));
+              entry_sort_string.entry = index_entry;
+              entry_sort_string.subentries_number = 1;
+              entry_sort_string.sort_string_subentries
+                = (INDEX_SUBENTRY_SORT_STRING *)
+                   malloc (sizeof (INDEX_SUBENTRY_SORT_STRING));
 
-              sortable_subentry = &sortable_entry->sortable_subentries[0];
+              subentry_sort_string
+                = &entry_sort_string.sort_string_subentries[0];
 
-              if (sort_string_key->sort_string[strspn
-                   (sort_string_key->sort_string, whitespace_chars)] == '\0')
+              if (sort_string[strspn
+                   (sort_string, whitespace_chars)] == '\0')
                 {
                   const char *entry_cmdname;
 
-                  sortable_subentry->sort_string = strdup("");
-                  sortable_subentry->sort_key = strdup("");
-                  free (sort_string_key->sort_string);
-                  free (sort_string_key->sort_key);
+                  subentry_sort_string->sort_string = strdup("");
+                  free (sort_string);
 
                   entry_cmdname = element_command_name (main_entry_element);
                   if (!entry_cmdname)
@@ -404,12 +452,9 @@ setup_sortable_index_entries (ERROR_MESSAGE_LIST 
*error_messages,
                 }
               else
                 {
-                  sortable_subentry->sort_string
-                     = sort_string_key->sort_string;
-                  sortable_subentry->sort_key = sort_string_key->sort_key;
+                  subentry_sort_string->sort_string = sort_string;
                   non_empty_index_subentries++;
                 }
-              free (sort_string_key);
 
               while (1)
                 {
@@ -419,34 +464,32 @@ setup_sortable_index_entries (ERROR_MESSAGE_LIST 
*error_messages,
                     break;
 
                   subentry = next_subentry;
-                  sortable_entry->subentries_number++;
-
-                  sortable_entry->sortable_subentries
-                   = (SORTABLE_INDEX_SUBENTRY *)
-                    realloc (sortable_entry->sortable_subentries,
-                        sizeof (SORTABLE_INDEX_SUBENTRY)
-                           * sortable_entry->subentries_number);
-                  if (!sortable_entry->sortable_subentries)
+                  entry_sort_string.subentries_number++;
+
+                  entry_sort_string.sort_string_subentries
+                   = (INDEX_SUBENTRY_SORT_STRING *)
+                    realloc (entry_sort_string.sort_string_subentries,
+                        sizeof (INDEX_SUBENTRY_SORT_STRING)
+                           * entry_sort_string.subentries_number);
+                  if (!entry_sort_string.sort_string_subentries)
                     fatal ("realloc failed");
 
-                  sortable_subentry
-                   = &sortable_entry->sortable_subentries[
-                          sortable_entry->subentries_number -1];
+                  subentry_sort_string
+                   = &entry_sort_string.sort_string_subentries[
+                          entry_sort_string.subentries_number -1];
 
-                  sort_string_key
-                    = index_entry_element_sort_string_key (index_entry,
-                            subentry, convert_text_options,
-                            entry_index->in_code, *collation_locale, 0);
+                  sort_string
+                    = index_entry_element_sort_string (index_entry,
+                                     subentry, convert_text_options,
+                                     entry_index->in_code, 0);
 
-                  if (sort_string_key->sort_string[strspn
-                     (sort_string_key->sort_string, whitespace_chars)] == '\0')
+                  if (sort_string[strspn
+                     (sort_string, whitespace_chars)] == '\0')
                     {
                       const char *entry_cmdname;
 
-                      sortable_subentry->sort_string = strdup("");
-                      sortable_subentry->sort_key = strdup("");
-                      free (sort_string_key->sort_string);
-                      free (sort_string_key->sort_key);
+                      subentry_sort_string->sort_string = strdup("");
+                      free (sort_string);
 
                       entry_cmdname = element_command_name 
(main_entry_element);
                       if (!entry_cmdname)
@@ -459,43 +502,176 @@ setup_sortable_index_entries (ERROR_MESSAGE_LIST 
*error_messages,
                       message_list_command_warn (error_messages, options,
                                              main_entry_element,
                                "empty index sub entry %zu key in @%s",
-                               sortable_entry->subentries_number -1,
+                               entry_sort_string.subentries_number -1,
                                 entry_cmdname);
                     }
                   else
                     {
-                      sortable_subentry->sort_string
-                         = sort_string_key->sort_string;
-                      sortable_subentry->sort_key = sort_string_key->sort_key;
+                      subentry_sort_string->sort_string = sort_string;
                       non_empty_index_subentries++;
                     }
-                  free (sort_string_key);
                 }
               if (non_empty_index_subentries > 0)
                 {
-                  int k;
-                  for (k = 0; k < sortable_entry->subentries_number; k++)
+                  size_t k;
+                  nr++;
+
+                  for (k = 0; k < entry_sort_string.subentries_number; k++)
                     {
                       uint8_t *encoded_u8;
                       ucs4_t next_char;
                       int new_len;
 
-                      sortable_subentry
-                        = &sortable_entry->sortable_subentries[k];
+                      subentry_sort_string
+                        = &entry_sort_string.sort_string_subentries[k];
              /* TODO quite inefficient, only need the first character */
                       encoded_u8
                        = u8_strconv_from_encoding (
-                                         sortable_subentry->sort_string,
+                                         subentry_sort_string->sort_string,
                                          "UTF-8", iconveh_question_mark);
                       new_len = u8_strmbtouc (&next_char, encoded_u8);
                       if (new_len > 0
                           && uc_is_property (next_char, 
UC_PROPERTY_ALPHABETIC))
-                        sortable_subentry->alpha = 1;
+                        subentry_sort_string->alpha = 1;
                       else
-                        sortable_subentry->alpha = 0;
+                        subentry_sort_string->alpha = 0;
 
                       free (encoded_u8);
                     }
+
+                  memcpy (&index_sort_strings->sort_string_entries[nr-1],
+                          &entry_sort_string,
+                          sizeof (INDEX_ENTRY_SORT_STRING));
+                }
+              else
+                {
+                  size_t k;
+                  for (k = 0; k < entry_sort_string.subentries_number; k++)
+                    {
+                      free (entry_sort_string.sort_string_subentries[k]
+                              .sort_string);
+                    }
+                  free (entry_sort_string.sort_string_subentries);
+                }
+              index_sort_strings->entries_number = nr;
+            }
+        }
+    }
+
+  destroy_text_options (convert_text_options);
+
+  return indices_sort_strings;
+}
+
+INDEX_COLLATOR *
+setup_collator (int use_unicode_collation, const char *collation_language,
+                const char *collation_locale)
+{
+  INDEX_COLLATOR *result = (INDEX_COLLATOR *) malloc (sizeof (INDEX_COLLATOR));
+  memset (result, 0, sizeof (INDEX_COLLATOR));
+
+  if (use_unicode_collation == 0)
+    {
+      result->type = ctn_no_unicode;
+      /* FIXME check if needed */
+      result->language = strdup ("");
+    }
+  else if (collation_language)
+    {
+      result->type = ctn_language_collation;
+      result->language = strdup (collation_language);
+      result->sv = call_setup_collator (1, collation_language);
+    }
+  else
+    {
+      #ifdef HAVE_STRXFRM_L
+      #ifdef HAVE_NEWLOCALE
+      if (collation_locale)
+        {
+          result->locale
+            = newlocale (LC_COLLATE_MASK, collation_locale, 0);
+          /* TODO warn if locale is not found? */
+          if (result->locale)
+            {
+              result->type = ctn_locale_collation;
+              result->language = strdup (collation_locale);
+              return result;
+            }
+        }
+      #endif
+      #endif
+
+      result->type = ctn_unicode;
+      /* FIXME check if needed */
+      result->language = strdup ("-");
+      result->sv = call_setup_collator (1, 0);
+    }
+  return result;
+}
+
+INDICES_SORTABLE_ENTRIES *
+setup_sortable_index_entries (INDEX_COLLATOR *collator,
+                         const INDICES_SORT_STRINGS *indices_sort_strings)
+{
+  size_t i;
+
+  if (!indices_sort_strings || indices_sort_strings->number <= 0)
+    return 0;
+
+  INDICES_SORTABLE_ENTRIES *indices_sortable_entries
+    = (INDICES_SORTABLE_ENTRIES *) malloc (sizeof (INDICES_SORTABLE_ENTRIES));
+
+  indices_sortable_entries->number = indices_sort_strings->number;
+  indices_sortable_entries->indices = (INDEX_SORTABLE_ENTRIES *)
+    malloc (indices_sort_strings->number * sizeof (INDEX_SORTABLE_ENTRIES));
+  memset (indices_sortable_entries->indices, 0,
+          indices_sort_strings->number * sizeof (INDEX_SORTABLE_ENTRIES));
+
+  for (i = 0; i < indices_sort_strings->number; i++)
+    {
+      INDEX_SORT_STRINGS *index_sort_strings
+         = &indices_sort_strings->indices[i];
+      INDEX_SORTABLE_ENTRIES *sortable_index_entries
+        = &indices_sortable_entries->indices[i];
+      if (index_sort_strings->entries_number > 0)
+        {
+          size_t j;
+
+          sortable_index_entries->index = index_sort_strings->index;
+          sortable_index_entries->number = index_sort_strings->entries_number;
+          sortable_index_entries->sortable_entries = (SORTABLE_INDEX_ENTRY *)
+            malloc (index_sort_strings->entries_number
+                    * sizeof (SORTABLE_INDEX_ENTRY));
+
+          for (j = 0; j < index_sort_strings->entries_number; j++)
+            {
+              size_t k;
+              INDEX_ENTRY_SORT_STRING *index_entry_sort_string
+                = &index_sort_strings->sort_string_entries[j];
+
+              SORTABLE_INDEX_ENTRY *sortable_entry
+                = &sortable_index_entries->sortable_entries[j];
+
+              sortable_entry->entry = index_entry_sort_string->entry;
+              sortable_entry->subentries_number
+                          = index_entry_sort_string->subentries_number;
+              sortable_entry->sortable_subentries = (SORTABLE_INDEX_SUBENTRY *)
+                malloc (index_entry_sort_string->subentries_number
+                        * sizeof (SORTABLE_INDEX_SUBENTRY));
+
+              for (k = 0; k < index_entry_sort_string->subentries_number; k++)
+                {
+                  SORTABLE_INDEX_SUBENTRY *sortable_subentry
+                    = &sortable_entry->sortable_subentries[k];
+                  INDEX_SUBENTRY_SORT_STRING *subenty_sort_string
+                    = &index_entry_sort_string->sort_string_subentries[k];
+              /*    if (subenty_sort_string->sort_string) */
+                    sortable_subentry->sort_string
+                     /* FIXME or refer to subenty_sort_string structure? */
+                     = strdup (subenty_sort_string->sort_string);
+                  sortable_subentry->alpha = subenty_sort_string->alpha;
+                  sortable_subentry->sort_key = get_sort_key (collator,
+                                           subenty_sort_string->sort_string);
                 }
             }
         }
@@ -503,9 +679,44 @@ setup_sortable_index_entries (ERROR_MESSAGE_LIST 
*error_messages,
   return indices_sortable_entries;
 }
 
+
+static INDICES_SORTABLE_ENTRIES *
+setup_sort_sortable_strings_collator (
+                      ERROR_MESSAGE_LIST *error_messages,
+                      OPTIONS *options, int use_unicode_collation,
+                      const char *collation_language,
+                      const char *collation_locale,
+                      const MERGED_INDICES *merged_indices,
+                      INDEX **indices_information, DOCUMENT *document,
+                      INDEX_COLLATOR **collator)
+{
+  const INDICES_SORT_STRINGS *indices_sort_strings;
+  INDICES_SORTABLE_ENTRIES *index_sortable_index_entries;
+
+  if (document)
+    {
+      indices_sort_strings = document_indices_sort_strings (error_messages,
+                                                        options, document, 0);
+    }
+  else
+    {
+      indices_sort_strings = setup_index_entries_sort_strings (error_messages,
+                                                      options, merged_indices,
+                                                      indices_information, 0);
+    }
+
+  *collator = setup_collator (use_unicode_collation, collation_language,
+                              collation_locale);
+
+  index_sortable_index_entries = setup_sortable_index_entries (*collator,
+                                                       indices_sort_strings);
+
+  return index_sortable_index_entries;
+}
+
 typedef struct LETTER_SORTABLE_ENTRIES {
     char *letter;
-    char *letter_sort_key;
+    BYTES_STRING *letter_sort_key;
     size_t space;
     size_t number;
     SORTABLE_INDEX_ENTRY **sortable_entries;
@@ -517,13 +728,26 @@ typedef struct INDEX_LETTERS_SORTABLE_ENTRIES {
     LETTER_SORTABLE_ENTRIES *letter_entries;
 } INDEX_LETTERS_SORTABLE_ENTRIES;
 
+#define MIN_INT(a,b) (((a)<(b))?(a):(b))
+static int
+compare_byte_strings (BYTES_STRING *a, BYTES_STRING *b)
+{
+  size_t common_len = MIN_INT (a->len, b->len);
+  int res = memcmp (a->bytes, b->bytes, common_len);
+  if (res == 0)
+    return (a->len > b->len) - (a->len < b->len);
+  return res;
+}
+
+#undef MIN_INT
+
 static int
 compare_index_letter (const void *a, const void *b)
 {
   const LETTER_SORTABLE_ENTRIES *lse_a = (const LETTER_SORTABLE_ENTRIES *) a;
   const LETTER_SORTABLE_ENTRIES *lse_b = (const LETTER_SORTABLE_ENTRIES *) b;
 
-  return strcmp (lse_a->letter_sort_key, lse_b->letter_sort_key);
+  return compare_byte_strings (lse_a->letter_sort_key, lse_b->letter_sort_key);
 }
 
 static int
@@ -533,7 +757,7 @@ compare_sortable_subentry_keys (const void *a, const void 
*b)
   const SORTABLE_INDEX_SUBENTRY *sis_b = (const SORTABLE_INDEX_SUBENTRY *) b;
 
   if (sis_a->alpha == sis_b->alpha)
-    return strcmp (sis_a->sort_key, sis_b->sort_key);
+    return compare_byte_strings (sis_a->sort_key, sis_b->sort_key);
 
   return (sis_a->alpha > sis_b->alpha) - (sis_a->alpha < sis_b->alpha);
 }
@@ -581,22 +805,80 @@ compare_sortable_index_entry (const void *a, const void 
*b)
   return strcmp (sie_a->entry->index_name, sie_b->entry->index_name);
 }
 
+void
+destroy_indices_sortable_entries (
+             INDICES_SORTABLE_ENTRIES *indices_sortable_entries)
+{
+  if (indices_sortable_entries)
+    {
+      size_t i;
+      for (i = 0; i < indices_sortable_entries->number; i++)
+        {
+          INDEX_SORTABLE_ENTRIES *sortable_index_entries
+            = &indices_sortable_entries->indices[i];
+          if (sortable_index_entries->number > 0)
+            {
+              size_t j;
+
+              for (j = 0; j < sortable_index_entries->number; j++)
+                {
+                  size_t k;
+                  SORTABLE_INDEX_ENTRY *sortable_entry
+                    = &sortable_index_entries->sortable_entries[j];
+
+                  for (k = 0; k < sortable_entry->subentries_number;
+                       k++)
+                    {
+                      SORTABLE_INDEX_SUBENTRY *sortable_subentry
+                        = &sortable_entry->sortable_subentries[k];
+                      free (sortable_subentry->sort_key->bytes);
+                      free (sortable_subentry->sort_key);
+                      free (sortable_subentry->sort_string);
+                    }
+                  free (sortable_entry->sortable_subentries);
+                }
+              free (sortable_index_entries->sortable_entries);
+            }
+        }
+      free (indices_sortable_entries->indices);
+      free (indices_sortable_entries);
+    }
+}
+
+void
+destroy_collator (INDEX_COLLATOR *collator)
+{
+  if (collator)
+    free (collator->language);
+  free (collator);
+}
+
 INDEX_SORTED_BY_LETTER *
 sort_indices_by_letter (ERROR_MESSAGE_LIST *error_messages,
-                        OPTIONS *options, const MERGED_INDICES *merged_indices,
-                        INDEX **indices_information)
+                        OPTIONS *options, int use_unicode_collation,
+                        const char *collation_language,
+                        const char *collation_locale,
+                        const MERGED_INDICES *merged_indices,
+                        INDEX **indices_information, DOCUMENT *document)
 {
   size_t i;
   int index_nr = 0;
-  locale_t collation_locale = 0;
   static INDEX_LETTERS_SORTABLE_ENTRIES index_letters_sortable_entries;
+  INDEX_COLLATOR *collator;
 
   INDICES_SORTABLE_ENTRIES *indices_sortable_entries
-    = setup_sortable_index_entries (error_messages, options, merged_indices,
-                                    indices_information, &collation_locale);
+    = setup_sort_sortable_strings_collator (error_messages, options,
+                                    use_unicode_collation, collation_language,
+                                    collation_locale,
+                                    merged_indices, indices_information,
+                                    document, &collator);
 
   if (!indices_sortable_entries || indices_sortable_entries->number <= 0)
-    return 0;
+    {
+      destroy_indices_sortable_entries (indices_sortable_entries);
+      destroy_collator (collator);
+      return 0;
+    }
 
   INDEX_SORTED_BY_LETTER *sorted_index_entries
    = (INDEX_SORTED_BY_LETTER *) malloc
@@ -629,7 +911,7 @@ sort_indices_by_letter (ERROR_MESSAGE_LIST *error_messages,
           char *upper_letter_string;
           char *norm_letter_string;
           TEXT letter_text;
-          char *letter_sort_key;
+          BYTES_STRING *letter_sort_key;
           int letter_added = 0;
 
           LETTER_SORTABLE_ENTRIES *letter_sortable_entries = 0;
@@ -661,6 +943,7 @@ sort_indices_by_letter (ERROR_MESSAGE_LIST *error_messages,
           free (upper_letter_string);
           encoded_u8 = u8_strconv_from_encoding (norm_letter_string, "UTF-8",
                                                   iconveh_question_mark);
+          free (norm_letter_string);
           current_u8 = encoded_u8;
 
           text_init (&letter_text);
@@ -692,8 +975,7 @@ sort_indices_by_letter (ERROR_MESSAGE_LIST *error_messages,
             }
           free (encoded_u8);
 
-          set_sort_key (collation_locale, letter_text.text,
-                        &letter_sort_key);
+          letter_sort_key = get_sort_key (collator, letter_text.text);
 
           if (index_letters_sortable_entries.letter_number > 0)
             {
@@ -739,6 +1021,7 @@ sort_indices_by_letter (ERROR_MESSAGE_LIST *error_messages,
           else
             {
               free (letter_text.text);
+              free (letter_sort_key->bytes);
               free (letter_sort_key);
             }
 
@@ -808,6 +1091,7 @@ sort_indices_by_letter (ERROR_MESSAGE_LIST *error_messages,
                 }
 
               /* TODO should we reuse the letters instead? */
+              free (letter_sortable_entries->letter_sort_key->bytes);
               free (letter_sortable_entries->letter_sort_key);
               free (letter_sortable_entries->sortable_entries);
             }
@@ -822,6 +1106,9 @@ sort_indices_by_letter (ERROR_MESSAGE_LIST *error_messages,
     sorted_index_entries = realloc (sorted_index_entries,
                      (index_nr+1) * sizeof (INDEX_SORTED_BY_LETTER));
 
+  destroy_collator (collator);
+  destroy_indices_sortable_entries (indices_sortable_entries);
+
   return sorted_index_entries;
 }
 
diff --git a/tp/Texinfo/XS/main/manipulate_indices.h 
b/tp/Texinfo/XS/main/manipulate_indices.h
index e558a9040a..80d748c7f7 100644
--- a/tp/Texinfo/XS/main/manipulate_indices.h
+++ b/tp/Texinfo/XS/main/manipulate_indices.h
@@ -8,7 +8,7 @@
 
 typedef struct SORTABLE_INDEX_SUBENTRY {
     char *sort_string;
-    char *sort_key;
+    BYTES_STRING *sort_key;
     int alpha;
 } SORTABLE_INDEX_SUBENTRY;
 
@@ -50,11 +50,20 @@ 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);
+void destroy_index_entries_sort_strings (
+                          INDICES_SORT_STRINGS *indices_sort_strings);
+INDICES_SORT_STRINGS *setup_index_entries_sort_strings (
+                    ERROR_MESSAGE_LIST *error_messages,
+                    OPTIONS *options, const MERGED_INDICES *merged_indices,
+                    INDEX **indices_information, int prefer_reference_element);
 
 INDEX_SORTED_BY_LETTER *sort_indices_by_letter (
                         ERROR_MESSAGE_LIST *error_messages,
-                        OPTIONS *options, const MERGED_INDICES *merged_indices,
-                        INDEX **indices_information);
+                        OPTIONS *options, int use_unicode_collation,
+                        const char *collation_language,
+                        const char *collation_locale,
+                        const MERGED_INDICES *merged_indices,
+                        INDEX **indices_information, DOCUMENT *document);
 
 INDEX_ENTRY_TEXT_OR_COMMAND *index_entry_first_letter_text_or_command
                                                 (INDEX_ENTRY *index_entry);
diff --git a/tp/Texinfo/options_data.txt b/tp/Texinfo/options_data.txt
index 35098056a1..64751aac9e 100644
--- a/tp/Texinfo/options_data.txt
+++ b/tp/Texinfo/options_data.txt
@@ -223,6 +223,7 @@ DEFAULT_RULE                       converter_customization 
undef   char
 DEF_TABLE                          converter_customization undef   integer
 DO_ABOUT                           converter_customization undef   integer
 DOCTYPE                            converter_customization undef   char
+DOCUMENTLANGUAGE_COLLATION         converter_customization undef   integer
 # for LaTeX
 END_USEPACKAGE                     converter_customization undef   char
 # for ext/epub3.pm
@@ -328,6 +329,9 @@ XREF_USE_NODE_NAME_ARG             converter_customization 
undef   integer
 XS_EXTERNAL_CONVERSION             converter_customization undef   integer
 XS_EXTERNAL_FORMATTING             converter_customization undef   integer
 
+# used for development tests, not sure that it will stay in the long term
+XS_STRXFRM_COLLATION_LOCALE        converter_customization undef   char
+
 # Not strings
 LINKS_BUTTONS                      converter_other undef   buttons
 TOP_BUTTONS                        converter_other undef   buttons
diff --git a/tp/t/test_utils.pl b/tp/t/test_utils.pl
index 5d828b39ae..fb1553fc6d 100644
--- a/tp/t/test_utils.pl
+++ b/tp/t/test_utils.pl
@@ -1147,6 +1147,10 @@ sub test($$)
       }
     }
   }
+
+  Texinfo::Document::indices_sort_strings($registrar,
+                                   $main_configuration, $document);
+
   # could be in a if !$XS_structuring, but the function should not be
   # overriden already in that case
   $document = Texinfo::Document::rebuild_document($document);
@@ -1162,7 +1166,6 @@ sub test($$)
   }
 
   my ($errors, $error_nrs) = $registrar->errors();
-
   my $indices_information = $document->indices_information();
   # FIXME maybe it would be good to compare $merged_index_entries?
   my $merged_index_entries = $document->merged_indices();
@@ -1190,6 +1193,7 @@ sub test($$)
     my $indices_sort_strings
       = Texinfo::Document::indices_sort_strings($registrar,
                                    $main_configuration, $document);
+
     $index_entries_sort_strings
      = Texinfo::Indices::format_index_entries_sort_strings(
                                                      $indices_sort_strings);
@@ -1213,6 +1217,7 @@ sub test($$)
     }
   }
 
+
   # use the parser expanded formats to be similar to the main program,
   # and also to avoid having @inline* and raw output format @-commands
   # with elided contents especially parsed because they are ignored
diff --git a/tp/tests/coverage/res_parser/formatting_epub/formatting.2 
b/tp/tests/coverage/res_parser/formatting_epub/formatting.2
index 2d0c9ff589..781e7d8016 100644
--- a/tp/tests/coverage/res_parser/formatting_epub/formatting.2
+++ b/tp/tests/coverage/res_parser/formatting_epub/formatting.2
@@ -307,6 +307,7 @@ formatting.texi:88: @ref reference to nonexistent node 
`node' (possibly involvin
 formatting.texi:88: @ref reference to nonexistent node `node' (possibly 
involving @mymacro)
 formatting.texi:88: @ref reference to nonexistent node `node' (possibly 
involving @mymacro)
 formatting.texi:88: @ref reference to nonexistent node `node' (possibly 
involving @mymacro)
+formatting.texi:123: warning: empty index key in @findex
 formatting.texi:32: warning: no htmlxref.cnf entry found for `file n---ame@' 
(possibly involving @mymacro)
 formatting.texi:32: warning: no htmlxref.cnf entry found for `file name' 
(possibly involving @mymacro)
 formatting.texi:32: warning: no htmlxref.cnf entry found for `a comma, in 
file' (possibly involving @mymacro)
@@ -371,4 +372,3 @@ formatting.texi:88: warning: @image file `f--ile@.' (for 
HTML) not found, using
 texi2any: @image file `f--ile@.' can not be copied
 formatting.texi:88: warning: @image file `filejk _" %@' (for HTML) not found, 
using `filejk _" %@.jpg' (possibly involving @mymacro)
 texi2any: @image file `filejk _" %@' can not be copied
-formatting.texi:123: warning: empty index key in @findex
diff --git a/tp/tests/coverage/res_parser/formatting_html32/formatting.2 
b/tp/tests/coverage/res_parser/formatting_html32/formatting.2
index c948381bb4..c4a9decc65 100644
--- a/tp/tests/coverage/res_parser/formatting_html32/formatting.2
+++ b/tp/tests/coverage/res_parser/formatting_html32/formatting.2
@@ -307,6 +307,7 @@ formatting.texi:88: @ref reference to nonexistent node 
`node' (possibly involvin
 formatting.texi:88: @ref reference to nonexistent node `node' (possibly 
involving @mymacro)
 formatting.texi:88: @ref reference to nonexistent node `node' (possibly 
involving @mymacro)
 formatting.texi:88: @ref reference to nonexistent node `node' (possibly 
involving @mymacro)
+formatting.texi:123: warning: empty index key in @findex
 formatting.texi:32: warning: @image file `f-ile' (for HTML) not found, using 
`f-ile.jpg' (possibly involving @mymacro)
 formatting.texi:32: warning: @image file `f-ile' (for HTML) not found, using 
`f-ile.jpg' (possibly involving @mymacro)
 formatting.texi:32: warning: @image file `f--ile@.' (for HTML) not found, 
using `f--ile@..file ext e--xt}' (possibly involving @mymacro)
@@ -327,4 +328,3 @@ formatting.texi:88: warning: @image file `f-ile' (for HTML) 
not found, using `f-
 formatting.texi:88: warning: @image file `f-ile' (for HTML) not found, using 
`f-ile.jpg' (possibly involving @mymacro)
 formatting.texi:88: warning: @image file `f--ile@.' (for HTML) not found, 
using `f--ile@..file ext e--xt}' (possibly involving @mymacro)
 formatting.texi:88: warning: @image file `filejk _" %@' (for HTML) not found, 
using `filejk _" %@.jpg' (possibly involving @mymacro)
-formatting.texi:123: warning: empty index key in @findex
diff --git a/tp/tests/coverage/res_parser/formatting_html_no_split/formatting.2 
b/tp/tests/coverage/res_parser/formatting_html_no_split/formatting.2
index 082b249eb9..e84c66d60d 100644
--- a/tp/tests/coverage/res_parser/formatting_html_no_split/formatting.2
+++ b/tp/tests/coverage/res_parser/formatting_html_no_split/formatting.2
@@ -307,6 +307,7 @@ formatting.texi:88: @ref reference to nonexistent node 
`node' (possibly involvin
 formatting.texi:88: @ref reference to nonexistent node `node' (possibly 
involving @mymacro)
 formatting.texi:88: @ref reference to nonexistent node `node' (possibly 
involving @mymacro)
 formatting.texi:88: @ref reference to nonexistent node `node' (possibly 
involving @mymacro)
+formatting.texi:123: warning: empty index key in @findex
 formatting.texi:22: warning: @image file `f-ile' (for HTML) not found, using 
`f-ile.jpg' (possibly involving @mymacro)
 formatting.texi:22: warning: @image file `f-ile' (for HTML) not found, using 
`f-ile.jpg' (possibly involving @mymacro)
 formatting.texi:22: warning: @image file `f--ile@.' (for HTML) not found, 
using `f--ile@..file ext e--xt}' (possibly involving @mymacro)
@@ -319,4 +320,3 @@ formatting.texi:88: warning: @image file `f-ile' (for HTML) 
not found, using `f-
 formatting.texi:88: warning: @image file `f-ile' (for HTML) not found, using 
`f-ile.jpg' (possibly involving @mymacro)
 formatting.texi:88: warning: @image file `f--ile@.' (for HTML) not found, 
using `f--ile@..file ext e--xt}' (possibly involving @mymacro)
 formatting.texi:88: warning: @image file `filejk _" %@' (for HTML) not found, 
using `filejk _" %@.jpg' (possibly involving @mymacro)
-formatting.texi:123: warning: empty index key in @findex
diff --git a/tp/tests/coverage/res_parser/formatting_info/formatting.2 
b/tp/tests/coverage/res_parser/formatting_info/formatting.2
index e8ca7e49e9..5047e36266 100644
--- a/tp/tests/coverage/res_parser/formatting_info/formatting.2
+++ b/tp/tests/coverage/res_parser/formatting_info/formatting.2
@@ -307,6 +307,7 @@ formatting.texi:88: @ref reference to nonexistent node 
`node' (possibly involvin
 formatting.texi:88: @ref reference to nonexistent node `node' (possibly 
involving @mymacro)
 formatting.texi:88: @ref reference to nonexistent node `node' (possibly 
involving @mymacro)
 formatting.texi:88: @ref reference to nonexistent node `node' (possibly 
involving @mymacro)
+formatting.texi:123: warning: empty index key in @findex
 formatting.texi:22: warning: @ref node name should not contain `,' (possibly 
involving @mymacro)
 formatting.texi:22: warning: @inforef node name should not contain `,' 
(possibly involving @mymacro)
 formatting.texi:22: warning: @ref cross-reference name should not contain `:' 
(possibly involving @mymacro)
@@ -323,5 +324,4 @@ formatting.texi:88: warning: @ref node name should not 
contain `,' (possibly inv
 formatting.texi:88: warning: @inforef node name should not contain `,' 
(possibly involving @mymacro)
 formatting.texi:88: warning: @ref cross-reference name should not contain `:' 
(possibly involving @mymacro)
 formatting.texi:88: warning: @ref cross-reference name should not contain `:' 
(possibly involving @mymacro)
-formatting.texi:123: warning: empty index key in @findex
 formatting.texi:194: warning: @node name should not contain `,': s--ect,ion
diff --git a/tp/tests/coverage/res_parser/formatting_plaintext/formatting.2 
b/tp/tests/coverage/res_parser/formatting_plaintext/formatting.2
index 9db7ff0fc3..57582a5f16 100644
--- a/tp/tests/coverage/res_parser/formatting_plaintext/formatting.2
+++ b/tp/tests/coverage/res_parser/formatting_plaintext/formatting.2
@@ -307,6 +307,7 @@ formatting.texi:88: @ref reference to nonexistent node 
`node' (possibly involvin
 formatting.texi:88: @ref reference to nonexistent node `node' (possibly 
involving @mymacro)
 formatting.texi:88: @ref reference to nonexistent node `node' (possibly 
involving @mymacro)
 formatting.texi:88: @ref reference to nonexistent node `node' (possibly 
involving @mymacro)
+formatting.texi:123: warning: empty index key in @findex
 formatting.texi:22: warning: @ref node name should not contain `,' (possibly 
involving @mymacro)
 formatting.texi:22: warning: @inforef node name should not contain `,' 
(possibly involving @mymacro)
 formatting.texi:22: warning: @ref cross-reference name should not contain `:' 
(possibly involving @mymacro)
@@ -319,4 +320,3 @@ formatting.texi:88: warning: @ref node name should not 
contain `,' (possibly inv
 formatting.texi:88: warning: @inforef node name should not contain `,' 
(possibly involving @mymacro)
 formatting.texi:88: warning: @ref cross-reference name should not contain `:' 
(possibly involving @mymacro)
 formatting.texi:88: warning: @ref cross-reference name should not contain `:' 
(possibly involving @mymacro)
-formatting.texi:123: warning: empty index key in @findex
diff --git a/tp/tests/coverage/res_parser/formatting_xhtml/formatting.2 
b/tp/tests/coverage/res_parser/formatting_xhtml/formatting.2
index c948381bb4..c4a9decc65 100644
--- a/tp/tests/coverage/res_parser/formatting_xhtml/formatting.2
+++ b/tp/tests/coverage/res_parser/formatting_xhtml/formatting.2
@@ -307,6 +307,7 @@ formatting.texi:88: @ref reference to nonexistent node 
`node' (possibly involvin
 formatting.texi:88: @ref reference to nonexistent node `node' (possibly 
involving @mymacro)
 formatting.texi:88: @ref reference to nonexistent node `node' (possibly 
involving @mymacro)
 formatting.texi:88: @ref reference to nonexistent node `node' (possibly 
involving @mymacro)
+formatting.texi:123: warning: empty index key in @findex
 formatting.texi:32: warning: @image file `f-ile' (for HTML) not found, using 
`f-ile.jpg' (possibly involving @mymacro)
 formatting.texi:32: warning: @image file `f-ile' (for HTML) not found, using 
`f-ile.jpg' (possibly involving @mymacro)
 formatting.texi:32: warning: @image file `f--ile@.' (for HTML) not found, 
using `f--ile@..file ext e--xt}' (possibly involving @mymacro)
@@ -327,4 +328,3 @@ formatting.texi:88: warning: @image file `f-ile' (for HTML) 
not found, using `f-
 formatting.texi:88: warning: @image file `f-ile' (for HTML) not found, using 
`f-ile.jpg' (possibly involving @mymacro)
 formatting.texi:88: warning: @image file `f--ile@.' (for HTML) not found, 
using `f--ile@..file ext e--xt}' (possibly involving @mymacro)
 formatting.texi:88: warning: @image file `filejk _" %@' (for HTML) not found, 
using `filejk _" %@.jpg' (possibly involving @mymacro)
-formatting.texi:123: warning: empty index key in @findex
diff --git a/tp/tests/layout/res_parser/formatting_enable_encoding/formatting.2 
b/tp/tests/layout/res_parser/formatting_enable_encoding/formatting.2
index c948381bb4..c4a9decc65 100644
--- a/tp/tests/layout/res_parser/formatting_enable_encoding/formatting.2
+++ b/tp/tests/layout/res_parser/formatting_enable_encoding/formatting.2
@@ -307,6 +307,7 @@ formatting.texi:88: @ref reference to nonexistent node 
`node' (possibly involvin
 formatting.texi:88: @ref reference to nonexistent node `node' (possibly 
involving @mymacro)
 formatting.texi:88: @ref reference to nonexistent node `node' (possibly 
involving @mymacro)
 formatting.texi:88: @ref reference to nonexistent node `node' (possibly 
involving @mymacro)
+formatting.texi:123: warning: empty index key in @findex
 formatting.texi:32: warning: @image file `f-ile' (for HTML) not found, using 
`f-ile.jpg' (possibly involving @mymacro)
 formatting.texi:32: warning: @image file `f-ile' (for HTML) not found, using 
`f-ile.jpg' (possibly involving @mymacro)
 formatting.texi:32: warning: @image file `f--ile@.' (for HTML) not found, 
using `f--ile@..file ext e--xt}' (possibly involving @mymacro)
@@ -327,4 +328,3 @@ formatting.texi:88: warning: @image file `f-ile' (for HTML) 
not found, using `f-
 formatting.texi:88: warning: @image file `f-ile' (for HTML) not found, using 
`f-ile.jpg' (possibly involving @mymacro)
 formatting.texi:88: warning: @image file `f--ile@.' (for HTML) not found, 
using `f--ile@..file ext e--xt}' (possibly involving @mymacro)
 formatting.texi:88: warning: @image file `filejk _" %@' (for HTML) not found, 
using `filejk _" %@.jpg' (possibly involving @mymacro)
-formatting.texi:123: warning: empty index key in @findex
diff --git a/tp/tests/layout/res_parser/formatting_epub_nodes/formatting.2 
b/tp/tests/layout/res_parser/formatting_epub_nodes/formatting.2
index 2d0c9ff589..781e7d8016 100644
--- a/tp/tests/layout/res_parser/formatting_epub_nodes/formatting.2
+++ b/tp/tests/layout/res_parser/formatting_epub_nodes/formatting.2
@@ -307,6 +307,7 @@ formatting.texi:88: @ref reference to nonexistent node 
`node' (possibly involvin
 formatting.texi:88: @ref reference to nonexistent node `node' (possibly 
involving @mymacro)
 formatting.texi:88: @ref reference to nonexistent node `node' (possibly 
involving @mymacro)
 formatting.texi:88: @ref reference to nonexistent node `node' (possibly 
involving @mymacro)
+formatting.texi:123: warning: empty index key in @findex
 formatting.texi:32: warning: no htmlxref.cnf entry found for `file n---ame@' 
(possibly involving @mymacro)
 formatting.texi:32: warning: no htmlxref.cnf entry found for `file name' 
(possibly involving @mymacro)
 formatting.texi:32: warning: no htmlxref.cnf entry found for `a comma, in 
file' (possibly involving @mymacro)
@@ -371,4 +372,3 @@ formatting.texi:88: warning: @image file `f--ile@.' (for 
HTML) not found, using
 texi2any: @image file `f--ile@.' can not be copied
 formatting.texi:88: warning: @image file `filejk _" %@' (for HTML) not found, 
using `filejk _" %@.jpg' (possibly involving @mymacro)
 texi2any: @image file `filejk _" %@' can not be copied
-formatting.texi:123: warning: empty index key in @findex
diff --git a/tp/tests/layout/res_parser/formatting_exotic/formatting.2 
b/tp/tests/layout/res_parser/formatting_exotic/formatting.2
index 082b249eb9..e84c66d60d 100644
--- a/tp/tests/layout/res_parser/formatting_exotic/formatting.2
+++ b/tp/tests/layout/res_parser/formatting_exotic/formatting.2
@@ -307,6 +307,7 @@ formatting.texi:88: @ref reference to nonexistent node 
`node' (possibly involvin
 formatting.texi:88: @ref reference to nonexistent node `node' (possibly 
involving @mymacro)
 formatting.texi:88: @ref reference to nonexistent node `node' (possibly 
involving @mymacro)
 formatting.texi:88: @ref reference to nonexistent node `node' (possibly 
involving @mymacro)
+formatting.texi:123: warning: empty index key in @findex
 formatting.texi:22: warning: @image file `f-ile' (for HTML) not found, using 
`f-ile.jpg' (possibly involving @mymacro)
 formatting.texi:22: warning: @image file `f-ile' (for HTML) not found, using 
`f-ile.jpg' (possibly involving @mymacro)
 formatting.texi:22: warning: @image file `f--ile@.' (for HTML) not found, 
using `f--ile@..file ext e--xt}' (possibly involving @mymacro)
@@ -319,4 +320,3 @@ formatting.texi:88: warning: @image file `f-ile' (for HTML) 
not found, using `f-
 formatting.texi:88: warning: @image file `f-ile' (for HTML) not found, using 
`f-ile.jpg' (possibly involving @mymacro)
 formatting.texi:88: warning: @image file `f--ile@.' (for HTML) not found, 
using `f--ile@..file ext e--xt}' (possibly involving @mymacro)
 formatting.texi:88: warning: @image file `filejk _" %@' (for HTML) not found, 
using `filejk _" %@.jpg' (possibly involving @mymacro)
-formatting.texi:123: warning: empty index key in @findex
diff --git a/tp/tests/layout/res_parser/formatting_fr/formatting.2 
b/tp/tests/layout/res_parser/formatting_fr/formatting.2
index c948381bb4..c4a9decc65 100644
--- a/tp/tests/layout/res_parser/formatting_fr/formatting.2
+++ b/tp/tests/layout/res_parser/formatting_fr/formatting.2
@@ -307,6 +307,7 @@ formatting.texi:88: @ref reference to nonexistent node 
`node' (possibly involvin
 formatting.texi:88: @ref reference to nonexistent node `node' (possibly 
involving @mymacro)
 formatting.texi:88: @ref reference to nonexistent node `node' (possibly 
involving @mymacro)
 formatting.texi:88: @ref reference to nonexistent node `node' (possibly 
involving @mymacro)
+formatting.texi:123: warning: empty index key in @findex
 formatting.texi:32: warning: @image file `f-ile' (for HTML) not found, using 
`f-ile.jpg' (possibly involving @mymacro)
 formatting.texi:32: warning: @image file `f-ile' (for HTML) not found, using 
`f-ile.jpg' (possibly involving @mymacro)
 formatting.texi:32: warning: @image file `f--ile@.' (for HTML) not found, 
using `f--ile@..file ext e--xt}' (possibly involving @mymacro)
@@ -327,4 +328,3 @@ formatting.texi:88: warning: @image file `f-ile' (for HTML) 
not found, using `f-
 formatting.texi:88: warning: @image file `f-ile' (for HTML) not found, using 
`f-ile.jpg' (possibly involving @mymacro)
 formatting.texi:88: warning: @image file `f--ile@.' (for HTML) not found, 
using `f--ile@..file ext e--xt}' (possibly involving @mymacro)
 formatting.texi:88: warning: @image file `filejk _" %@' (for HTML) not found, 
using `filejk _" %@.jpg' (possibly involving @mymacro)
-formatting.texi:123: warning: empty index key in @findex
diff --git a/tp/tests/layout/res_parser/formatting_fr_icons/formatting.2 
b/tp/tests/layout/res_parser/formatting_fr_icons/formatting.2
index c948381bb4..c4a9decc65 100644
--- a/tp/tests/layout/res_parser/formatting_fr_icons/formatting.2
+++ b/tp/tests/layout/res_parser/formatting_fr_icons/formatting.2
@@ -307,6 +307,7 @@ formatting.texi:88: @ref reference to nonexistent node 
`node' (possibly involvin
 formatting.texi:88: @ref reference to nonexistent node `node' (possibly 
involving @mymacro)
 formatting.texi:88: @ref reference to nonexistent node `node' (possibly 
involving @mymacro)
 formatting.texi:88: @ref reference to nonexistent node `node' (possibly 
involving @mymacro)
+formatting.texi:123: warning: empty index key in @findex
 formatting.texi:32: warning: @image file `f-ile' (for HTML) not found, using 
`f-ile.jpg' (possibly involving @mymacro)
 formatting.texi:32: warning: @image file `f-ile' (for HTML) not found, using 
`f-ile.jpg' (possibly involving @mymacro)
 formatting.texi:32: warning: @image file `f--ile@.' (for HTML) not found, 
using `f--ile@..file ext e--xt}' (possibly involving @mymacro)
@@ -327,4 +328,3 @@ formatting.texi:88: warning: @image file `f-ile' (for HTML) 
not found, using `f-
 formatting.texi:88: warning: @image file `f-ile' (for HTML) not found, using 
`f-ile.jpg' (possibly involving @mymacro)
 formatting.texi:88: warning: @image file `f--ile@.' (for HTML) not found, 
using `f--ile@..file ext e--xt}' (possibly involving @mymacro)
 formatting.texi:88: warning: @image file `filejk _" %@' (for HTML) not found, 
using `filejk _" %@.jpg' (possibly involving @mymacro)
-formatting.texi:123: warning: empty index key in @findex
diff --git a/tp/tests/layout/res_parser/formatting_fr_info/formatting.2 
b/tp/tests/layout/res_parser/formatting_fr_info/formatting.2
index e8ca7e49e9..5047e36266 100644
--- a/tp/tests/layout/res_parser/formatting_fr_info/formatting.2
+++ b/tp/tests/layout/res_parser/formatting_fr_info/formatting.2
@@ -307,6 +307,7 @@ formatting.texi:88: @ref reference to nonexistent node 
`node' (possibly involvin
 formatting.texi:88: @ref reference to nonexistent node `node' (possibly 
involving @mymacro)
 formatting.texi:88: @ref reference to nonexistent node `node' (possibly 
involving @mymacro)
 formatting.texi:88: @ref reference to nonexistent node `node' (possibly 
involving @mymacro)
+formatting.texi:123: warning: empty index key in @findex
 formatting.texi:22: warning: @ref node name should not contain `,' (possibly 
involving @mymacro)
 formatting.texi:22: warning: @inforef node name should not contain `,' 
(possibly involving @mymacro)
 formatting.texi:22: warning: @ref cross-reference name should not contain `:' 
(possibly involving @mymacro)
@@ -323,5 +324,4 @@ formatting.texi:88: warning: @ref node name should not 
contain `,' (possibly inv
 formatting.texi:88: warning: @inforef node name should not contain `,' 
(possibly involving @mymacro)
 formatting.texi:88: warning: @ref cross-reference name should not contain `:' 
(possibly involving @mymacro)
 formatting.texi:88: warning: @ref cross-reference name should not contain `:' 
(possibly involving @mymacro)
-formatting.texi:123: warning: empty index key in @findex
 formatting.texi:194: warning: @node name should not contain `,': s--ect,ion
diff --git 
a/tp/tests/layout/res_parser/formatting_info_ascii_punctuation/formatting.2 
b/tp/tests/layout/res_parser/formatting_info_ascii_punctuation/formatting.2
index e8ca7e49e9..5047e36266 100644
--- a/tp/tests/layout/res_parser/formatting_info_ascii_punctuation/formatting.2
+++ b/tp/tests/layout/res_parser/formatting_info_ascii_punctuation/formatting.2
@@ -307,6 +307,7 @@ formatting.texi:88: @ref reference to nonexistent node 
`node' (possibly involvin
 formatting.texi:88: @ref reference to nonexistent node `node' (possibly 
involving @mymacro)
 formatting.texi:88: @ref reference to nonexistent node `node' (possibly 
involving @mymacro)
 formatting.texi:88: @ref reference to nonexistent node `node' (possibly 
involving @mymacro)
+formatting.texi:123: warning: empty index key in @findex
 formatting.texi:22: warning: @ref node name should not contain `,' (possibly 
involving @mymacro)
 formatting.texi:22: warning: @inforef node name should not contain `,' 
(possibly involving @mymacro)
 formatting.texi:22: warning: @ref cross-reference name should not contain `:' 
(possibly involving @mymacro)
@@ -323,5 +324,4 @@ formatting.texi:88: warning: @ref node name should not 
contain `,' (possibly inv
 formatting.texi:88: warning: @inforef node name should not contain `,' 
(possibly involving @mymacro)
 formatting.texi:88: warning: @ref cross-reference name should not contain `:' 
(possibly involving @mymacro)
 formatting.texi:88: warning: @ref cross-reference name should not contain `:' 
(possibly involving @mymacro)
-formatting.texi:123: warning: empty index key in @findex
 formatting.texi:194: warning: @node name should not contain `,': s--ect,ion
diff --git 
a/tp/tests/layout/res_parser/formatting_info_disable_encoding/formatting.2 
b/tp/tests/layout/res_parser/formatting_info_disable_encoding/formatting.2
index e8ca7e49e9..5047e36266 100644
--- a/tp/tests/layout/res_parser/formatting_info_disable_encoding/formatting.2
+++ b/tp/tests/layout/res_parser/formatting_info_disable_encoding/formatting.2
@@ -307,6 +307,7 @@ formatting.texi:88: @ref reference to nonexistent node 
`node' (possibly involvin
 formatting.texi:88: @ref reference to nonexistent node `node' (possibly 
involving @mymacro)
 formatting.texi:88: @ref reference to nonexistent node `node' (possibly 
involving @mymacro)
 formatting.texi:88: @ref reference to nonexistent node `node' (possibly 
involving @mymacro)
+formatting.texi:123: warning: empty index key in @findex
 formatting.texi:22: warning: @ref node name should not contain `,' (possibly 
involving @mymacro)
 formatting.texi:22: warning: @inforef node name should not contain `,' 
(possibly involving @mymacro)
 formatting.texi:22: warning: @ref cross-reference name should not contain `:' 
(possibly involving @mymacro)
@@ -323,5 +324,4 @@ formatting.texi:88: warning: @ref node name should not 
contain `,' (possibly inv
 formatting.texi:88: warning: @inforef node name should not contain `,' 
(possibly involving @mymacro)
 formatting.texi:88: warning: @ref cross-reference name should not contain `:' 
(possibly involving @mymacro)
 formatting.texi:88: warning: @ref cross-reference name should not contain `:' 
(possibly involving @mymacro)
-formatting.texi:123: warning: empty index key in @findex
 formatting.texi:194: warning: @node name should not contain `,': s--ect,ion
diff --git a/tp/tests/layout/res_parser/formatting_inline_css/formatting.2 
b/tp/tests/layout/res_parser/formatting_inline_css/formatting.2
index c948381bb4..c4a9decc65 100644
--- a/tp/tests/layout/res_parser/formatting_inline_css/formatting.2
+++ b/tp/tests/layout/res_parser/formatting_inline_css/formatting.2
@@ -307,6 +307,7 @@ formatting.texi:88: @ref reference to nonexistent node 
`node' (possibly involvin
 formatting.texi:88: @ref reference to nonexistent node `node' (possibly 
involving @mymacro)
 formatting.texi:88: @ref reference to nonexistent node `node' (possibly 
involving @mymacro)
 formatting.texi:88: @ref reference to nonexistent node `node' (possibly 
involving @mymacro)
+formatting.texi:123: warning: empty index key in @findex
 formatting.texi:32: warning: @image file `f-ile' (for HTML) not found, using 
`f-ile.jpg' (possibly involving @mymacro)
 formatting.texi:32: warning: @image file `f-ile' (for HTML) not found, using 
`f-ile.jpg' (possibly involving @mymacro)
 formatting.texi:32: warning: @image file `f--ile@.' (for HTML) not found, 
using `f--ile@..file ext e--xt}' (possibly involving @mymacro)
@@ -327,4 +328,3 @@ formatting.texi:88: warning: @image file `f-ile' (for HTML) 
not found, using `f-
 formatting.texi:88: warning: @image file `f-ile' (for HTML) not found, using 
`f-ile.jpg' (possibly involving @mymacro)
 formatting.texi:88: warning: @image file `f--ile@.' (for HTML) not found, 
using `f--ile@..file ext e--xt}' (possibly involving @mymacro)
 formatting.texi:88: warning: @image file `filejk _" %@' (for HTML) not found, 
using `filejk _" %@.jpg' (possibly involving @mymacro)
-formatting.texi:123: warning: empty index key in @findex
diff --git a/tp/tests/layout/res_parser/formatting_mathjax/formatting.2 
b/tp/tests/layout/res_parser/formatting_mathjax/formatting.2
index c948381bb4..c4a9decc65 100644
--- a/tp/tests/layout/res_parser/formatting_mathjax/formatting.2
+++ b/tp/tests/layout/res_parser/formatting_mathjax/formatting.2
@@ -307,6 +307,7 @@ formatting.texi:88: @ref reference to nonexistent node 
`node' (possibly involvin
 formatting.texi:88: @ref reference to nonexistent node `node' (possibly 
involving @mymacro)
 formatting.texi:88: @ref reference to nonexistent node `node' (possibly 
involving @mymacro)
 formatting.texi:88: @ref reference to nonexistent node `node' (possibly 
involving @mymacro)
+formatting.texi:123: warning: empty index key in @findex
 formatting.texi:32: warning: @image file `f-ile' (for HTML) not found, using 
`f-ile.jpg' (possibly involving @mymacro)
 formatting.texi:32: warning: @image file `f-ile' (for HTML) not found, using 
`f-ile.jpg' (possibly involving @mymacro)
 formatting.texi:32: warning: @image file `f--ile@.' (for HTML) not found, 
using `f--ile@..file ext e--xt}' (possibly involving @mymacro)
@@ -327,4 +328,3 @@ formatting.texi:88: warning: @image file `f-ile' (for HTML) 
not found, using `f-
 formatting.texi:88: warning: @image file `f-ile' (for HTML) not found, using 
`f-ile.jpg' (possibly involving @mymacro)
 formatting.texi:88: warning: @image file `f--ile@.' (for HTML) not found, 
using `f--ile@..file ext e--xt}' (possibly involving @mymacro)
 formatting.texi:88: warning: @image file `filejk _" %@' (for HTML) not found, 
using `filejk _" %@.jpg' (possibly involving @mymacro)
-formatting.texi:123: warning: empty index key in @findex
diff --git 
a/tp/tests/layout/res_parser/formatting_numerical_entities/formatting.2 
b/tp/tests/layout/res_parser/formatting_numerical_entities/formatting.2
index c948381bb4..c4a9decc65 100644
--- a/tp/tests/layout/res_parser/formatting_numerical_entities/formatting.2
+++ b/tp/tests/layout/res_parser/formatting_numerical_entities/formatting.2
@@ -307,6 +307,7 @@ formatting.texi:88: @ref reference to nonexistent node 
`node' (possibly involvin
 formatting.texi:88: @ref reference to nonexistent node `node' (possibly 
involving @mymacro)
 formatting.texi:88: @ref reference to nonexistent node `node' (possibly 
involving @mymacro)
 formatting.texi:88: @ref reference to nonexistent node `node' (possibly 
involving @mymacro)
+formatting.texi:123: warning: empty index key in @findex
 formatting.texi:32: warning: @image file `f-ile' (for HTML) not found, using 
`f-ile.jpg' (possibly involving @mymacro)
 formatting.texi:32: warning: @image file `f-ile' (for HTML) not found, using 
`f-ile.jpg' (possibly involving @mymacro)
 formatting.texi:32: warning: @image file `f--ile@.' (for HTML) not found, 
using `f--ile@..file ext e--xt}' (possibly involving @mymacro)
@@ -327,4 +328,3 @@ formatting.texi:88: warning: @image file `f-ile' (for HTML) 
not found, using `f-
 formatting.texi:88: warning: @image file `f-ile' (for HTML) not found, using 
`f-ile.jpg' (possibly involving @mymacro)
 formatting.texi:88: warning: @image file `f--ile@.' (for HTML) not found, 
using `f--ile@..file ext e--xt}' (possibly involving @mymacro)
 formatting.texi:88: warning: @image file `filejk _" %@' (for HTML) not found, 
using `filejk _" %@.jpg' (possibly involving @mymacro)
-formatting.texi:123: warning: empty index key in @findex
diff --git 
a/tp/tests/layout/res_parser/formatting_plaintext_ascii_punctuation/formatting.2
 
b/tp/tests/layout/res_parser/formatting_plaintext_ascii_punctuation/formatting.2
index 9db7ff0fc3..57582a5f16 100644
--- 
a/tp/tests/layout/res_parser/formatting_plaintext_ascii_punctuation/formatting.2
+++ 
b/tp/tests/layout/res_parser/formatting_plaintext_ascii_punctuation/formatting.2
@@ -307,6 +307,7 @@ formatting.texi:88: @ref reference to nonexistent node 
`node' (possibly involvin
 formatting.texi:88: @ref reference to nonexistent node `node' (possibly 
involving @mymacro)
 formatting.texi:88: @ref reference to nonexistent node `node' (possibly 
involving @mymacro)
 formatting.texi:88: @ref reference to nonexistent node `node' (possibly 
involving @mymacro)
+formatting.texi:123: warning: empty index key in @findex
 formatting.texi:22: warning: @ref node name should not contain `,' (possibly 
involving @mymacro)
 formatting.texi:22: warning: @inforef node name should not contain `,' 
(possibly involving @mymacro)
 formatting.texi:22: warning: @ref cross-reference name should not contain `:' 
(possibly involving @mymacro)
@@ -319,4 +320,3 @@ formatting.texi:88: warning: @ref node name should not 
contain `,' (possibly inv
 formatting.texi:88: warning: @inforef node name should not contain `,' 
(possibly involving @mymacro)
 formatting.texi:88: warning: @ref cross-reference name should not contain `:' 
(possibly involving @mymacro)
 formatting.texi:88: warning: @ref cross-reference name should not contain `:' 
(possibly involving @mymacro)
-formatting.texi:123: warning: empty index key in @findex
diff --git 
a/tp/tests/layout/res_parser/formatting_sort_element_counts/formatting.2 
b/tp/tests/layout/res_parser/formatting_sort_element_counts/formatting.2
index 082b249eb9..e84c66d60d 100644
--- a/tp/tests/layout/res_parser/formatting_sort_element_counts/formatting.2
+++ b/tp/tests/layout/res_parser/formatting_sort_element_counts/formatting.2
@@ -307,6 +307,7 @@ formatting.texi:88: @ref reference to nonexistent node 
`node' (possibly involvin
 formatting.texi:88: @ref reference to nonexistent node `node' (possibly 
involving @mymacro)
 formatting.texi:88: @ref reference to nonexistent node `node' (possibly 
involving @mymacro)
 formatting.texi:88: @ref reference to nonexistent node `node' (possibly 
involving @mymacro)
+formatting.texi:123: warning: empty index key in @findex
 formatting.texi:22: warning: @image file `f-ile' (for HTML) not found, using 
`f-ile.jpg' (possibly involving @mymacro)
 formatting.texi:22: warning: @image file `f-ile' (for HTML) not found, using 
`f-ile.jpg' (possibly involving @mymacro)
 formatting.texi:22: warning: @image file `f--ile@.' (for HTML) not found, 
using `f--ile@..file ext e--xt}' (possibly involving @mymacro)
@@ -319,4 +320,3 @@ formatting.texi:88: warning: @image file `f-ile' (for HTML) 
not found, using `f-
 formatting.texi:88: warning: @image file `f-ile' (for HTML) not found, using 
`f-ile.jpg' (possibly involving @mymacro)
 formatting.texi:88: warning: @image file `f--ile@.' (for HTML) not found, 
using `f--ile@..file ext e--xt}' (possibly involving @mymacro)
 formatting.texi:88: warning: @image file `filejk _" %@' (for HTML) not found, 
using `filejk _" %@.jpg' (possibly involving @mymacro)
-formatting.texi:123: warning: empty index key in @findex
diff --git a/tp/tests/layout/res_parser/formatting_texi2html/formatting.2 
b/tp/tests/layout/res_parser/formatting_texi2html/formatting.2
index c948381bb4..c4a9decc65 100644
--- a/tp/tests/layout/res_parser/formatting_texi2html/formatting.2
+++ b/tp/tests/layout/res_parser/formatting_texi2html/formatting.2
@@ -307,6 +307,7 @@ formatting.texi:88: @ref reference to nonexistent node 
`node' (possibly involvin
 formatting.texi:88: @ref reference to nonexistent node `node' (possibly 
involving @mymacro)
 formatting.texi:88: @ref reference to nonexistent node `node' (possibly 
involving @mymacro)
 formatting.texi:88: @ref reference to nonexistent node `node' (possibly 
involving @mymacro)
+formatting.texi:123: warning: empty index key in @findex
 formatting.texi:32: warning: @image file `f-ile' (for HTML) not found, using 
`f-ile.jpg' (possibly involving @mymacro)
 formatting.texi:32: warning: @image file `f-ile' (for HTML) not found, using 
`f-ile.jpg' (possibly involving @mymacro)
 formatting.texi:32: warning: @image file `f--ile@.' (for HTML) not found, 
using `f--ile@..file ext e--xt}' (possibly involving @mymacro)
@@ -327,4 +328,3 @@ formatting.texi:88: warning: @image file `f-ile' (for HTML) 
not found, using `f-
 formatting.texi:88: warning: @image file `f-ile' (for HTML) not found, using 
`f-ile.jpg' (possibly involving @mymacro)
 formatting.texi:88: warning: @image file `f--ile@.' (for HTML) not found, 
using `f--ile@..file ext e--xt}' (possibly involving @mymacro)
 formatting.texi:88: warning: @image file `filejk _" %@' (for HTML) not found, 
using `filejk _" %@.jpg' (possibly involving @mymacro)
-formatting.texi:123: warning: empty index key in @findex
diff --git a/tp/tests/layout/res_parser/formatting_texi2html_nodes/formatting.2 
b/tp/tests/layout/res_parser/formatting_texi2html_nodes/formatting.2
index c948381bb4..c4a9decc65 100644
--- a/tp/tests/layout/res_parser/formatting_texi2html_nodes/formatting.2
+++ b/tp/tests/layout/res_parser/formatting_texi2html_nodes/formatting.2
@@ -307,6 +307,7 @@ formatting.texi:88: @ref reference to nonexistent node 
`node' (possibly involvin
 formatting.texi:88: @ref reference to nonexistent node `node' (possibly 
involving @mymacro)
 formatting.texi:88: @ref reference to nonexistent node `node' (possibly 
involving @mymacro)
 formatting.texi:88: @ref reference to nonexistent node `node' (possibly 
involving @mymacro)
+formatting.texi:123: warning: empty index key in @findex
 formatting.texi:32: warning: @image file `f-ile' (for HTML) not found, using 
`f-ile.jpg' (possibly involving @mymacro)
 formatting.texi:32: warning: @image file `f-ile' (for HTML) not found, using 
`f-ile.jpg' (possibly involving @mymacro)
 formatting.texi:32: warning: @image file `f--ile@.' (for HTML) not found, 
using `f--ile@..file ext e--xt}' (possibly involving @mymacro)
@@ -327,4 +328,3 @@ formatting.texi:88: warning: @image file `f-ile' (for HTML) 
not found, using `f-
 formatting.texi:88: warning: @image file `f-ile' (for HTML) not found, using 
`f-ile.jpg' (possibly involving @mymacro)
 formatting.texi:88: warning: @image file `f--ile@.' (for HTML) not found, 
using `f--ile@..file ext e--xt}' (possibly involving @mymacro)
 formatting.texi:88: warning: @image file `filejk _" %@' (for HTML) not found, 
using `filejk _" %@.jpg' (possibly involving @mymacro)
-formatting.texi:123: warning: empty index key in @findex
diff --git a/tp/tests/layout/res_parser/formatting_weird_quotes/formatting.2 
b/tp/tests/layout/res_parser/formatting_weird_quotes/formatting.2
index c948381bb4..c4a9decc65 100644
--- a/tp/tests/layout/res_parser/formatting_weird_quotes/formatting.2
+++ b/tp/tests/layout/res_parser/formatting_weird_quotes/formatting.2
@@ -307,6 +307,7 @@ formatting.texi:88: @ref reference to nonexistent node 
`node' (possibly involvin
 formatting.texi:88: @ref reference to nonexistent node `node' (possibly 
involving @mymacro)
 formatting.texi:88: @ref reference to nonexistent node `node' (possibly 
involving @mymacro)
 formatting.texi:88: @ref reference to nonexistent node `node' (possibly 
involving @mymacro)
+formatting.texi:123: warning: empty index key in @findex
 formatting.texi:32: warning: @image file `f-ile' (for HTML) not found, using 
`f-ile.jpg' (possibly involving @mymacro)
 formatting.texi:32: warning: @image file `f-ile' (for HTML) not found, using 
`f-ile.jpg' (possibly involving @mymacro)
 formatting.texi:32: warning: @image file `f--ile@.' (for HTML) not found, 
using `f--ile@..file ext e--xt}' (possibly involving @mymacro)
@@ -327,4 +328,3 @@ formatting.texi:88: warning: @image file `f-ile' (for HTML) 
not found, using `f-
 formatting.texi:88: warning: @image file `f-ile' (for HTML) not found, using 
`f-ile.jpg' (possibly involving @mymacro)
 formatting.texi:88: warning: @image file `f--ile@.' (for HTML) not found, 
using `f--ile@..file ext e--xt}' (possibly involving @mymacro)
 formatting.texi:88: warning: @image file `filejk _" %@' (for HTML) not found, 
using `filejk _" %@.jpg' (possibly involving @mymacro)
-formatting.texi:123: warning: empty index key in @findex
diff --git a/tp/tests/tex_html/res_parser/formatting_singular/formatting.2 
b/tp/tests/tex_html/res_parser/formatting_singular/formatting.2
index 004f7d9618..3aa1d61f84 100644
--- a/tp/tests/tex_html/res_parser/formatting_singular/formatting.2
+++ b/tp/tests/tex_html/res_parser/formatting_singular/formatting.2
@@ -307,6 +307,7 @@ formatting.texi:88: @ref reference to nonexistent node 
`node' (possibly involvin
 formatting.texi:88: @ref reference to nonexistent node `node' (possibly 
involving @mymacro)
 formatting.texi:88: @ref reference to nonexistent node `node' (possibly 
involving @mymacro)
 formatting.texi:88: @ref reference to nonexistent node `node' (possibly 
involving @mymacro)
+formatting.texi:123: warning: empty index key in @findex
 texexpand 
 formatting.texi:22: warning: @image file `f-ile' (for HTML) not found, using 
`f-ile.jpg' (possibly involving @mymacro)
 formatting.texi:22: warning: @image file `f-ile' (for HTML) not found, using 
`f-ile.jpg' (possibly involving @mymacro)
@@ -320,4 +321,3 @@ formatting.texi:88: warning: @image file `f-ile' (for HTML) 
not found, using `f-
 formatting.texi:88: warning: @image file `f-ile' (for HTML) not found, using 
`f-ile.jpg' (possibly involving @mymacro)
 formatting.texi:88: warning: @image file `f--ile@.' (for HTML) not found, 
using `f--ile@..file ext e--xt}' (possibly involving @mymacro)
 formatting.texi:88: warning: @image file `filejk _" %@' (for HTML) not found, 
using `filejk _" %@.jpg' (possibly involving @mymacro)
-formatting.texi:123: warning: empty index key in @findex
diff --git a/tp/texi2any.pl b/tp/texi2any.pl
index e7aeeb452b..8577b6a008 100755
--- a/tp/texi2any.pl
+++ b/tp/texi2any.pl
@@ -617,12 +617,14 @@ my %formats_table = (
  'info' => {
              'nodes_tree' => 1,
              'floats' => 1,
+             'setup_index_entries_sort_strings' => 1,
              'module' => 'Texinfo::Convert::Info'
            },
   'plaintext' => {
              'nodes_tree' => 1,
              'floats' => 1,
              'split' => 1,
+             'setup_index_entries_sort_strings' => 1,
              'module' => 'Texinfo::Convert::Plaintext'
            },
   'html' => {
@@ -633,6 +635,7 @@ my %formats_table = (
              'move_index_entries_after_items' => 1,
              'relate_index_entries_to_table_items' => 1,
              'no_warn_non_empty_parts' => 1,
+             'setup_index_entries_sort_strings' => 1,
              'module' => 'Texinfo::Convert::HTML'
            },
   'latex' => {
@@ -657,6 +660,7 @@ my %formats_table = (
                   # is 'ixinsxml', as Texinfo tree conversion is done
                   # from within Texinfo::Convert::IXINSXML
              'nodes_tree' => 1,
+             'setup_index_entries_sort_strings' => 1,
              'module' => 'Texinfo::Convert::IXINSXML',
              'floats' => 1,
            },
@@ -1671,6 +1675,11 @@ while(@input_files) {
     Texinfo::Structuring::number_floats($document);
   }
 
+  if ($formats_table{$converted_format}->{'setup_index_entries_sort_strings'}) 
{
+    Texinfo::Document::indices_sort_strings($registrar, $main_configuration,
+                                            $document);
+  }
+
   $document = Texinfo::Document::rebuild_document($document);
 
   if ($XS_structuring) {



reply via email to

[Prev in Thread] Current Thread [Next in Thread]