aboutsummaryrefslogtreecommitdiff
;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2014-2017, 2019-2021, 2023-2024 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2018 Mark H Weaver <mhw@netris.org>
;;; Copyright © 2023 Janneke Nieuwenhuizen <jannek@gnu.org>
;;;
;;; This file is part of GNU Guix.
;;;
;;; GNU Guix is free software; you can redistribute it and/or modify it
;;; under the terms of the GNU General Public License as published by
;;; the Free Software Foundation; either version 3 of the License, or (at
;;; your option) any later version.
;;;
;;; GNU Guix is distributed in the hope that it will be useful, but
;;; WITHOUT ANY WARRANTY; without even the implied warranty of
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;;; GNU General Public License for more details.
;;;
;;; You should have received a copy of the GNU General Public License
;;; along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.

(define-module (gnu system locale)
  #:use-module (guix gexp)
  #:use-module (guix store)
  #:use-module (guix modules)
  #:use-module (guix records)
  #:use-module (guix packages)
  #:use-module (guix utils)
  #:use-module (gnu packages base)
  #:use-module (gnu packages compression)
  #:use-module (srfi srfi-26)
  #:use-module (ice-9 match)
  #:export (locale-definition
            locale-definition?
            locale-definition-name
            locale-definition-source
            locale-definition-charset

            locale-name->definition
            locale-directory

            %default-locale-libcs
            %default-locale-definitions

            glibc-supported-locales))

;;; Commentary:
;;;
;;; Locale definitions, and compilation thereof.
;;;
;;; Code:

(define-record-type* <locale-definition> locale-definition
  make-locale-definition
  locale-definition?
  (name    locale-definition-name)                ;string--e.g., "fr_FR.utf8"
  (source  locale-definition-source)              ;string--e.g., "fr_FR"
  (charset locale-definition-charset              ;string--e.g., "UTF-8"
           (default "UTF-8")))

