1
2
3
4
5 package gettext
6
7 import (
8 "archive/zip"
9 "fmt"
10 "io/ioutil"
11 "sort"
12 "strings"
13 )
14
15 type zipFS struct {
16 root string
17 name string
18 r *zip.Reader
19 }
20
21 func newZipFS(r *zip.Reader, name string) *zipFS {
22 fs := &zipFS{r: r, name: name}
23 fs.root = fs.zipRoot()
24 return fs
25 }
26
27 func (p *zipFS) zipName() string {
28 name := p.name
29 if x := strings.LastIndexAny(name, `\/`); x != -1 {
30 name = name[x+1:]
31 }
32 name = strings.TrimSuffix(name, ".zip")
33 return name
34 }
35
36 func (p *zipFS) zipRoot() string {
37 var somepath string
38 for _, f := range p.r.File {
39 if x := strings.Index(f.Name, "LC_MESSAGES"); x != -1 {
40 somepath = f.Name
41 }
42 if x := strings.Index(f.Name, "LC_RESOURCE"); x != -1 {
43 somepath = f.Name
44 }
45 }
46 if somepath == "" {
47 return p.zipName()
48 }
49
50 ss := strings.Split(somepath, "/")
51 for i, s := range ss {
52
53
54 if (s == "LC_MESSAGES" || s == "LC_RESOURCE") && i >= 2 {
55 return strings.Join(ss[:i-1], "/")
56 }
57 }
58
59 return p.zipName()
60 }
61
62 func (p *zipFS) LocaleList() []string {
63 var locals []string
64 for s := range p.lsZip(p.r) {
65 locals = append(locals, s)
66 }
67 sort.Strings(locals)
68 return locals
69 }
70
71 func (p *zipFS) LoadMessagesFile(domain, lang, ext string) ([]byte, error) {
72 trName := p.makeMessagesFileName(domain, lang, ext)
73 for _, f := range p.r.File {
74 if f.Name != trName {
75 continue
76 }
77 rc, err := f.Open()
78 if err != nil {
79 return nil, err
80 }
81 rcData, err := ioutil.ReadAll(rc)
82 rc.Close()
83 return rcData, err
84 }
85 return nil, fmt.Errorf("not found")
86 }
87
88 func (p *zipFS) LoadResourceFile(domain, lang, name string) ([]byte, error) {
89 rcName := p.makeResourceFileName(domain, lang, name)
90 for _, f := range p.r.File {
91 if f.Name != rcName {
92 continue
93 }
94 rc, err := f.Open()
95 if err != nil {
96 return nil, err
97 }
98 rcData, err := ioutil.ReadAll(rc)
99 rc.Close()
100 return rcData, err
101 }
102 return nil, fmt.Errorf("not found")
103 }
104
105 func (p *zipFS) String() string {
106 return "gettext.zipfs(" + p.name + ")"
107 }
108
109 func (p *zipFS) makeMessagesFileName(domain, lang, ext string) string {
110 return fmt.Sprintf("%s/%s/LC_MESSAGES/%s%s", p.root, lang, domain, ext)
111 }
112
113 func (p *zipFS) makeResourceFileName(domain, lang, name string) string {
114 return fmt.Sprintf("%s/%s/LC_RESOURCE/%s/%s", p.root, lang, domain, name)
115 }
116
117 func (p *zipFS) lsZip(r *zip.Reader) map[string]bool {
118 ssMap := make(map[string]bool)
119 for _, f := range r.File {
120 if x := strings.Index(f.Name, "LC_MESSAGES"); x != -1 {
121 s := strings.TrimRight(f.Name[:x], `\/`)
122 if x = strings.LastIndexAny(s, `\/`); x != -1 {
123 s = s[x+1:]
124 }
125 if s != "" {
126 ssMap[s] = true
127 }
128 continue
129 }
130 if x := strings.Index(f.Name, "LC_RESOURCE"); x != -1 {
131 s := strings.TrimRight(f.Name[:x], `\/`)
132 if x = strings.LastIndexAny(s, `\/`); x != -1 {
133 s = s[x+1:]
134 }
135 if s != "" {
136 ssMap[s] = true
137 }
138 continue
139 }
140 }
141 return ssMap
142 }
143
View as plain text