locale.scm 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. ;;; GNU Guix --- Functional package management for GNU
  2. ;;; Copyright © 2018 Mathieu Othacehe <m.othacehe@gmail.com>
  3. ;;; Copyright © 2019 Ludovic Courtès <ludo@gnu.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. (define-module (gnu installer newt locale)
  20. #:use-module (gnu installer locale)
  21. #:use-module (gnu installer steps)
  22. #:use-module (gnu installer newt page)
  23. #:use-module (guix i18n)
  24. #:use-module (newt)
  25. #:use-module (srfi srfi-1)
  26. #:use-module (srfi srfi-26)
  27. #:use-module (srfi srfi-34)
  28. #:use-module (srfi srfi-35)
  29. #:use-module (ice-9 match)
  30. #:export (run-locale-page))
  31. (define (run-language-page languages language->text)
  32. (define result
  33. (run-listbox-selection-page
  34. #:title (G_ "Locale language")
  35. #:info-text (G_ "Choose the language to use for the \
  36. installation process and for the installed system.")
  37. #:info-textbox-width 70
  38. #:listbox-items languages
  39. #:listbox-item->text language->text
  40. #:sort-listbox-items? #f
  41. #:button-text (G_ "Exit")
  42. #:button-callback-procedure
  43. (lambda _
  44. (raise
  45. (condition
  46. (&installer-step-abort))))))
  47. ;; Immediately install the chosen language so that the territory page that
  48. ;; comes after (optionally) is displayed in the chosen language.
  49. (setenv "LANGUAGE" result)
  50. result)
  51. (define (run-territory-page territories territory->text)
  52. (let ((title (G_ "Locale location")))
  53. (run-listbox-selection-page
  54. #:title title
  55. #:info-text (G_ "Choose a territory for this language.")
  56. #:listbox-items territories
  57. #:listbox-item->text territory->text
  58. #:button-text (G_ "Back")
  59. #:button-callback-procedure
  60. (lambda _
  61. (raise
  62. (condition
  63. (&installer-step-abort)))))))
  64. (define (run-codeset-page codesets)
  65. (let ((title (G_ "Locale codeset")))
  66. (run-listbox-selection-page
  67. #:title title
  68. #:info-text (G_ "Choose the locale encoding.")
  69. #:listbox-items codesets
  70. #:listbox-item->text identity
  71. #:listbox-default-item "UTF-8"
  72. #:button-text (G_ "Back")
  73. #:button-callback-procedure
  74. (lambda _
  75. (raise
  76. (condition
  77. (&installer-step-abort)))))))
  78. (define (run-modifier-page modifiers modifier->text)
  79. (let ((title (G_ "Locale modifier")))
  80. (run-listbox-selection-page
  81. #:title title
  82. #:info-text (G_ "Choose your locale's modifier. The most frequent \
  83. modifier is euro. It indicates that you want to use Euro as the currency \
  84. symbol.")
  85. #:listbox-items modifiers
  86. #:listbox-item->text modifier->text
  87. #:button-text (G_ "Back")
  88. #:button-callback-procedure
  89. (lambda _
  90. (raise
  91. (condition
  92. (&installer-step-abort)))))))
  93. (define* (run-locale-page #:key
  94. supported-locales
  95. iso639-languages
  96. iso3166-territories)
  97. "Run a page asking the user to select a locale language and possibly
  98. territory, codeset and modifier. Use SUPPORTED-LOCALES as the list of glibc
  99. available locales. ISO639-LANGUAGES is an association list associating a
  100. locale code to a locale name. ISO3166-TERRITORIES is an association list
  101. associating a territory code with a territory name. The formated locale, under
  102. glibc format is returned."
  103. (define (break-on-locale-found locales)
  104. "Raise the &installer-step-break condition if LOCALES contains exactly one
  105. element."
  106. (and (= (length locales) 1)
  107. (raise
  108. (condition (&installer-step-break)))))
  109. (define (filter-locales locales result)
  110. "Filter the list of locale records LOCALES using the RESULT returned by
  111. the installer-steps defined below."
  112. (filter
  113. (lambda (locale)
  114. (and-map identity
  115. `(,(string=? (locale-language locale)
  116. (result-step result 'language))
  117. ,@(if (result-step-done? result 'territory)
  118. (list (equal? (locale-territory locale)
  119. (result-step result 'territory)))
  120. '())
  121. ,@(if (result-step-done? result 'codeset)
  122. (list (equal? (locale-codeset locale)
  123. (result-step result 'codeset)))
  124. '())
  125. ,@(if (result-step-done? result 'modifier)
  126. (list (equal? (locale-modifier locale)
  127. (result-step result 'modifier)))
  128. '()))))
  129. locales))
  130. (define (result->locale-string locales result)
  131. "Supposing that LOCALES contains exactly one locale record, turn it into a
  132. glibc locale string and return it."
  133. (match (filter-locales locales result)
  134. ((locale)
  135. (locale->locale-string locale))))
  136. (define (sort-languages languages)
  137. "Extract some languages from LANGUAGES list and place them ahead."
  138. (let* ((first-languages '("en"))
  139. (other-languages (lset-difference equal?
  140. languages
  141. first-languages)))
  142. `(,@first-languages ,@other-languages)))
  143. (define locale-steps
  144. (list
  145. (installer-step
  146. (id 'language)
  147. (compute
  148. (lambda _
  149. (run-language-page
  150. (sort-languages
  151. (delete-duplicates (map locale-language supported-locales)))
  152. (lambda (language)
  153. (let ((english (language-code->language-name iso639-languages
  154. language)))
  155. (setenv "LANGUAGE" language)
  156. (let ((native (gettext english "iso_639-3")))
  157. (unsetenv "LANGUAGE")
  158. native)))))))
  159. (installer-step
  160. (id 'territory)
  161. (compute
  162. (lambda (result _)
  163. (let ((locales (filter-locales supported-locales result)))
  164. ;; Stop the process if the language returned by the previous step
  165. ;; is matching one and only one supported locale.
  166. (break-on-locale-found locales)
  167. ;; Otherwise, ask the user to select a territory among those
  168. ;; supported by the previously selected language.
  169. (run-territory-page
  170. (delete-duplicates (map locale-territory locales))
  171. (lambda (territory)
  172. (if territory
  173. (let ((english (territory-code->territory-name
  174. iso3166-territories territory)))
  175. (gettext english "iso_3166-1"))
  176. (G_ "No location"))))))))
  177. (installer-step
  178. (id 'codeset)
  179. (compute
  180. (lambda (result _)
  181. (let ((locales (filter-locales supported-locales result)))
  182. ;; Same as above but we now have a language and a territory to
  183. ;; narrow down the search of a locale.
  184. (break-on-locale-found locales)
  185. ;; Otherwise, choose a codeset.
  186. (let ((codesets (delete-duplicates (map locale-codeset locales))))
  187. (if (member "UTF-8" codesets)
  188. "UTF-8" ;don't even ask
  189. (run-codeset-page codesets)))))))
  190. (installer-step
  191. (id 'modifier)
  192. (compute
  193. (lambda (result _)
  194. (let ((locales (filter-locales supported-locales result)))
  195. ;; Same thing with a language, a territory and a codeset this time.
  196. (break-on-locale-found locales)
  197. ;; Otherwise, ask for a modifier.
  198. (run-modifier-page
  199. (delete-duplicates (map locale-modifier locales))
  200. (lambda (modifier)
  201. (or modifier (G_ "No modifier"))))))))))
  202. ;; If run-installer-steps returns locally, it means that the user had to go
  203. ;; through all steps (language, territory, codeset and modifier) to select a
  204. ;; locale. In that case, like if we exited by raising &installer-step-break
  205. ;; condition, turn the result into a glibc locale string and return it.
  206. (result->locale-string
  207. supported-locales
  208. (run-installer-steps #:steps locale-steps)))