aboutsummaryrefslogtreecommitdiff
;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2018 Mathieu Othacehe <m.othacehe@gmail.com>
;;; Copyright © 2019 Ludovic Courtès <ludo@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 installer locale)
  #:use-module (gnu installer utils)
  #:use-module ((gnu build locale) #:select (normalize-codeset))
  #:use-module (guix records)
  #:use-module (json)
  #:use-module (srfi srfi-1)
  #:use-module (ice-9 match)
  #:use-module (ice-9 regex)
  #:export (locale-language
            locale-territory
            locale-codeset
            locale-modifier

            locale->locale-string
            supported-locales->locales

            iso639->iso639-languages
            language-code->language-name

            iso3166->iso3166-territories
            territory-code->territory-name

            locale->configuration))


;;;
;;; Locale.
;;;

;; A glibc locale string has the following format:
;; language[_territory[.codeset][@modifier]].
(define locale-regexp "^([^_@]+)(_([^\\.@]+))?(\\.([^@]+))?(@([^$]+))?$")

;; LOCALE will be better expressed in a (guix record) that in an association
;; list. However, loading large files containing records does not scale
;; well. The same thing goes for ISO639 and ISO3166 association lists used
;; later in this module.
(define (locale-language assoc)
  (assoc-ref assoc 'language))
(define (locale-territory assoc)
  (assoc-ref assoc 'territory))
(define (locale-codeset assoc)
  (assoc-ref assoc 'codeset))
(define (locale-modifier assoc)
  (assoc-ref assoc 'modifier))

(define* (locale-string->locale string #:optional codeset)
  "Return the locale association list built from the parsing of STRING and,
optionally, CODESET."
  (let ((matches (string-match locale-regexp string)))
    `((language  . ,(match:substring matches 1))
      (territory . ,(match:substring matches 3))
      (codeset   . ,(or codeset (match:substring matches 5)))
      (modifier  . ,(match:substring matches 7)))))

(define (locale->locale-string locale)
  "Reverse operation of locale-string->locale."
  (let ((language (locale-language locale))
        (territory (locale-territory locale))
        (codeset (locale-codeset locale))
        (modifier (locale-modifier locale)))
    (apply string-append
           `(,language
             ,@(if territory
                   `("_" ,territory)
                   '())
             ,@(if codeset
                   `("." ,(normalize-codeset codeset))
                   '())
             ,@(if modifier
                   `("@" ,modifier)
                   '())))))

(define (supported-locales->locales supported-locales)
  "Given SUPPORTED-LOCALES, a file produced by 'glibc-supported-locales',
return a list of locales where each locale is an alist."
  (filter-map (match-lambda
                (("C.UTF-8" . codeset) #f)
                ((locale . codeset)
                 (locale-string->locale locale codeset)))
       (call-with-input-file supported-locales read)))


;;;
;;; Language.
;;;

(define (iso639-language-alpha2 assoc)
  (assoc-ref assoc 'alpha2))

(define (iso639-language-alpha3 assoc)
  (assoc-ref assoc 'alpha3))

(define (iso639-language-name assoc)
  (assoc-ref assoc 'name))

(define (supported-locale? locales alpha2 alpha3)
  "Find a locale in LOCALES whose alpha2 field matches ALPHA-2 or alpha3 field
matches ALPHA-3. The ISO639 standard specifies that ALPHA-2 is optional. Thus,
if ALPHA-2 is #f, only consider ALPHA-3. Return #f if not matching locale was
found."
  (find (lambda (locale)
          (let ((language (locale-language locale)))
            (or (and=> alpha2
                       (lambda (code)
                         (string=? language code)))
                (string=? language alpha3))))
        locales))

(define (iso639->iso639-languages locales iso639-3 iso639-5)
  "Return a list of ISO639 association lists created from the parsing of
ISO639-3 and ISO639-5 files."
  (call-with-input-file iso639-3
    (lambda (port-iso639-3)
      (call-with-input-file iso639-5
        (lambda (port-iso639-5)
          (filter-map
           (lambda (hash)
             (let ((alpha2 (assoc-ref hash "alpha_2"))
                   (alpha3 (assoc-ref hash "alpha_3"))
                   (name   (assoc-ref hash "name")))
               (and (supported-locale? locales alpha2 alpha3)
                    `((alpha2 . ,alpha2)
                      (alpha3 . ,alpha3)
                      (name   . ,name)))))
           (append
            (vector->list
             (assoc-ref (json->scm port-iso639-3) "639-3"))
            (vector->list
             (assoc-ref (json->scm port-iso639-5) "639-5")))))))))

(define (language-code->language-name languages language-code)
  "Using LANGUAGES as a list of ISO639 association lists, return the language
name corresponding to the given LANGUAGE-CODE."
  (let ((iso639-language
         (find (lambda (language)
                 (or
                  (and=> (iso639-language-alpha2 language)
                         (lambda (alpha2)
                           (string=? alpha2 language-code)))
                  (string=? (iso639-language-alpha3 language)
                            language-code)))
               languages)))
    (iso639-language-name iso639-language)))


;;;
;;; Territory.
;;;

(define (iso3166-territory-alpha2 assoc)
  (assoc-ref assoc 'alpha2))

(define (iso3166-territory-alpha3 assoc)
  (assoc-ref assoc 'alpha3))

(define (iso3166-territory-name assoc)
  (assoc-ref assoc 'name))

(define (iso3166->iso3166-territories iso3166)
  "Return a list of ISO3166 association lists created from the parsing of
ISO3166 file."
  (call-with-input-file iso3166
    (lambda (port)
      (map (lambda (hash)
             `((alpha2 . ,(assoc-ref hash "alpha_2"))
               (alpha3 . ,(assoc-ref hash "alpha_3"))
               (name   . ,(assoc-ref hash "name"))))
           (vector->list
            (assoc-ref (json->scm port) "3166-1"))))))

(define (territory-code->territory-name territories territory-code)
  "Using TERRITORIES as a list of ISO3166 association lists return the
territory name corresponding to the given TERRITORY-CODE."
  (let ((iso3166-territory
         (find (lambda (territory)
                 (or
                  (and=> (iso3166-territory-alpha2 territory)
                         (lambda (alpha2)
                           (string=? alpha2 territory-code)))
                  (string=? (iso3166-territory-alpha3 territory)
                            territory-code)))
               territories)))
    (iso3166-territory-name iso3166-territory)))


;;;
;;; Configuration formatter.
;;;

(define (locale->configuration locale)
  "Return the configuration field for LOCALE."
  `((locale ,locale)))
packages/crypto.scm, gnu/packages/databases.scm, gnu/packages/django.scm, gnu/packages/dns.scm, gnu/packages/elixir.scm, gnu/packages/emacs-xyz.scm, gnu/packages/emacs.scm, gnu/packages/enlightenment.scm, gnu/packages/erlang.scm, gnu/packages/fonts.scm, gnu/packages/fontutils.scm, gnu/packages/forth.scm, gnu/packages/fvwm.scm, gnu/packages/games.scm, gnu/packages/gl.scm, gnu/packages/gnome.scm, gnu/packages/gnunet.scm, gnu/packages/gnupg.scm, gnu/packages/gtk.scm, gnu/packages/guile-wm.scm, gnu/packages/guile-xyz.scm, gnu/packages/haskell-apps.scm, gnu/packages/haskell-check.scm, gnu/packages/haskell-crypto.scm, gnu/packages/haskell-xyz.scm, gnu/packages/haskell.scm, gnu/packages/image-viewers.scm, gnu/packages/image.scm, gnu/packages/irc.scm, gnu/packages/language.scm, gnu/packages/libcanberra.scm, gnu/packages/linux.scm, gnu/packages/lisp-xyz.scm, gnu/packages/lisp.scm, gnu/packages/lolcode.scm, gnu/packages/lxde.scm, gnu/packages/lxqt.scm, gnu/packages/mail.scm, gnu/packages/markup.scm, gnu/packages/mate.scm, gnu/packages/maths.scm, gnu/packages/mc.scm, gnu/packages/messaging.scm, gnu/packages/music.scm, gnu/packages/ncurses.scm, gnu/packages/networking.scm, gnu/packages/nickle.scm, gnu/packages/openbox.scm, gnu/packages/pdf.scm, gnu/packages/perl-check.scm, gnu/packages/perl.scm, gnu/packages/python-compression.scm, gnu/packages/python-crypto.scm, gnu/packages/python-web.scm, gnu/packages/python-xyz.scm, gnu/packages/python.scm, gnu/packages/qt.scm, gnu/packages/ruby.scm, gnu/packages/rust.scm, gnu/packages/scheme.scm, gnu/packages/serialization.scm, gnu/packages/shells.scm, gnu/packages/ssh.scm, gnu/packages/suckless.scm, gnu/packages/tbb.scm, gnu/packages/telephony.scm, gnu/packages/text-editors.scm, gnu/packages/textutils.scm, gnu/packages/time.scm, gnu/packages/tls.scm, gnu/packages/tor.scm, gnu/packages/version-control.scm, gnu/packages/video.scm, gnu/packages/vim.scm, gnu/packages/web.scm, gnu/packages/wm.scm, gnu/packages/xdisorg.scm, gnu/packages/xfce.scm, gnu/packages/xml.scm, gnu/packages/xorg.scm, gnu/services/certbot.scm, gnu/services/desktop.scm, gnu/services/version-control.scm, gnu/services/web.scm, guix/import/hackage.scm, guix/licenses.scm: Likewise. Signed-off-by: Efraim Flashner <efraim@flashner.co.il> nikita 2020-04-23Merge branch 'master' into core-updates... Conflicts: etc/news.scm gnu/local.mk gnu/packages/bootloaders.scm gnu/packages/linphone.scm gnu/packages/linux.scm gnu/packages/tls.scm gnu/system.scm Marius Bakke 2020-04-20gnu: xfce.scm: Sort module imports....* gnu/packages/xfce.scm: Sort module imports. Signed-off-by: Danny Milosavljevic <dannym@scratchpost.org> Naga Malleswari 2020-04-19Revert "gnu: libxfce4util: Update to 4.15.0."...This reverts commit c0bff513a41a12b446565f3c0de06343acbb6e23. Danny Milosavljevic 2020-04-19Merge branch 'master' into core-updatesMarius Bakke 2020-04-16gnu: xfce4-taskmanager: Update to 1.2.3....* gnu/packages/xfce.scm (xfce4-taskmanager): Update to 1.2.3. [source]: Hard-code NAME. Tobias Geerinckx-Rice 2020-04-16gnu: xfwm4: Update to 4.14.1....* gnu/packages/xfce.scm (xfwm4): Update to 4.14.1. [source]: Hard-code NAME. Tobias Geerinckx-Rice 2020-04-16gnu: xfdesktop: Update to 4.14.2....* gnu/packages/xfce.scm (xfdesktop): Update to 4.14.2. [source]: Hard-code NAME. Tobias Geerinckx-Rice 2020-04-13Merge branch 'master' into core-updatesMarius Bakke 2020-04-12gnu: xfce4-whiskermenu-plugin: Update to 2.4.3....* gnu/packages/xfce.scm (xfce4-whiskermenu-plugin): Update to 2.4.3. Tobias Geerinckx-Rice 2020-04-12gnu: xfce4-pulseaudio-plugin: Update to 0.4.3....* gnu/packages/xfce.scm (xfce4-pulseaudio-plugin): Update to 0.4.3. [source]: Hard-code NAME. Tobias Geerinckx-Rice 2020-04-12gnu: xfce4-clipman-plugin: Update to 1.6.1....* gnu/packages/xfce.scm (xfce4-clipman-plugin): Update to 1.6.1. Tobias Geerinckx-Rice 2020-04-12gnu: xfce4-screensaver: Update to 0.1.10....* gnu/packages/xfce.scm (xfce4-screensaver): Update to 0.1.10. Tobias Geerinckx-Rice 2020-04-12gnu: xfce4-session: Update to 4.14.2....* gnu/packages/xfce.scm (xfce4-session): Update to 4.14.2. [source]: Hard-code NAME. [description]: Tweak. Tobias Geerinckx-Rice 2020-04-12gnu: garcon: Update to 0.7.0....* gnu/packages/xfce.scm (garcon): Update to 0.7.0. Tobias Geerinckx-Rice 2020-04-12gnu: exo: Update to 0.12.11....* gnu/packages/xfce.scm (exo): Update to 0.12.11. Tobias Geerinckx-Rice 2020-04-11Merge branch 'master' into core-updatesMarius Bakke 2020-04-11gnu: thunar: Update to 1.8.14....* gnu/packages/xfce.scm (thunar): Update to 1.8.14. Tobias Geerinckx-Rice 2020-04-11Merge branch 'master' into core-updatesMarius Bakke 2020-04-10gnu: xfce: Fix typo....* gnu/packages/xfce.scm (xfce)[inputs]: Re-spell ‘tumlber’. Tobias Geerinckx-Rice 2020-04-08Merge branch 'master' into core-updates... Conflicts: etc/news.scm gnu/local.mk gnu/packages/check.scm gnu/packages/cross-base.scm gnu/packages/gimp.scm gnu/packages/java.scm gnu/packages/mail.scm gnu/packages/sdl.scm gnu/packages/texinfo.scm gnu/packages/tls.scm gnu/packages/version-control.scm Marius Bakke 2020-04-07gnu: libxfce4util: Update to 4.15.0....* gnu/packages/xfce.scm (libxfce4util): Update to 4.15.0. Signed-off-by: Danny Milosavljevic <dannym@scratchpost.org> Naga Malleswari 2020-04-05gnu: xfce4-places-plugin: Make some inputs native....* gnu/packages/xfce.scm (xfce4-places-plugin)[inputs]: Move desktop-files-utils from here... [native-inputs]: ...to here. Signed-off-by: Danny Milosavljevic <dannym@scratchpost.org> Vincent Legoll 2020-04-05gnu: ristretto: Make some inputs native....* gnu/packages/xfce.scm (ristretto)[inputs]: Move desktop-files-utils from here... [native-inputs]: ...to here. Signed-off-by: Danny Milosavljevic <dannym@scratchpost.org> Vincent Legoll 2020-03-30Merge branch 'master' into core-updates... Conflicts: gnu/packages/admin.scm gnu/packages/commencement.scm gnu/packages/guile.scm gnu/packages/linux.scm gnu/packages/package-management.scm gnu/packages/pulseaudio.scm gnu/packages/web.scm Marius Bakke 2020-03-29gnu: xfce4-screensaver: Update to 0.1.9....* gnu/packages/xfce.scm (xfce4-screensaver): Update to 0.1.9. Tobias Geerinckx-Rice 2020-03-14Merge branch 'master' into core-updatesMarius Bakke