forked from Plemya-x/ALR
		
	feat: add new logger and translation
This commit is contained in:
		@@ -21,14 +21,16 @@ package config
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"log/slog"
 | 
			
		||||
	"os"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"sync"
 | 
			
		||||
 | 
			
		||||
	"github.com/pelletier/go-toml/v2"
 | 
			
		||||
 | 
			
		||||
	"github.com/leonelquinteros/gotext"
 | 
			
		||||
 | 
			
		||||
	"gitea.plemya-x.ru/Plemya-x/ALR/internal/types"
 | 
			
		||||
	"gitea.plemya-x.ru/Plemya-x/ALR/pkg/loggerctx"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type ALRConfig struct {
 | 
			
		||||
@@ -56,10 +58,9 @@ func New() *ALRConfig {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *ALRConfig) Load(ctx context.Context) {
 | 
			
		||||
	log := loggerctx.From(ctx)
 | 
			
		||||
	cfgFl, err := os.Open(c.GetPaths(ctx).ConfigPath)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Warn("Error opening config file, using defaults").Err(err).Send()
 | 
			
		||||
		slog.Warn(gotext.Get("Error opening config file, using defaults"), "err", err)
 | 
			
		||||
		c.cfg = defaultConfig
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
@@ -72,27 +73,28 @@ func (c *ALRConfig) Load(ctx context.Context) {
 | 
			
		||||
 | 
			
		||||
	err = toml.NewDecoder(cfgFl).Decode(config)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Warn("Error decoding config file, using defaults").Err(err).Send()
 | 
			
		||||
		slog.Warn(gotext.Get("Error decoding config file, using defaults"), "err", err)
 | 
			
		||||
		c.cfg = defaultConfig
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	c.cfg = config
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *ALRConfig) initPaths(ctx context.Context) {
 | 
			
		||||
	log := loggerctx.From(ctx)
 | 
			
		||||
func (c *ALRConfig) initPaths() {
 | 
			
		||||
	paths := &Paths{}
 | 
			
		||||
 | 
			
		||||
	cfgDir, err := os.UserConfigDir()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Fatal("Unable to detect user config directory").Err(err).Send()
 | 
			
		||||
		slog.Error(gotext.Get("Unable to detect user config directory"), "err", err)
 | 
			
		||||
		os.Exit(1)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	paths.ConfigDir = filepath.Join(cfgDir, "alr")
 | 
			
		||||
 | 
			
		||||
	err = os.MkdirAll(paths.ConfigDir, 0o755)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Fatal("Unable to create ALR config directory").Err(err).Send()
 | 
			
		||||
		slog.Error(gotext.Get("Unable to create ALR config directory"), "err", err)
 | 
			
		||||
		os.Exit(1)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	paths.ConfigPath = filepath.Join(paths.ConfigDir, "alr.toml")
 | 
			
		||||
@@ -100,12 +102,14 @@ func (c *ALRConfig) initPaths(ctx context.Context) {
 | 
			
		||||
	if _, err := os.Stat(paths.ConfigPath); err != nil {
 | 
			
		||||
		cfgFl, err := os.Create(paths.ConfigPath)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			log.Fatal("Unable to create ALR config file").Err(err).Send()
 | 
			
		||||
			slog.Error(gotext.Get("Unable to create ALR config file"), "err", err)
 | 
			
		||||
			os.Exit(1)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		err = toml.NewEncoder(cfgFl).Encode(&defaultConfig)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			log.Fatal("Error encoding default configuration").Err(err).Send()
 | 
			
		||||
			slog.Error(gotext.Get("Error encoding default configuration"), "err", err)
 | 
			
		||||
			os.Exit(1)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		cfgFl.Close()
 | 
			
		||||
@@ -113,7 +117,8 @@ func (c *ALRConfig) initPaths(ctx context.Context) {
 | 
			
		||||
 | 
			
		||||
	cacheDir, err := os.UserCacheDir()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Fatal("Unable to detect cache directory").Err(err).Send()
 | 
			
		||||
		slog.Error(gotext.Get("Unable to detect cache directory"), "err", err)
 | 
			
		||||
		os.Exit(1)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	paths.CacheDir = filepath.Join(cacheDir, "alr")
 | 
			
		||||
@@ -122,12 +127,14 @@ func (c *ALRConfig) initPaths(ctx context.Context) {
 | 
			
		||||
 | 
			
		||||
	err = os.MkdirAll(paths.RepoDir, 0o755)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Fatal("Unable to create repo cache directory").Err(err).Send()
 | 
			
		||||
		slog.Error(gotext.Get("Unable to create repo cache directory"), "err", err)
 | 
			
		||||
		os.Exit(1)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = os.MkdirAll(paths.PkgsDir, 0o755)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Fatal("Unable to create package cache directory").Err(err).Send()
 | 
			
		||||
		slog.Error(gotext.Get("Unable to create package cache directory"), "err", err)
 | 
			
		||||
		os.Exit(1)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	paths.DBPath = filepath.Join(paths.CacheDir, "db")
 | 
			
		||||
@@ -137,7 +144,7 @@ func (c *ALRConfig) initPaths(ctx context.Context) {
 | 
			
		||||
 | 
			
		||||
func (c *ALRConfig) GetPaths(ctx context.Context) *Paths {
 | 
			
		||||
	c.pathsOnce.Do(func() {
 | 
			
		||||
		c.initPaths(ctx)
 | 
			
		||||
		c.initPaths()
 | 
			
		||||
	})
 | 
			
		||||
	return c.paths
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										93
									
								
								internal/logger/log.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										93
									
								
								internal/logger/log.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,93 @@
 | 
			
		||||
// ALR - Any Linux Repository
 | 
			
		||||
// Copyright (C) 2025 Евгений Храмов
 | 
			
		||||
//
 | 
			
		||||
// This program 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.
 | 
			
		||||
//
 | 
			
		||||
// This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 | 
			
		||||
package logger
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"log/slog"
 | 
			
		||||
	"os"
 | 
			
		||||
 | 
			
		||||
	"github.com/charmbracelet/lipgloss"
 | 
			
		||||
	"github.com/charmbracelet/log"
 | 
			
		||||
	"github.com/leonelquinteros/gotext"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type Logger struct {
 | 
			
		||||
	lOut slog.Handler
 | 
			
		||||
	lErr slog.Handler
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func setupOutLogger() *log.Logger {
 | 
			
		||||
	styles := log.DefaultStyles()
 | 
			
		||||
	logger := log.New(os.Stdout)
 | 
			
		||||
	logger.SetStyles(styles)
 | 
			
		||||
	return logger
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func setupErrorLogger() *log.Logger {
 | 
			
		||||
	styles := log.DefaultStyles()
 | 
			
		||||
	styles.Levels[log.ErrorLevel] = lipgloss.NewStyle().
 | 
			
		||||
		SetString(gotext.Get("ERROR")).
 | 
			
		||||
		Padding(0, 1, 0, 1).
 | 
			
		||||
		Background(lipgloss.Color("204")).
 | 
			
		||||
		Foreground(lipgloss.Color("0"))
 | 
			
		||||
	logger := log.New(os.Stderr)
 | 
			
		||||
	logger.SetStyles(styles)
 | 
			
		||||
	return logger
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func New() *Logger {
 | 
			
		||||
	standardLogger := setupOutLogger()
 | 
			
		||||
	errLogger := setupErrorLogger()
 | 
			
		||||
	return &Logger{
 | 
			
		||||
		lOut: standardLogger,
 | 
			
		||||
		lErr: errLogger,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (l *Logger) Enabled(ctx context.Context, level slog.Level) bool {
 | 
			
		||||
	if level <= slog.LevelInfo {
 | 
			
		||||
		return l.lOut.Enabled(ctx, level)
 | 
			
		||||
	}
 | 
			
		||||
	return l.lErr.Enabled(ctx, level)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (l *Logger) Handle(ctx context.Context, rec slog.Record) error {
 | 
			
		||||
	if rec.Level <= slog.LevelInfo {
 | 
			
		||||
		return l.lOut.Handle(ctx, rec)
 | 
			
		||||
	}
 | 
			
		||||
	return l.lErr.Handle(ctx, rec)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (l *Logger) WithAttrs(attrs []slog.Attr) slog.Handler {
 | 
			
		||||
	sl := *l
 | 
			
		||||
	sl.lOut = l.lOut.WithAttrs(attrs)
 | 
			
		||||
	sl.lErr = l.lErr.WithAttrs(attrs)
 | 
			
		||||
	return &sl
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (l *Logger) WithGroup(name string) slog.Handler {
 | 
			
		||||
	sl := *l
 | 
			
		||||
	sl.lOut = l.lOut.WithGroup(name)
 | 
			
		||||
	sl.lErr = l.lErr.WithGroup(name)
 | 
			
		||||
	return &sl
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func SetupDefault() {
 | 
			
		||||
	logger := slog.New(New())
 | 
			
		||||
	slog.SetDefault(logger)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										84
									
								
								internal/translations/default.pot
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								internal/translations/default.pot
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,84 @@
 | 
			
		||||
msgid ""
 | 
			
		||||
msgstr ""
 | 
			
		||||
"Project-Id-Version: \n"
 | 
			
		||||
"Last-Translator: Automatically generated\n"
 | 
			
		||||
"Language-Team: none\n"
 | 
			
		||||
"Language: en\n"
 | 
			
		||||
"MIME-Version: 1.0\n"
 | 
			
		||||
"Content-Type: text/plain; charset=UTF-8\n"
 | 
			
		||||
"Content-Transfer-Encoding: 8bit\n"
 | 
			
		||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
 | 
			
		||||
 | 
			
		||||
#: info.go:42
 | 
			
		||||
msgid "Print information about a package"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: info.go:47
 | 
			
		||||
msgid "Show all information, not just for the current distro"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: info.go:59
 | 
			
		||||
msgid "Command info expected at least 1 argument, got %d"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: info.go:65
 | 
			
		||||
msgid "Error pulling repositories"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: info.go:71
 | 
			
		||||
msgid "Error finding packages"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: info.go:87
 | 
			
		||||
msgid "Error parsing os-release file"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: info.go:96
 | 
			
		||||
msgid "Error resolving overrides"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: info.go:105
 | 
			
		||||
#: info.go:111
 | 
			
		||||
msgid "Error encoding script variables"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: internal/config/config.go:63
 | 
			
		||||
msgid "Error opening config file, using defaults"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: internal/config/config.go:76
 | 
			
		||||
msgid "Error decoding config file, using defaults"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: internal/config/config.go:88
 | 
			
		||||
msgid "Unable to detect user config directory"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: internal/config/config.go:96
 | 
			
		||||
msgid "Unable to create ALR config directory"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: internal/config/config.go:105
 | 
			
		||||
msgid "Unable to create ALR config file"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: internal/config/config.go:111
 | 
			
		||||
msgid "Error encoding default configuration"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: internal/config/config.go:120
 | 
			
		||||
msgid "Unable to detect cache directory"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: internal/config/config.go:130
 | 
			
		||||
msgid "Unable to create repo cache directory"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: internal/config/config.go:136
 | 
			
		||||
msgid "Unable to create package cache directory"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: internal/logger/log.go:44
 | 
			
		||||
msgid "ERROR"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										88
									
								
								internal/translations/po/ru/default.po
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										88
									
								
								internal/translations/po/ru/default.po
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,88 @@
 | 
			
		||||
#
 | 
			
		||||
# Maxim Slipenko <maks1ms@alt-gnome.ru>, 2025.
 | 
			
		||||
#
 | 
			
		||||
msgid ""
 | 
			
		||||
msgstr ""
 | 
			
		||||
"PO-Revision-Date: 2025-01-22 14:23+0300\n"
 | 
			
		||||
"Last-Translator: Maxim Slipenko <maks1ms@alt-gnome.ru>\n"
 | 
			
		||||
"Language: ru\n"
 | 
			
		||||
"MIME-Version: 1.0\n"
 | 
			
		||||
"Content-Type: text/plain; charset=UTF-8\n"
 | 
			
		||||
"Content-Transfer-Encoding: 8bit\n"
 | 
			
		||||
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
 | 
			
		||||
"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
 | 
			
		||||
"X-Generator: Gtranslator 47.1\n"
 | 
			
		||||
"Project-Id-Version: \n"
 | 
			
		||||
"Language-Team: Russian\n"
 | 
			
		||||
 | 
			
		||||
#: info.go:42
 | 
			
		||||
msgid "Print information about a package"
 | 
			
		||||
msgstr "Напечатать информацию о пакете"
 | 
			
		||||
 | 
			
		||||
#: info.go:47
 | 
			
		||||
msgid "Show all information, not just for the current distro"
 | 
			
		||||
msgstr "Показывать всю информацию, а не только для текущего дистрибутива"
 | 
			
		||||
 | 
			
		||||
#: info.go:59
 | 
			
		||||
msgid "Command info expected at least 1 argument, got %d"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: info.go:65
 | 
			
		||||
msgid "Error pulling repositories"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: info.go:71
 | 
			
		||||
msgid "Error finding packages"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: info.go:87
 | 
			
		||||
msgid "Error parsing os-release file"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: info.go:96
 | 
			
		||||
msgid "Error resolving overrides"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: info.go:105 info.go:111
 | 
			
		||||
msgid "Error encoding script variables"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: internal/config/config.go:63
 | 
			
		||||
msgid "Error opening config file, using defaults"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: internal/config/config.go:76
 | 
			
		||||
msgid "Error decoding config file, using defaults"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: internal/config/config.go:88
 | 
			
		||||
msgid "Unable to detect user config directory"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: internal/config/config.go:96
 | 
			
		||||
msgid "Unable to create ALR config directory"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: internal/config/config.go:105
 | 
			
		||||
msgid "Unable to create ALR config file"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: internal/config/config.go:111
 | 
			
		||||
msgid "Error encoding default configuration"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: internal/config/config.go:120
 | 
			
		||||
msgid "Unable to detect cache directory"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: internal/config/config.go:130
 | 
			
		||||
msgid "Unable to create repo cache directory"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: internal/config/config.go:136
 | 
			
		||||
msgid "Unable to create package cache directory"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: internal/logger/log.go:44
 | 
			
		||||
msgid "ERROR"
 | 
			
		||||
msgstr "ОШИБКА"
 | 
			
		||||
@@ -22,8 +22,13 @@ package translations
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"embed"
 | 
			
		||||
	"io/fs"
 | 
			
		||||
	"os"
 | 
			
		||||
	"path"
 | 
			
		||||
	"sync"
 | 
			
		||||
 | 
			
		||||
	"github.com/jeandeaual/go-locale"
 | 
			
		||||
	"github.com/leonelquinteros/gotext"
 | 
			
		||||
	"go.elara.ws/logger"
 | 
			
		||||
	"go.elara.ws/translate"
 | 
			
		||||
	"golang.org/x/text/language"
 | 
			
		||||
@@ -56,3 +61,25 @@ func Translator(ctx context.Context) *translate.Translator {
 | 
			
		||||
func NewLogger(ctx context.Context, l logger.Logger, lang language.Tag) *translate.TranslatedLogger {
 | 
			
		||||
	return translate.NewLogger(l, *Translator(ctx), lang)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//go:embed po
 | 
			
		||||
var poFS embed.FS
 | 
			
		||||
 | 
			
		||||
func Setup() {
 | 
			
		||||
	userLanguage, err := locale.GetLanguage()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		panic(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_, err = fs.Stat(poFS, path.Join("po", userLanguage))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		if os.IsNotExist(err) {
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		panic(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	loc := gotext.NewLocaleFSWithPath(userLanguage, &poFS, "po")
 | 
			
		||||
	loc.SetDomain("default")
 | 
			
		||||
	gotext.SetLocales([]*gotext.Locale{loc})
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user