Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

filemapping: add support for io/fs (including e.g. go:embed filesystems) #16

Merged
merged 6 commits into from
Jul 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,13 @@ requiring a context string respectively.
```go
import "github.com/snapcore/go-gettext"

//go:embed translations
var assets embed.FS

domain := &gettext.TextDomain{
Name: "messages",
LocaleDir: "path/to/translations",
LocaleDir: "./translations",
LocaleFS: assets, // leave away to use the filesystem directly
}
// or use domain.Locale(lang...) to open a different locale's catalog
locale := domain.UserLocale()
Expand Down
4 changes: 2 additions & 2 deletions filemapping.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ package gettext

import (
"fmt"
"io/fs"
"io/ioutil"
"os"
"runtime"
)

Expand All @@ -21,7 +21,7 @@ func (m *fileMapping) Close() error {
return m.closeMapping()
}

func openMapping(f *os.File) (*fileMapping, error) {
func openMapping(f fs.File) (*fileMapping, error) {
fi, err := f.Stat()
if err != nil {
return nil, err
Expand Down
11 changes: 9 additions & 2 deletions filemapping_unix.go
Original file line number Diff line number Diff line change
@@ -1,15 +1,22 @@
//go:build !windows
// +build !windows

package gettext

import (
"errors"
"io/fs"
"os"
"syscall"
)

func (m *fileMapping) tryMap(f *os.File, size int64) error {
func (m *fileMapping) tryMap(f fs.File, size int64) error {
var err error
m.data, err = syscall.Mmap(int(f.Fd()), 0, int(size), syscall.PROT_READ, syscall.MAP_PRIVATE)
of, ok := f.(*os.File)
if !ok {
return errors.New("virtual filesystem doesn't support mmap")
}
m.data, err = syscall.Mmap(int(of.Fd()), 0, int(size), syscall.PROT_READ, syscall.MAP_PRIVATE)
if err != nil {
return err
}
Expand Down
10 changes: 8 additions & 2 deletions filemapping_windows.go
Original file line number Diff line number Diff line change
@@ -1,16 +1,22 @@
package gettext

import (
"errors"
"io/fs"
"os"
"syscall"
"unsafe"
)

// Adapted from https://github.com/golang/exp/blob/master/mmap/mmap_windows.go

func (m *fileMapping) tryMap(f *os.File, size int64) error {
func (m *fileMapping) tryMap(f fs.File, size int64) error {
of, ok := f.(*os.File)
if !ok {
return errors.New("virtual filesystem doesn't support mmap")
}
low, high := uint32(size), uint32(size>>32)
fmap, err := syscall.CreateFileMapping(syscall.Handle(f.Fd()), nil, syscall.PAGE_READONLY, high, low, nil)
fmap, err := syscall.CreateFileMapping(syscall.Handle(of.Fd()), nil, syscall.PAGE_READONLY, high, low, nil)
if err != nil {
return err
}
Expand Down
16 changes: 13 additions & 3 deletions gettext.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ package gettext

import (
"fmt"
"io/fs"
"os"
"path"
"sync"
Expand All @@ -17,8 +18,11 @@ type TextDomain struct {
// Name is the name of the text domain
Name string
// LocaleDir is the base directory holding translations of the
// domain. If it is empty, DefaultLocaleDir will be used.
// domain. If it is empty, DefaultLocaleDir will be used if LocaleFS is nil; otherwise the root of LocaleFS will be used.
LocaleDir string
// LocaleFS is the filesystem used to access LocaleDir.
// When nil, the normal OS filesystem will be used.
LocaleFS fs.FS
// PathResolver is called to determine the path of a
// particular locale's translations. If it is nil then
// DefaultResolver will be used, which implements the standard
Expand Down Expand Up @@ -62,7 +66,7 @@ func (t *TextDomain) load(locale string) *mocatalog {
}

localeDir := t.LocaleDir
if localeDir == "" {
if localeDir == "" && t.LocaleFS == nil {
localeDir = DefaultLocaleDir
}
resolver := t.PathResolver
Expand All @@ -71,7 +75,13 @@ func (t *TextDomain) load(locale string) *mocatalog {
}
t.cache[locale] = nil
path := resolver(localeDir, locale, t.Name)
f, err := os.Open(path)
var f fs.File
var err error
if t.LocaleFS != nil {
f, err = t.LocaleFS.Open(path)
} else {
f, err = os.Open(path)
}
if err != nil {
return nil
}
Expand Down
10 changes: 10 additions & 0 deletions gettext_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package gettext

import (
"embed"
"fmt"
"io/ioutil"
"os"
Expand Down Expand Up @@ -271,3 +272,12 @@ func TestNotMoFile(t *testing.T) {
)

}

//go:embed testdata
var assets embed.FS

func TestFS(t *testing.T) {
translations := &TextDomain{Name: "messages", LocaleDir: "testdata", LocaleFS: assets, PathResolver: my_resolver}
en := translations.Locale("en")
assert_equal(t, en.Gettext("greeting"), "Hello")
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module github.com/snapcore/go-gettext

go 1.13
go 1.18
3 changes: 2 additions & 1 deletion mofile.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"bytes"
"encoding/binary"
"fmt"
"io/fs"
"os"
"sort"
"strings"
Expand Down Expand Up @@ -223,7 +224,7 @@ func ParseMO(file *os.File) (Catalog, error) {
return Catalog{[]*mocatalog{mo}}, nil
}

func parseMO(file *os.File) (*mocatalog, error) {
func parseMO(file fs.File) (*mocatalog, error) {
m, err := openMapping(file)
if err != nil {
return nil, err
Expand Down
Loading