github.com/rigado/snapd@v2.42.5-go-mod+incompatible/i18n/i18n.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2014-2015 Canonical Ltd 5 * 6 * This program is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 3 as 8 * published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 * 18 */ 19 20 package i18n 21 22 //go:generate update-pot 23 24 import ( 25 "fmt" 26 "os" 27 "path/filepath" 28 "strings" 29 30 "github.com/snapcore/go-gettext" 31 32 "github.com/snapcore/snapd/dirs" 33 "github.com/snapcore/snapd/osutil" 34 ) 35 36 // TEXTDOMAIN is the message domain used by snappy; see dgettext(3) 37 // for more information. 38 var ( 39 TEXTDOMAIN = "snappy" 40 locale gettext.Catalog 41 translations gettext.Translations 42 ) 43 44 func init() { 45 bindTextDomain(TEXTDOMAIN, "/usr/share/locale") 46 setLocale("") 47 } 48 49 func langpackResolver(baseRoot string, locale string, domain string) string { 50 // first check for the real locale (e.g. de_DE) 51 // then try to simplify the locale (e.g. de_DE -> de) 52 locales := []string{locale, strings.SplitN(locale, "_", 2)[0]} 53 for _, locale := range locales { 54 r := filepath.Join(locale, "LC_MESSAGES", fmt.Sprintf("%s.mo", domain)) 55 56 // look into the core snaps first for translations, 57 // then the main system 58 candidateDirs := []string{ 59 filepath.Join(dirs.SnapMountDir, "/core/current/", baseRoot), 60 baseRoot, 61 } 62 for _, root := range candidateDirs { 63 // ubuntu uses /usr/lib/locale-langpack and patches the glibc gettext 64 // implementation 65 langpack := filepath.Join(root, "..", "locale-langpack", r) 66 if osutil.FileExists(langpack) { 67 return langpack 68 } 69 70 regular := filepath.Join(root, r) 71 if osutil.FileExists(regular) { 72 return regular 73 } 74 } 75 } 76 77 return "" 78 } 79 80 func bindTextDomain(domain, dir string) { 81 translations = gettext.NewTranslations(dir, domain, langpackResolver) 82 } 83 84 func setLocale(loc string) { 85 if loc == "" { 86 loc = os.Getenv("LC_MESSAGES") 87 if loc == "" { 88 loc = os.Getenv("LANG") 89 } 90 } 91 // de_DE.UTF-8, de_DE@euro all need to get simplified 92 loc = strings.Split(loc, "@")[0] 93 loc = strings.Split(loc, ".")[0] 94 95 locale = translations.Locale(loc) 96 } 97 98 // G is the shorthand for Gettext 99 func G(msgid string) string { 100 return locale.Gettext(msgid) 101 } 102 103 // https://www.gnu.org/software/gettext/manual/html_node/Plural-forms.html 104 // (search for 1000) 105 func ngn(d int) uint32 { 106 const max = 1000000 107 if d < 0 { 108 d = -d 109 } 110 if d > max { 111 return uint32((d % max) + max) 112 } 113 return uint32(d) 114 } 115 116 // NG is the shorthand for NGettext 117 func NG(msgid string, msgidPlural string, n int) string { 118 return locale.NGettext(msgid, msgidPlural, ngn(n)) 119 }