Merge branch 'master' into core-updates
[jackhill/guix/guix.git] / gnu / system / locale.scm
1 ;;; GNU Guix --- Functional package management for GNU
2 ;;; Copyright © 2014, 2015, 2016, 2017, 2019 Ludovic Courtès <ludo@gnu.org>
3 ;;; Copyright © 2018 Mark H Weaver <mhw@netris.org>
4 ;;;
5 ;;; This file is part of GNU Guix.
6 ;;;
7 ;;; GNU Guix is free software; you can redistribute it and/or modify it
8 ;;; under the terms of the GNU General Public License as published by
9 ;;; the Free Software Foundation; either version 3 of the License, or (at
10 ;;; your option) any later version.
11 ;;;
12 ;;; GNU Guix is distributed in the hope that it will be useful, but
13 ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
14 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 ;;; GNU General Public License for more details.
16 ;;;
17 ;;; You should have received a copy of the GNU General Public License
18 ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
19
20 (define-module (gnu system locale)
21 #:use-module (guix gexp)
22 #:use-module (guix store)
23 #:use-module (guix modules)
24 #:use-module (guix records)
25 #:use-module (guix packages)
26 #:use-module (guix utils)
27 #:use-module (gnu packages base)
28 #:use-module (gnu packages compression)
29 #:use-module (srfi srfi-26)
30 #:use-module (ice-9 match)
31 #:export (locale-definition
32 locale-definition?
33 locale-definition-name
34 locale-definition-source
35 locale-definition-charset
36
37 locale-name->definition
38 locale-directory
39
40 %default-locale-libcs
41 %default-locale-definitions
42
43 glibc-supported-locales))
44
45 ;;; Commentary:
46 ;;;
47 ;;; Locale definitions, and compilation thereof.
48 ;;;
49 ;;; Code:
50
51 (define-record-type* <locale-definition> locale-definition
52 make-locale-definition
53 locale-definition?
54 (name locale-definition-name) ;string--e.g., "fr_FR.utf8"
55 (source locale-definition-source) ;string--e.g., "fr_FR"
56 (charset locale-definition-charset ;string--e.g., "UTF-8"
57 (default "UTF-8")))
58
59 (define %not-dot
60 (char-set-complement (char-set #\.)))
61
62 (define (denormalize-codeset codeset)
63 "Attempt to guess the \"real\" name of CODESET, a normalized codeset as
64 defined in (info \"(libc) Using gettextized software\")."
65 (cond ((string=? codeset "utf8")
66 "UTF-8")
67 ((string-prefix? "iso8859" codeset)
68 (string-append "ISO-8859-" (string-drop codeset 7)))
69 ((string=? codeset "eucjp")
70 "EUC-JP")
71 (else ;cross fingers, hope for the best
72 codeset)))
73
74 (define (locale-name->definition name)
75 "Return a <locale-definition> corresponding to NAME, guessing the charset,
76 or #f on failure."
77 (match (string-tokenize name %not-dot)
78 ((source charset)
79 ;; XXX: NAME is supposed to use the "normalized codeset", such as "utf8",
80 ;; whereas the actual name used is different. Add a special case to make
81 ;; the right guess for UTF-8.
82 (locale-definition (name name)
83 (source source)
84 (charset (denormalize-codeset charset))))
85 (_
86 #f)))
87
88 (define* (single-locale-directory locales
89 #:key (libc glibc))
90 "Return a directory containing all of LOCALES for LIBC compiled.
91
92 Because locale data formats are incompatible when switching from one libc to
93 another, locale data is put in a sub-directory named after the 'version' field
94 of LIBC."
95 (define version
96 (version-major+minor (package-version libc)))
97
98 (define build
99 (with-imported-modules (source-module-closure
100 '((gnu build locale)))
101 #~(begin
102 (use-modules (gnu build locale))
103
104 (mkdir #$output)
105 (mkdir (string-append #$output "/" #$version))
106
107 ;; 'localedef' executes 'gzip' to access compressed locale sources.
108 (setenv "PATH"
109 (string-append #$gzip "/bin:" #$libc "/bin"))
110
111 (setvbuf (current-output-port) 'line)
112 (setvbuf (current-error-port) 'line)
113 (for-each (lambda (locale codeset name)
114 (build-locale locale
115 #:codeset codeset
116 #:name name
117 #:directory
118 (string-append #$output "/" #$version)))
119 '#$(map locale-definition-source locales)
120 '#$(map locale-definition-charset locales)
121 '#$(map locale-definition-name locales)))))
122
123 (computed-file (string-append "locale-" version) build))
124
125 (define* (locale-directory locales
126 #:key (libcs %default-locale-libcs))
127 "Return a locale directory containing all of LOCALES for each libc package
128 listed in LIBCS.
129
130 It is useful to list more than one libc when willing to support
131 already-installed packages built against a different libc since the locale
132 data format changes between libc versions."
133 (match libcs
134 ((libc)
135 (single-locale-directory locales #:libc libc))
136 ((libcs ..1)
137 (let ((dirs (map (lambda (libc)
138 (single-locale-directory locales #:libc libc))
139 libcs)))
140 (computed-file "locale-multiple-versions"
141 (with-imported-modules '((guix build union))
142 #~(begin
143 (use-modules (guix build union))
144 (union-build #$output (list #$@dirs))))
145 #:options '(#:local-build? #t
146 #:substitutable? #f))))))
147
148 (define %default-locale-libcs
149 ;; The libcs for which we build locales by default.
150 (list glibc))
151
152 (define %default-locale-definitions
153 ;; Arbitrary set of locales that are built by default. They are here mostly
154 ;; to facilitate first-time use to some people, while others may have to add
155 ;; a specific <locale-definition>.
156 (letrec-syntax ((utf8-locale (syntax-rules ()
157 ((_ name*)
158 (locale-definition
159 ;; Note: We choose "utf8", which is the
160 ;; "normalized codeset".
161 (name (string-append name* ".utf8"))
162 (source name*)
163 (charset "UTF-8")))))
164 (utf8-locales (syntax-rules ()
165 ((_ name ...)
166 (list (utf8-locale name) ...)))))
167 ;; Add "en_US.UTF-8" for compatibility with Guix 0.8.
168 (cons (locale-definition
169 (name "en_US.UTF-8")
170 (source "en_US")
171 (charset "UTF-8"))
172 (utf8-locales "ca_ES"
173 "cs_CZ"
174 "da_DK"
175 "de_DE"
176 "el_GR"
177 "en_AU"
178 "en_CA"
179 "en_GB"
180 "en_US"
181 "es_AR"
182 "es_CL"
183 "es_ES"
184 "es_MX"
185 "fi_FI"
186 "fr_BE"
187 "fr_CA"
188 "fr_CH"
189 "fr_FR"
190 "ga_IE"
191 "it_IT"
192 "ja_JP"
193 "ko_KR"
194 "nb_NO"
195 "nl_NL"
196 "pl_PL"
197 "pt_PT"
198 "ro_RO"
199 "ru_RU"
200 "sv_SE"
201 "tr_TR"
202 "uk_UA"
203 "vi_VN"
204 "zh_CN"))))
205
206 \f
207 ;;;
208 ;;; Locales supported by glibc.
209 ;;;
210
211 (define* (glibc-supported-locales #:optional (glibc glibc))
212 "Return a file-like object that contains a list of locale name/encoding
213 pairs such as (\"oc_FR.UTF-8\" . \"UTF-8\"). Each pair corresponds to a
214 locale supported by GLIBC."
215 (define build
216 (with-imported-modules (source-module-closure
217 '((guix build gnu-build-system)
218 (gnu build locale)))
219 #~(begin
220 (use-modules (guix build gnu-build-system)
221 (gnu build locale)
222 (ice-9 pretty-print))
223
224 (define unpack
225 (assq-ref %standard-phases 'unpack))
226
227
228 (setenv "PATH"
229 (string-append #+(file-append tar "/bin") ":"
230 #+(file-append xz "/bin") ":"
231 #+(file-append gzip "/bin")))
232 (unpack #:source #+(package-source glibc))
233
234 (let ((locales (call-with-input-file "localedata/SUPPORTED"
235 read-supported-locales)))
236 (call-with-output-file #$output
237 (lambda (port)
238 (pretty-print locales port)))))))
239
240 (computed-file "glibc-supported-locales.scm" build))
241
242 ;;; locale.scm ends here