1
2
3
4
5 package po
6
7 import (
8 "bytes"
9 "fmt"
10 "io"
11 "strconv"
12 "strings"
13 )
14
15
16 type Comment struct {
17 StartLine int
18 TranslatorComment string
19 ExtractedComment string
20 ReferenceFile []string
21 ReferenceLine []int
22 Flags []string
23 PrevMsgContext string
24 PrevMsgId string
25 }
26
27 func (p *Comment) less(q *Comment) bool {
28 if p.StartLine != 0 || q.StartLine != 0 {
29 return p.StartLine < q.StartLine
30 }
31 if a, b := len(p.ReferenceFile), len(q.ReferenceFile); a != b {
32 return a < b
33 }
34 for i := 0; i < len(p.ReferenceFile); i++ {
35 if a, b := p.ReferenceFile[i], q.ReferenceFile[i]; a != b {
36 return a < b
37 }
38 if a, b := p.ReferenceLine[i], q.ReferenceLine[i]; a != b {
39 return a < b
40 }
41 }
42 return false
43 }
44
45 func (p *Comment) readPoComment(r *lineReader) (err error) {
46 *p = Comment{}
47 if err = r.skipBlankLine(); err != nil {
48 return err
49 }
50 defer func(oldPos int) {
51 newPos := r.currentPos()
52 if newPos != oldPos && err == io.EOF {
53 err = nil
54 }
55 }(r.currentPos())
56
57 p.StartLine = r.currentPos() + 1
58 for {
59 var s string
60 if s, _, err = r.currentLine(); err != nil {
61 return
62 }
63 if len(s) == 0 || s[0] != '#' {
64 return
65 }
66
67 if err = p.readTranslatorComment(r); err != nil {
68 return
69 }
70 if err = p.readExtractedComment(r); err != nil {
71 return
72 }
73 if err = p.readReferenceComment(r); err != nil {
74 return
75 }
76 if err = p.readFlagsComment(r); err != nil {
77 return
78 }
79 if err = p.readPrevMsgContext(r); err != nil {
80 return
81 }
82 if err = p.readPrevMsgId(r); err != nil {
83 return
84 }
85 }
86 }
87
88 func (p *Comment) readTranslatorComment(r *lineReader) (err error) {
89 const prefix = "# "
90 for {
91 var s string
92 if s, _, err = r.readLine(); err != nil {
93 return err
94 }
95 if len(s) < 1 || s[0] != '#' {
96 r.unreadLine()
97 return nil
98 }
99 if len(s) >= 2 {
100 switch s[1] {
101 case '.', ',', ':', '|':
102 r.unreadLine()
103 return nil
104 }
105 }
106 if p.TranslatorComment != "" {
107 p.TranslatorComment += "\n"
108 }
109 p.TranslatorComment += strings.TrimSpace(s[1:])
110 }
111 }
112
113 func (p *Comment) readExtractedComment(r *lineReader) (err error) {
114 const prefix = "#."
115 for {
116 var s string
117 if s, _, err = r.readLine(); err != nil {
118 return err
119 }
120 if len(s) < len(prefix) || s[:len(prefix)] != prefix {
121 r.unreadLine()
122 return nil
123 }
124 if p.ExtractedComment != "" {
125 p.ExtractedComment += "\n"
126 }
127 p.ExtractedComment += strings.TrimSpace(s[len(prefix):])
128 }
129 }
130
131 func (p *Comment) readReferenceComment(r *lineReader) (err error) {
132 const prefix = "#:"
133 for {
134 var s string
135 if s, _, err = r.readLine(); err != nil {
136 return err
137 }
138 if len(s) < len(prefix) || s[:len(prefix)] != prefix {
139 r.unreadLine()
140 return nil
141 }
142 ss := strings.Split(strings.TrimSpace(s[len(prefix):]), " ")
143 for i := 0; i < len(ss); i++ {
144 idx := strings.Index(ss[i], ":")
145 if idx <= 0 {
146 continue
147 }
148 name := strings.TrimSpace(ss[i][:idx])
149 line, _ := strconv.Atoi(strings.TrimSpace(ss[i][idx+1:]))
150 p.ReferenceFile = append(p.ReferenceFile, name)
151 p.ReferenceLine = append(p.ReferenceLine, line)
152 }
153 }
154 }
155
156 func (p *Comment) readFlagsComment(r *lineReader) (err error) {
157 const prefix = "#,"
158 for {
159 var s string
160 if s, _, err = r.readLine(); err != nil {
161 return err
162 }
163 if len(s) < len(prefix) || s[:len(prefix)] != prefix {
164 r.unreadLine()
165 return nil
166 }
167 ss := strings.Split(strings.TrimSpace(s[len(prefix):]), ",")
168 for i := 0; i < len(ss); i++ {
169 p.Flags = append(p.Flags, strings.TrimSpace(ss[i]))
170 }
171 }
172 }
173
174 func (p *Comment) readPrevMsgContext(r *lineReader) (err error) {
175 var s string
176 if s, _, err = r.currentLine(); err != nil {
177 return
178 }
179 if !rePrevMsgContextComments.MatchString(s) {
180 return
181 }
182 p.PrevMsgContext, err = p.readString(r)
183 return
184 }
185
186 func (p *Comment) readPrevMsgId(r *lineReader) (err error) {
187 var s string
188 if s, _, err = r.currentLine(); err != nil {
189 return
190 }
191 if !rePrevMsgIdComments.MatchString(s) {
192 return
193 }
194 p.PrevMsgId, err = p.readString(r)
195 return
196 }
197
198 func (p *Comment) readString(r *lineReader) (msg string, err error) {
199 var s string
200 if s, _, err = r.readLine(); err != nil {
201 return
202 }
203 msg += decodePoString(s)
204 for {
205 if s, _, err = r.readLine(); err != nil {
206 return
207 }
208 if !reStringLineComments.MatchString(s) {
209 r.unreadLine()
210 break
211 }
212 msg += decodePoString(s)
213 }
214 return
215 }
216
217
218 func (p *Comment) GetFuzzy() bool {
219 for _, s := range p.Flags {
220 if s == "fuzzy" {
221 return true
222 }
223 }
224 return false
225 }
226
227
228 func (p *Comment) SetFuzzy(fuzzy bool) {
229
230 }
231
232
233 func (p Comment) String() string {
234 var buf bytes.Buffer
235 if p.TranslatorComment != "" {
236 ss := strings.Split(p.TranslatorComment, "\n")
237 for i := 0; i < len(ss); i++ {
238 fmt.Fprintf(&buf, "# %s\n", ss[i])
239 }
240 }
241 if p.ExtractedComment != "" {
242 ss := strings.Split(p.ExtractedComment, "\n")
243 for i := 0; i < len(ss); i++ {
244 fmt.Fprintf(&buf, "#. %s\n", ss[i])
245 }
246 }
247 if a, b := len(p.ReferenceFile), len(p.ReferenceLine); a != 0 && a == b {
248 fmt.Fprintf(&buf, "#:")
249 for i := 0; i < len(p.ReferenceFile); i++ {
250 fmt.Fprintf(&buf, " %s:%d", p.ReferenceFile[i], p.ReferenceLine[i])
251 }
252 fmt.Fprintf(&buf, "\n")
253 }
254 if len(p.Flags) != 0 {
255 fmt.Fprintf(&buf, "#, %s", p.Flags[0])
256 for i := 1; i < len(p.Flags); i++ {
257 fmt.Fprintf(&buf, ", %s", p.Flags[i])
258 }
259 fmt.Fprintf(&buf, "\n")
260 }
261 if p.PrevMsgContext != "" {
262 s := encodeCommentPoString(p.PrevMsgContext)
263 fmt.Fprintf(&buf, "#| msgctxt %s\n", s)
264 }
265 if p.PrevMsgId != "" {
266 s := encodeCommentPoString(p.PrevMsgId)
267 fmt.Fprintf(&buf, "#| msgid %s\n", s)
268 }
269 return buf.String()
270 }
271
View as plain text