(define %not-dot
  (char-set-complement (char-set #\.)))

(define (denormalize-codeset codeset)
  "Attempt to guess the \"real\" name of CODESET, a normalized codeset as
defined in (info \"(libc) Using gettextized software\")."
  (cond ((string=? codeset "utf8")
         "UTF-8")
        ((string-prefix? "iso8859" codeset)
         (string-append "ISO-8859-" (string-drop codeset 7)))
        ((string=? codeset "eucjp")
         "EUC-JP")
        (else                                ;cross fingers, hope for the best
         codeset)))

(define (locale-name->definition name)
  "Return a <locale-definition> corresponding to NAME, guessing the charset,
or #f on failure."
  (match (string-tokenize name %not-dot)
    ((source charset)
     ;; XXX: NAME is supposed to use the "normalized codeset", such as "utf8",
     ;; whereas the actual name used is different.  Add a special case to make
     ;; the right guess for UTF-8.
     (locale-definition (name name)
                        (source source)
                        (charset (denormalize-codeset charset))))
    (_
     #f)))

(define* (single-locale-directory locales
                                  #:key (libc glibc))
  "Return a directory containing all of LOCALES for LIBC compiled.

Because locale data formats are incompatible when switching from one libc to
another, locale data is put in a sub-directory named after the 'version' field
of LIBC."
  (define version
    (version-major+minor (package-version libc)))

  (define build
    (with-imported-modules (source-module-closure
                            '((gnu build locale)))
     #~(begin
         (use-modules (gnu build locale))

         (mkdir #$output)
         (mkdir (string-append #$output "/" #$version))

         ;; 'localedef' executes 'gzip' to access compressed locale sources.
         (setenv "PATH"
                 (string-append #+gzip "/bin:" #+libc "/bin"))

         (setvbuf (current-output-port) 'line)
         (setvbuf (current-error-port) 'line)
         (for-each (lambda (locale codeset name)
                     (build-locale locale
                                   #:codeset codeset
                                   #:name name
                                   #:directory
                                   (string-append #$output "/" #$version)))
                   '#$(map locale-definition-source locales)
                   '#$(map locale-definition-charset locales)
                   '#$(map locale-definition-name locales)))))

  (computed-file (string-append "locale-" version) build))

(define* (locale-directory locales
                           #:key (libcs %default-locale-libcs))
  "Return a locale directory containing all of LOCALES for each libc package
listed in LIBCS.

It is useful to list more than one libc when willing to support
already-installed packages built against a different libc since the locale
data format changes between libc versions."
  (match libcs
    ((libc)
     (single-locale-directory locales #:libc libc))
    ((libcs ..1)
     (let ((dirs (map (lambda (libc)
                        (single-locale-directory locales #:libc libc))
                      libcs)))
       (computed-file "locale-multiple-versions"
                      (with-imported-modules '((guix build union))
                        #~(begin
                            (use-modules (guix build union))
                            (union-build #$output (list #$@dirs))))
                      #:options '(#:local-build? #t
                                  #:substitutable? #f))))))

(define %default-locale-libcs
  ;; The libcs for which we build locales by default.
  (list glibc glibc-2.35))

(define %default-locale-definitions
  ;; Arbitrary set of locales that are built by default.  They come as a
  ;; "bonus" in addition to that specified in the 'locale' field of the
  ;; operating system, for the user's convenience, so they shouldn't take too
  ;; much space.
  (letrec-syntax ((utf8-locale (syntax-rules ()
                                 ((_ name*)
                                  (locale-definition
                                   ;; Note: We choose "utf8", which is the
                                   ;; "normalized codeset".
                                   (name (string-append name* ".utf8"))
                                   (source name*)
                                   (charset "UTF-8")))))
                  (utf8-locales (syntax-rules ()
                                  ((_ name ...)
                                   (list (utf8-locale name) ...)))))
    ;; The six UN official languages plus Portuguese, with at most two
    ;; variants per language.
    (utf8-locales "ar_DZ"
                  "en_GB"
                  "en_US"
                  "es_AR"
                  "es_ES"
                  "fr_FR"
                  "pt_BR"
                  "pt_PT"
                  "ru_RU"
                  "zh_CN")))


;;;
;;; Locales supported by glibc.
;;;

(define* (glibc-supported-locales #:optional (glibc glibc))
  "Return a file-like object that contains a list of locale name/encoding
pairs such as (\"oc_FR.UTF-8\" . \"UTF-8\").  Each pair corresponds to a
locale supported by GLIBC."
  (define build
    (with-imported-modules (source-module-closure
                            '((guix build gnu-build-system)
                              (gnu build locale)))
      #~(begin
          (use-modules (guix build gnu-build-system)
                       (gnu build locale)
                       (ice-9 pretty-print))

          (define unpack
            (assq-ref %standard-phases 'unpack))


          (setenv "PATH"
                  (string-append #+(file-append tar "/bin") ":"
                                 #+(file-append xz "/bin") ":"
                                 #+(file-append gzip "/bin")))
          (unpack #:source #+(package-source glibc))

          (let ((locales (call-with-input-file "localedata/SUPPORTED"
                           read-supported-locales)))
            (call-with-output-file #$output
              (lambda (port)
                (pretty-print locales port)))))))

  (computed-file "glibc-supported-locales.scm" build))

;;; locale.scm ends here
ode'>-rw-r--r--aspell.scm12696logplainabout -rw-r--r--assembly.scm5073logplainabout -rw-r--r--astronomy.scm6787logplainabout -rw-r--r--attr.scm3169logplainabout -rw-r--r--audio.scm132528logplainabout -rw-r--r--augeas.scm3080logplainabout -rw-r--r--autogen.scm2737logplainabout -rw-r--r--autotools.scm18617logplainabout d---------aux-files116logplain -rw-r--r--avahi.scm4243logplainabout -rw-r--r--avr.scm7071logplainabout -rw-r--r--axoloti.scm16276logplainabout -rw-r--r--backup.scm34941logplainabout -rw-r--r--base.scm55919logplainabout -rw-r--r--bash.scm15665logplainabout -rw-r--r--bdw-gc.scm4712logplainabout -rw-r--r--benchmark.scm7333logplainabout -rw-r--r--bioconductor.scm14682logplainabout -rw-r--r--bioinformatics.scm537761logplainabout -rw-r--r--bison.scm2398logplainabout -rw-r--r--bittorrent.scm18341logplainabout -rw-r--r--boost.scm6976logplainabout -rw-r--r--bootloaders.scm31694logplainabout -rw-r--r--bootstrap.scm25179logplainabout d---------bootstrap195logplain -rw-r--r--build-tools.scm8883logplainabout -rw-r--r--busybox.scm4131logplainabout -rw-r--r--c.scm7097logplainabout -rw-r--r--calcurse.scm2976logplainabout -rw-r--r--calendar.scm8405logplainabout -rw-r--r--ccache.scm2845logplainabout -rw-r--r--cdrom.scm30000logplainabout -rw-r--r--certs.scm8921logplainabout -rw-r--r--check.scm77825logplainabout -rw-r--r--chemistry.scm4978logplainabout -rw-r--r--chez.scm26143logplainabout -rw-r--r--ci.scm13265logplainabout -rw-r--r--cinnamon.scm3376logplainabout -rw-r--r--cmake.scm7501logplainabout -rw-r--r--cobol.scm3003logplainabout -rw-r--r--code.scm28734logplainabout -rw-r--r--commencement.scm45816logplainabout -rw-r--r--compression.scm92665logplainabout -rw-r--r--compton.scm4097logplainabout -rw-r--r--conkeror.scm3730logplainabout -rw-r--r--conky.scm3210logplainabout -rw-r--r--connman.scm6893logplainabout -rw-r--r--cook.scm3594logplainabout -rw-r--r--cpio.scm2038logplainabout -rw-r--r--cpp.scm10810logplainabout -rw-r--r--cppi.scm1775logplainabout -rw-r--r--cran.scm147678logplainabout -rw-r--r--cross-base.scm21515logplainabout -rw-r--r--crypto.scm31490logplainabout -rw-r--r--cryptsetup.scm5257logplainabout -rw-r--r--cups.scm29574logplainabout -rw-r--r--curl.scm10841logplainabout -rw-r--r--cyrus-sasl.scm3023logplainabout -rw-r--r--databases.scm113113logplainabout -rw-r--r--datamash.scm2011logplainabout -rw-r--r--datastructures.scm7607logplainabout -rw-r--r--dav.scm4611logplainabout -rw-r--r--dc.scm2236logplainabout -rw-r--r--debian.scm7428logplainabout -rw-r--r--debug.scm15979logplainabout -rw-r--r--dejagnu.scm3510logplainabout -rw-r--r--dico.scm3264logplainabout -rw-r--r--dictionaries.scm11916logplainabout -rw-r--r--digest.scm2285logplainabout -rw-r--r--direct-connect.scm2606logplainabout -rw-r--r--disk.scm21454logplainabout -rw-r--r--display-managers.scm15015logplainabout -rw-r--r--django.scm31764logplainabout -rw-r--r--djvu.scm2064logplainabout -rw-r--r--dns.scm22628logplainabout -rw-r--r--docbook.scm11743logplainabout -rw-r--r--docker.scm3912logplainabout -rw-r--r--documentation.scm10592logplainabout -rw-r--r--dunst.scm3135logplainabout -rw-r--r--dvtm.scm2311logplainabout -rw-r--r--ebook.scm11872logplainabout -rw-r--r--ed.scm2374logplainabout -rw-r--r--education.scm12661logplainabout -rw-r--r--electronics.scm9922logplainabout -rw-r--r--elf.scm6531logplainabout -rw-r--r--elixir.scm5280logplainabout -rw-r--r--emacs.scm434954logplainabout -rw-r--r--embedded.scm47153logplainabout -rw-r--r--emulators.scm54729logplainabout -rw-r--r--enchant.scm2381logplainabout -rw-r--r--engineering.scm73150logplainabout -rw-r--r--enlightenment.scm16760logplainabout -rw-r--r--entr.scm2854logplainabout -rw-r--r--erlang.scm8501logplainabout -rw-r--r--fabric-management.scm6860logplainabout -rw-r--r--fcitx.scm4722logplainabout -rw-r--r--figlet.scm1797logplainabout -rw-r--r--file-systems.scm9583logplainabout -rw-r--r--file.scm2056logplainabout -rw-r--r--finance.scm29085logplainabout -rw-r--r--firmware.scm18863logplainabout -rw-r--r--flashing-tools.scm18628logplainabout -rw-r--r--flex.scm4199logplainabout -rw-r--r--fltk.scm5854logplainabout -rw-r--r--fonts.scm53215logplainabout -rw-r--r--fontutils.scm27201logplainabout -rw-r--r--forth.scm2434logplainabout -rw-r--r--fpga.scm13864logplainabout -rw-r--r--freedesktop.scm51069logplainabout -rw-r--r--freeipmi.scm2013logplainabout -rw-r--r--fribidi.scm2002logplainabout -rw-r--r--ftp.scm9452logplainabout -rw-r--r--fvwm.scm3296logplainabout -rw-r--r--game-development.scm48914logplainabout -rw-r--r--games.scm216075logplainabout -rw-r--r--gawk.scm3785logplainabout -rw-r--r--gcal.scm1980logplainabout -rw-r--r--gcc.scm42271logplainabout -rw-r--r--gd.scm6286logplainabout -rw-r--r--gdb.scm4600logplainabout -rw-r--r--geo.scm29849logplainabout -rw-r--r--gettext.scm9414logplainabout -rw-r--r--ghostscript.scm14779logplainabout -rw-r--r--gimp.scm12497logplainabout -rw-r--r--gkrellm.scm2451logplainabout -rw-r--r--gl.scm31509logplainabout -rw-r--r--glib.scm35508logplainabout -rw-r--r--gnome.scm286377logplainabout -rw-r--r--gnu-doc.scm4109logplainabout -rw-r--r--gnu-pw-mgr.scm2096logplainabout -rw-r--r--gnucash.scm11098logplainabout -rw-r--r--gnunet.scm14716logplainabout -rw-r--r--gnupg.scm40276logplainabout -rw-r--r--gnustep.scm12237logplainabout -rw-r--r--gnuzilla.scm40138logplainabout -rw-r--r--gobby.scm7921logplainabout -rw-r--r--golang.scm70559logplainabout -rw-r--r--gperf.scm2354logplainabout -rw-r--r--gprolog.scm2537logplainabout -rw-r--r--gps.scm8992logplainabout -rw-r--r--graph.scm8446logplainabout -rw-r--r--graphics.scm31593logplainabout -rw-r--r--graphviz.scm10568logplainabout -rw-r--r--groff.scm6571logplainabout -rw-r--r--groovy.scm47128logplainabout -rw-r--r--gsasl.scm4580logplainabout -rw-r--r--gstreamer.scm18299logplainabout -rw-r--r--gtk.scm65340logplainabout -rw-r--r--guile-wm.scm6927logplainabout -rw-r--r--guile.scm99531logplainabout -rw-r--r--gv.scm3247logplainabout -rw-r--r--gxmessage.scm2352logplainabout -rw-r--r--ham-radio.scm2063logplainabout -rw-r--r--haskell-check.scm30571logplainabout -rw-r--r--haskell-crypto.scm26089logplainabout -rw-r--r--haskell-web.scm44269logplainabout -rw-r--r--haskell.scm362961logplainabout -rw-r--r--hexedit.scm2920logplainabout -rw-r--r--hugs.scm3688logplainabout -rw-r--r--hurd.scm10722logplainabout -rw-r--r--ibus.scm10551logplainabout -rw-r--r--icu4c.scm3691logplainabout -rw-r--r--idris.scm12660logplainabout -rw-r--r--idutils.scm2089logplainabout -rw-r--r--image-processing.scm16852logplainabout -rw-r--r--image-viewers.scm17315logplainabout -rw-r--r--image.scm57379logplainabout -rw-r--r--imagemagick.scm9347logplainabout -rw-r--r--inklingreader.scm2239logplainabout -rw-r--r--inkscape.scm3468logplainabout -rw-r--r--irc.scm17924logplainabout -rw-r--r--iso-codes.scm4097logplainabout -rw-r--r--java.scm436351logplainabout -rw-r--r--javascript.scm19045logplainabout -rw-r--r--jemalloc.scm3293logplainabout -rw-r--r--jrnl.scm2353logplainabout -rw-r--r--julia.scm16912logplainabout -rw-r--r--kde-frameworks.scm140257logplainabout -rw-r--r--kde.scm19917logplainabout -rw-r--r--kerberos.scm7928logplainabout -rw-r--r--key-mon.scm2079logplainabout -rw-r--r--kodi.scm19552logplainabout -rw-r--r--language.scm16392logplainabout -rw-r--r--ld-wrapper.in11660logplainabout