Move translations to server
This commit is contained in:
+6
-1
@@ -48,6 +48,7 @@ func (app *Router) routes(path string) http.Handler {
|
||||
app.R(r, "/artist", model.Artist{}, true)
|
||||
app.R(r, "/player", model.Player{}, true)
|
||||
app.R(r, "/transcoding", model.Transcoding{}, conf.Server.EnableTranscodingConfig)
|
||||
app.addResource(r, "/translation", newTranslationRepository, false)
|
||||
|
||||
// Keepalive endpoint to be used to keep the session valid (ex: while playing songs)
|
||||
r.Get("/keepalive/*", func(w http.ResponseWriter, r *http.Request) { _, _ = w.Write([]byte(`{"response":"ok"}`)) })
|
||||
@@ -64,12 +65,16 @@ func (app *Router) R(r chi.Router, pathPrefix string, model interface{}, persist
|
||||
constructor := func(ctx context.Context) rest.Repository {
|
||||
return app.ds.Resource(ctx, model)
|
||||
}
|
||||
app.addResource(r, pathPrefix, constructor, persistable)
|
||||
}
|
||||
|
||||
func (app *Router) addResource(r chi.Router, pathPrefix string, constructor rest.RepositoryConstructor, persistable bool) {
|
||||
r.Route(pathPrefix, func(r chi.Router) {
|
||||
r.Get("/", rest.GetAll(constructor))
|
||||
if persistable {
|
||||
r.Post("/", rest.Post(constructor))
|
||||
}
|
||||
r.Route("/{id:[0-9a-f\\-]+}", func(r chi.Router) {
|
||||
r.Route("/{id}", func(r chi.Router) {
|
||||
r.Use(UrlParams)
|
||||
r.Get("/", rest.Get(constructor))
|
||||
if persistable {
|
||||
|
||||
@@ -13,7 +13,7 @@ import (
|
||||
"github.com/deluan/navidrome/model"
|
||||
)
|
||||
|
||||
// Injects the `firstTime` config in the `index.html` template
|
||||
// Injects the config in the `index.html` template
|
||||
func ServeIndex(ds model.DataStore, fs http.FileSystem) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
c, err := ds.User(r.Context()).CountAll()
|
||||
@@ -21,6 +21,9 @@ func ServeIndex(ds model.DataStore, fs http.FileSystem) http.HandlerFunc {
|
||||
|
||||
t := getIndexTemplate(r, fs)
|
||||
|
||||
if err != nil {
|
||||
log.Error("Error loading default English translation file", err)
|
||||
}
|
||||
appConfig := map[string]interface{}{
|
||||
"version": consts.Version(),
|
||||
"firstTime": firstTime,
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/deluan/navidrome/log"
|
||||
"github.com/deluan/navidrome/resources"
|
||||
"github.com/deluan/rest"
|
||||
)
|
||||
|
||||
const i18nFolder = "i18n"
|
||||
|
||||
type translation struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Data string `json:"data"`
|
||||
}
|
||||
|
||||
var (
|
||||
once sync.Once
|
||||
translations map[string]translation
|
||||
)
|
||||
|
||||
func newTranslationRepository(context.Context) rest.Repository {
|
||||
if err := loadTranslations(); err != nil {
|
||||
log.Error("Error loading translation files", err)
|
||||
}
|
||||
return &translationRepository{}
|
||||
}
|
||||
|
||||
type translationRepository struct{}
|
||||
|
||||
func (r *translationRepository) Read(id string) (interface{}, error) {
|
||||
if t, ok := translations[id]; ok {
|
||||
return t, nil
|
||||
}
|
||||
return nil, rest.ErrNotFound
|
||||
}
|
||||
|
||||
// Simple Count implementation. Does not support any `options`
|
||||
func (r *translationRepository) Count(options ...rest.QueryOptions) (int64, error) {
|
||||
return int64(len(translations)), nil
|
||||
}
|
||||
|
||||
// Simple ReadAll implementation, only returns IDs. Does not support any `options`, always sort by name asc
|
||||
func (r *translationRepository) ReadAll(options ...rest.QueryOptions) (interface{}, error) {
|
||||
var result []translation
|
||||
for _, t := range translations {
|
||||
t.Data = ""
|
||||
result = append(result, t)
|
||||
}
|
||||
sort.Slice(result, func(i, j int) bool {
|
||||
return result[i].Name < result[j].Name
|
||||
})
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (r *translationRepository) EntityName() string {
|
||||
return "translation"
|
||||
}
|
||||
|
||||
func (r *translationRepository) NewInstance() interface{} {
|
||||
return &translation{}
|
||||
}
|
||||
|
||||
func loadTranslations() (loadError error) {
|
||||
once.Do(func() {
|
||||
translations = make(map[string]translation)
|
||||
dir, err := resources.AssetFile().Open(i18nFolder)
|
||||
if err != nil {
|
||||
loadError = err
|
||||
return
|
||||
}
|
||||
files, err := dir.Readdir(0)
|
||||
if err != nil {
|
||||
loadError = err
|
||||
return
|
||||
}
|
||||
for _, f := range files {
|
||||
t, err := loadTranslation(f.Name())
|
||||
if err != nil {
|
||||
log.Error("Error loading translation file", "file", f.Name(), err)
|
||||
continue
|
||||
}
|
||||
translations[t.ID] = t
|
||||
}
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
func loadTranslation(fileName string) (trans translation, err error) {
|
||||
id := strings.TrimSuffix(fileName, filepath.Ext(fileName))
|
||||
filePath := filepath.Join(i18nFolder, fileName)
|
||||
data, err := resources.Asset(filePath)
|
||||
trans.Data = string(data)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
var out map[string]interface{}
|
||||
err = json.Unmarshal(data, &out)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
trans.Name = out["languageName"].(string)
|
||||
trans.ID = id
|
||||
return
|
||||
}
|
||||
|
||||
var _ rest.Repository = (*translationRepository)(nil)
|
||||
Reference in New Issue
Block a user