123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271 |
- // Copyright 2013 ChaiShushan <chaishushan{AT}gmail.com>. All rights reserved.
- // Use of this source code is governed by a BSD-style
- // license that can be found in the LICENSE file.
- package po
- import (
- "bytes"
- "fmt"
- "io"
- "strconv"
- "strings"
- )
- // Comment represents every message's comments.
- type Comment struct {
- StartLine int // comment start line
- TranslatorComment string // # translator-comments // TrimSpace
- ExtractedComment string // #. extracted-comments
- ReferenceFile []string // #: src/msgcmp.c:338 src/po-lex.c:699
- ReferenceLine []int // #: src/msgcmp.c:338 src/po-lex.c:699
- Flags []string // #, fuzzy,c-format,range:0..10
- PrevMsgContext string // #| msgctxt previous-context
- PrevMsgId string // #| msgid previous-untranslated-string
- }
- func (p *Comment) less(q *Comment) bool {
- if p.StartLine != 0 || q.StartLine != 0 {
- return p.StartLine < q.StartLine
- }
- if a, b := len(p.ReferenceFile), len(q.ReferenceFile); a != b {
- return a < b
- }
- for i := 0; i < len(p.ReferenceFile); i++ {
- if a, b := p.ReferenceFile[i], q.ReferenceFile[i]; a != b {
- return a < b
- }
- if a, b := p.ReferenceLine[i], q.ReferenceLine[i]; a != b {
- return a < b
- }
- }
- return false
- }
- func (p *Comment) readPoComment(r *lineReader) (err error) {
- *p = Comment{}
- if err = r.skipBlankLine(); err != nil {
- return err
- }
- defer func(oldPos int) {
- newPos := r.currentPos()
- if newPos != oldPos && err == io.EOF {
- err = nil
- }
- }(r.currentPos())
- p.StartLine = r.currentPos() + 1
- for {
- var s string
- if s, _, err = r.currentLine(); err != nil {
- return
- }
- if len(s) == 0 || s[0] != '#' {
- return
- }
- if err = p.readTranslatorComment(r); err != nil {
- return
- }
- if err = p.readExtractedComment(r); err != nil {
- return
- }
- if err = p.readReferenceComment(r); err != nil {
- return
- }
- if err = p.readFlagsComment(r); err != nil {
- return
- }
- if err = p.readPrevMsgContext(r); err != nil {
- return
- }
- if err = p.readPrevMsgId(r); err != nil {
- return
- }
- }
- }
- func (p *Comment) readTranslatorComment(r *lineReader) (err error) {
- const prefix = "# " // .,:|
- for {
- var s string
- if s, _, err = r.readLine(); err != nil {
- return err
- }
- if len(s) < 1 || s[0] != '#' {
- r.unreadLine()
- return nil
- }
- if len(s) >= 2 {
- switch s[1] {
- case '.', ',', ':', '|':
- r.unreadLine()
- return nil
- }
- }
- if p.TranslatorComment != "" {
- p.TranslatorComment += "\n"
- }
- p.TranslatorComment += strings.TrimSpace(s[1:])
- }
- }
- func (p *Comment) readExtractedComment(r *lineReader) (err error) {
- const prefix = "#."
- for {
- var s string
- if s, _, err = r.readLine(); err != nil {
- return err
- }
- if len(s) < len(prefix) || s[:len(prefix)] != prefix {
- r.unreadLine()
- return nil
- }
- if p.ExtractedComment != "" {
- p.ExtractedComment += "\n"
- }
- p.ExtractedComment += strings.TrimSpace(s[len(prefix):])
- }
- }
- func (p *Comment) readReferenceComment(r *lineReader) (err error) {
- const prefix = "#:"
- for {
- var s string
- if s, _, err = r.readLine(); err != nil {
- return err
- }
- if len(s) < len(prefix) || s[:len(prefix)] != prefix {
- r.unreadLine()
- return nil
- }
- ss := strings.Split(strings.TrimSpace(s[len(prefix):]), " ")
- for i := 0; i < len(ss); i++ {
- idx := strings.Index(ss[i], ":")
- if idx <= 0 {
- continue
- }
- name := strings.TrimSpace(ss[i][:idx])
- line, _ := strconv.Atoi(strings.TrimSpace(ss[i][idx+1:]))
- p.ReferenceFile = append(p.ReferenceFile, name)
- p.ReferenceLine = append(p.ReferenceLine, line)
- }
- }
- }
- func (p *Comment) readFlagsComment(r *lineReader) (err error) {
- const prefix = "#,"
- for {
- var s string
- if s, _, err = r.readLine(); err != nil {
- return err
- }
- if len(s) < len(prefix) || s[:len(prefix)] != prefix {
- r.unreadLine()
- return nil
- }
- ss := strings.Split(strings.TrimSpace(s[len(prefix):]), ",")
- for i := 0; i < len(ss); i++ {
- p.Flags = append(p.Flags, strings.TrimSpace(ss[i]))
- }
- }
- }
- func (p *Comment) readPrevMsgContext(r *lineReader) (err error) {
- var s string
- if s, _, err = r.currentLine(); err != nil {
- return
- }
- if !rePrevMsgContextComments.MatchString(s) {
- return
- }
- p.PrevMsgContext, err = p.readString(r)
- return
- }
- func (p *Comment) readPrevMsgId(r *lineReader) (err error) {
- var s string
- if s, _, err = r.currentLine(); err != nil {
- return
- }
- if !rePrevMsgIdComments.MatchString(s) {
- return
- }
- p.PrevMsgId, err = p.readString(r)
- return
- }
- func (p *Comment) readString(r *lineReader) (msg string, err error) {
- var s string
- if s, _, err = r.readLine(); err != nil {
- return
- }
- msg += decodePoString(s)
- for {
- if s, _, err = r.readLine(); err != nil {
- return
- }
- if !reStringLineComments.MatchString(s) {
- r.unreadLine()
- break
- }
- msg += decodePoString(s)
- }
- return
- }
- // GetFuzzy gets the fuzzy flag.
- func (p *Comment) GetFuzzy() bool {
- for _, s := range p.Flags {
- if s == "fuzzy" {
- return true
- }
- }
- return false
- }
- // SetFuzzy sets the fuzzy flag.
- func (p *Comment) SetFuzzy(fuzzy bool) {
- //
- }
- // String returns the po format comment string.
- func (p Comment) String() string {
- var buf bytes.Buffer
- if p.TranslatorComment != "" {
- ss := strings.Split(p.TranslatorComment, "\n")
- for i := 0; i < len(ss); i++ {
- fmt.Fprintf(&buf, "# %s\n", ss[i])
- }
- }
- if p.ExtractedComment != "" {
- ss := strings.Split(p.ExtractedComment, "\n")
- for i := 0; i < len(ss); i++ {
- fmt.Fprintf(&buf, "#. %s\n", ss[i])
- }
- }
- if a, b := len(p.ReferenceFile), len(p.ReferenceLine); a != 0 && a == b {
- fmt.Fprintf(&buf, "#:")
- for i := 0; i < len(p.ReferenceFile); i++ {
- fmt.Fprintf(&buf, " %s:%d", p.ReferenceFile[i], p.ReferenceLine[i])
- }
- fmt.Fprintf(&buf, "\n")
- }
- if len(p.Flags) != 0 {
- fmt.Fprintf(&buf, "#, %s", p.Flags[0])
- for i := 1; i < len(p.Flags); i++ {
- fmt.Fprintf(&buf, ", %s", p.Flags[i])
- }
- fmt.Fprintf(&buf, "\n")
- }
- if p.PrevMsgContext != "" {
- s := encodeCommentPoString(p.PrevMsgContext)
- fmt.Fprintf(&buf, "#| msgctxt %s\n", s)
- }
- if p.PrevMsgId != "" {
- s := encodeCommentPoString(p.PrevMsgId)
- fmt.Fprintf(&buf, "#| msgid %s\n", s)
- }
- return buf.String()
- }
|