Add support for loading external i18n language files.
The new `--i18n-dir` directory allows the loading of an external directory of i18n JSON files, milar to have `--static-dir` works. New languages can be added and existing language files can be customized this way. This commit changes file loading behaviour so that invalid or non-existent don't halt the execution of the app completely but merely throw a warning and continue with the default (en) lang.
This commit is contained in:
parent
4ddaba889f
commit
c479a90c42
18
cmd/i18n.go
18
cmd/i18n.go
|
@ -29,8 +29,8 @@ func handleGetI18nLang(c echo.Context) error {
|
|||
return echo.NewHTTPError(http.StatusBadRequest, "Invalid language code.")
|
||||
}
|
||||
|
||||
i, err := getI18nLang(lang, app.fs)
|
||||
if err != nil {
|
||||
i, ok, err := getI18nLang(lang, app.fs)
|
||||
if err != nil && !ok {
|
||||
return echo.NewHTTPError(http.StatusBadRequest, "Unknown language.")
|
||||
}
|
||||
|
||||
|
@ -65,29 +65,31 @@ func getI18nLangList(lang string, app *App) ([]i18nLang, error) {
|
|||
return out, nil
|
||||
}
|
||||
|
||||
func getI18nLang(lang string, fs stuffbin.FileSystem) (*i18n.I18n, error) {
|
||||
// The bool indicates whether the specified language could be loaded. If it couldn't
|
||||
// be, the app shouldn't halt but throw a warning.
|
||||
func getI18nLang(lang string, fs stuffbin.FileSystem) (*i18n.I18n, bool, error) {
|
||||
const def = "en"
|
||||
|
||||
b, err := fs.Read(fmt.Sprintf("/i18n/%s.json", def))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error reading default i18n language file: %s: %v", def, err)
|
||||
return nil, false, fmt.Errorf("error reading default i18n language file: %s: %v", def, err)
|
||||
}
|
||||
|
||||
// Initialize with the default language.
|
||||
i, err := i18n.New(b)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error unmarshalling i18n language: %v", err)
|
||||
return nil, false, fmt.Errorf("error unmarshalling i18n language: %s: %v", lang, err)
|
||||
}
|
||||
|
||||
// Load the selected language on top of it.
|
||||
b, err = fs.Read(fmt.Sprintf("/i18n/%s.json", lang))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error reading i18n language file: %v", err)
|
||||
return i, true, fmt.Errorf("error reading i18n language file: %s: %v", lang, err)
|
||||
}
|
||||
|
||||
if err := i.Load(b); err != nil {
|
||||
return nil, fmt.Errorf("error loading i18n language file: %v", err)
|
||||
return i, true, fmt.Errorf("error loading i18n language file: %s: %v", lang, err)
|
||||
}
|
||||
|
||||
return i, nil
|
||||
return i, true, nil
|
||||
}
|
||||
|
|
26
cmd/init.go
26
cmd/init.go
|
@ -82,6 +82,7 @@ func initFlags() {
|
|||
f.Bool("version", false, "current version of the build")
|
||||
f.Bool("new-config", false, "generate sample config file")
|
||||
f.String("static-dir", "", "(optional) path to directory with static files")
|
||||
f.String("i18n-dir", "", "(optional) path to directory with i18n language files")
|
||||
f.Bool("yes", false, "assume 'yes' to prompts, eg: during --install")
|
||||
if err := f.Parse(os.Args[1:]); err != nil {
|
||||
lo.Fatalf("error loading flags: %v", err)
|
||||
|
@ -107,7 +108,7 @@ func initConfigFiles(files []string, ko *koanf.Koanf) {
|
|||
|
||||
// initFileSystem initializes the stuffbin FileSystem to provide
|
||||
// access to bunded static assets to the app.
|
||||
func initFS(staticDir string) stuffbin.FileSystem {
|
||||
func initFS(staticDir, i18nDir string) stuffbin.FileSystem {
|
||||
// Get the executable's path.
|
||||
path, err := os.Executable()
|
||||
if err != nil {
|
||||
|
@ -144,7 +145,7 @@ func initFS(staticDir string) stuffbin.FileSystem {
|
|||
}
|
||||
}
|
||||
|
||||
// Optional static directory to override files.
|
||||
// Optional static directory to override static files.
|
||||
if staticDir != "" {
|
||||
lo.Printf("loading static files from: %v", staticDir)
|
||||
fStatic, err := stuffbin.NewLocalFS("/", []string{
|
||||
|
@ -161,6 +162,19 @@ func initFS(staticDir string) stuffbin.FileSystem {
|
|||
lo.Fatalf("error merging static directory: %s: %v", staticDir, err)
|
||||
}
|
||||
}
|
||||
|
||||
// Optional static directory to override i18n language files.
|
||||
if i18nDir != "" {
|
||||
lo.Printf("loading i18n language files from: %v", i18nDir)
|
||||
fi18n, err := stuffbin.NewLocalFS("/", []string{i18nDir + ":/i18n"}...)
|
||||
if err != nil {
|
||||
lo.Fatalf("failed reading i18n directory: %s: %v", i18nDir, err)
|
||||
}
|
||||
|
||||
if err := fs.Merge(fi18n); err != nil {
|
||||
lo.Fatalf("error merging i18n directory: %s: %v", i18nDir, err)
|
||||
}
|
||||
}
|
||||
return fs
|
||||
}
|
||||
|
||||
|
@ -262,9 +276,13 @@ func initConstants() *constants {
|
|||
// and then the selected language is loaded on top of it so that if there are
|
||||
// missing translations in it, the default English translations show up.
|
||||
func initI18n(lang string, fs stuffbin.FileSystem) *i18n.I18n {
|
||||
i, err := getI18nLang(lang, fs)
|
||||
i, ok, err := getI18nLang(lang, fs)
|
||||
if err != nil {
|
||||
lo.Fatal(err)
|
||||
if ok {
|
||||
lo.Println(err)
|
||||
} else {
|
||||
lo.Fatal(err)
|
||||
}
|
||||
}
|
||||
return i
|
||||
}
|
||||
|
|
|
@ -166,7 +166,7 @@ func newConfigFile() error {
|
|||
|
||||
// Initialize the static file system into which all
|
||||
// required static assets (.sql, .js files etc.) are loaded.
|
||||
fs := initFS("")
|
||||
fs := initFS("", "")
|
||||
b, err := fs.Read("config.toml.sample")
|
||||
if err != nil {
|
||||
return fmt.Errorf("error reading sample config (is binary stuffed?): %v", err)
|
||||
|
|
|
@ -106,7 +106,7 @@ func init() {
|
|||
|
||||
// Connect to the database, load the filesystem to read SQL queries.
|
||||
db = initDB()
|
||||
fs = initFS(ko.String("static-dir"))
|
||||
fs = initFS(ko.String("static-dir"), ko.String("i18n-dir"))
|
||||
|
||||
// Installer mode? This runs before the SQL queries are loaded and prepared
|
||||
// as the installer needs to work on an empty DB.
|
||||
|
|
Loading…
Reference in New Issue