mirror of
https://github.com/clearlinux/clr-installer.git
synced 2026-08-21 15:17:54 +00:00
59302346d6
Signed-off-by: Mark D Horn <mark.d.horn@intel.com>
243 lines
5.5 KiB
Go
243 lines
5.5 KiB
Go
// Copyright © 2020 Intel Corporation
|
|
//
|
|
// SPDX-License-Identifier: GPL-3.0-only
|
|
|
|
package language
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"sort"
|
|
"strings"
|
|
|
|
"github.com/clearlinux/clr-installer/cmd"
|
|
"github.com/clearlinux/clr-installer/log"
|
|
|
|
"golang.org/x/text/language"
|
|
"golang.org/x/text/language/display"
|
|
)
|
|
|
|
// Language represents a system language, containing the locale code and lang tag representation
|
|
type Language struct {
|
|
Code string
|
|
Tag language.Tag
|
|
userDefined bool
|
|
}
|
|
|
|
const (
|
|
// DefaultLanguage is the default language string
|
|
DefaultLanguage = "en_US.UTF-8"
|
|
|
|
// RequiredBundle the bundle needed to set language other than the default
|
|
RequiredBundle = "glibc-locale"
|
|
)
|
|
|
|
// validLanguages stores the list of localized languages
|
|
var localizedLanguages = map[string]bool{ // TODO: Remove this when localization is applied for all languages
|
|
"en_US.UTF-8": false,
|
|
"zh_CN.UTF-8": false,
|
|
"es_MX.UTF-8": false,
|
|
}
|
|
|
|
// validLanguages stores the list of all valid, known languages
|
|
var validLanguages []*Language
|
|
|
|
// displayLanguage is The default language to display all language value
|
|
var displayLanguage *display.Dictionary
|
|
|
|
func init() {
|
|
displayLanguage = display.English
|
|
}
|
|
|
|
// SetSelectionLanguage changes the default display language
|
|
func SetSelectionLanguage(code string) {
|
|
// The language package can show the language choices
|
|
// in different languages, but it generic per language
|
|
// aka no country specific values
|
|
parts := strings.Split(code, "_")
|
|
shortCode := strings.ToLower(parts[0])
|
|
switch shortCode {
|
|
case "de":
|
|
displayLanguage = display.German
|
|
case "en":
|
|
displayLanguage = display.English
|
|
case "es":
|
|
displayLanguage = display.Spanish
|
|
case "fr":
|
|
displayLanguage = display.French
|
|
case "ja":
|
|
displayLanguage = display.Japanese
|
|
case "pt":
|
|
displayLanguage = display.Portuguese
|
|
case "zh":
|
|
displayLanguage = display.Chinese
|
|
default:
|
|
displayLanguage = display.English
|
|
}
|
|
}
|
|
|
|
// IsUserDefined returns true if the configuration was interactively
|
|
// defined by the user
|
|
func (l *Language) IsUserDefined() bool {
|
|
return l.userDefined
|
|
}
|
|
|
|
// GetConfValues converts a Language to display string which can
|
|
// be displayed as the configured value
|
|
func (l *Language) GetConfValues() (string, string) {
|
|
saveDefault := displayLanguage
|
|
SetSelectionLanguage(l.Code)
|
|
|
|
en := displayLanguage.Tags()
|
|
name := en.Name(l.Tag)
|
|
|
|
displayLanguage = saveDefault
|
|
|
|
return name, l.Code
|
|
}
|
|
|
|
// MarshalYAML marshals Language into YAML format
|
|
func (l *Language) MarshalYAML() (interface{}, error) {
|
|
return l.Code, nil
|
|
}
|
|
|
|
// UnmarshalYAML unmarshals Language from YAML format
|
|
func (l *Language) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
|
var code string
|
|
|
|
if err := unmarshal(&code); err != nil {
|
|
return err
|
|
}
|
|
|
|
l.Code = code
|
|
l.userDefined = false
|
|
if tag, err := language.Parse(code); err != nil {
|
|
l.Tag = tag
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Equals compares tow Language instances
|
|
func (l *Language) Equals(comp *Language) bool {
|
|
if comp == nil {
|
|
return false
|
|
}
|
|
|
|
return l.Code == comp.Code
|
|
}
|
|
|
|
func getLangName(tagName string) *Language {
|
|
langDict := displayLanguage.Languages()
|
|
var lang *Language
|
|
|
|
if tag, err := language.Parse(tagName); err != nil {
|
|
saveTag := tag
|
|
|
|
simple := strings.Replace(tagName, ".UTF-8", "", -1)
|
|
// In case the MustParse fails, recover and fallback
|
|
defer func() {
|
|
if r := recover(); r != nil {
|
|
tag = saveTag
|
|
}
|
|
}()
|
|
tag = language.MustParse(simple)
|
|
|
|
langName := langDict.Name(tag)
|
|
tagString := tag.String()
|
|
|
|
if tagString != "" && tagString != "und" && langName != "" {
|
|
lang = &Language{
|
|
Code: tagName,
|
|
Tag: tag,
|
|
}
|
|
} else {
|
|
log.Debug("Unable to use language locale '%s'", tagName)
|
|
}
|
|
} else {
|
|
log.Debug("Unable to parse language locale '%s'", tagName)
|
|
}
|
|
|
|
return lang
|
|
}
|
|
|
|
// Load uses localectl to load the currently available locales/Languages
|
|
func Load() ([]*Language, error) {
|
|
if validLanguages != nil {
|
|
return validLanguages, nil
|
|
}
|
|
validLanguages = []*Language{}
|
|
|
|
uniqLang := make(map[string]*Language)
|
|
|
|
w := bytes.NewBuffer(nil)
|
|
err := cmd.Run(w, "locale", "-a")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
tks := strings.Split(w.String(), "\n")
|
|
for _, curr := range tks {
|
|
if curr == "" {
|
|
continue
|
|
}
|
|
if lang := getLangName(curr); lang != nil {
|
|
uniqLang[curr] = lang
|
|
}
|
|
}
|
|
|
|
// Create a sorted order list of keys
|
|
sortedKeys := make([]string, 0, len(uniqLang))
|
|
for k := range uniqLang {
|
|
// TODO: Remove this when localization is applied for all languages
|
|
if _, found := localizedLanguages[k]; found {
|
|
sortedKeys = append(sortedKeys, k)
|
|
}
|
|
}
|
|
sort.Strings(sortedKeys)
|
|
|
|
for _, value := range sortedKeys {
|
|
validLanguages = append(validLanguages, uniqLang[value])
|
|
}
|
|
|
|
return validLanguages, nil
|
|
}
|
|
|
|
// IsValidLanguage verifies if the given language is valid
|
|
func IsValidLanguage(l *Language) bool {
|
|
var result = false
|
|
allLanguages, err := Load()
|
|
if err != nil {
|
|
return result
|
|
}
|
|
|
|
for _, curr := range allLanguages {
|
|
if curr.Equals(l) {
|
|
result = true
|
|
}
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
// SetTargetLanguage creates a locale locale.conf on the target
|
|
func SetTargetLanguage(rootDir string, language string) error {
|
|
targetLocaleFile := filepath.Join(rootDir, "/etc/locale.conf")
|
|
|
|
filehandle, err := os.OpenFile(targetLocaleFile, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)
|
|
if err != nil {
|
|
return fmt.Errorf("Could not create locale file")
|
|
}
|
|
|
|
defer func() {
|
|
_ = filehandle.Close()
|
|
}()
|
|
|
|
if _, err := filehandle.Write([]byte("LANG=" + language + "\n")); err != nil {
|
|
return fmt.Errorf("Could not write keyboard file")
|
|
}
|
|
|
|
return nil
|
|
}
|