...

Source file src/github.com/chai2010/gettext-go/po/comment.go

Documentation: github.com/chai2010/gettext-go/po

     1  // Copyright 2013 ChaiShushan <chaishushan{AT}gmail.com>. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package po
     6  
     7  import (
     8  	"bytes"
     9  	"fmt"
    10  	"io"
    11  	"strconv"
    12  	"strings"
    13  )
    14  
    15  // Comment represents every message's comments.
    16  type Comment struct {
    17  	StartLine         int      // comment start line
    18  	TranslatorComment string   // #  translator-comments // TrimSpace
    19  	ExtractedComment  string   // #. extracted-comments
    20  	ReferenceFile     []string // #: src/msgcmp.c:338 src/po-lex.c:699
    21  	ReferenceLine     []int    // #: src/msgcmp.c:338 src/po-lex.c:699
    22  	Flags             []string // #, fuzzy,c-format,range:0..10
    23  	PrevMsgContext    string   // #| msgctxt previous-context
    24  	PrevMsgId         string   // #| msgid previous-untranslated-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  // GetFuzzy gets the fuzzy flag.
   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  // SetFuzzy sets the fuzzy flag.
   228  func (p *Comment) SetFuzzy(fuzzy bool) {
   229  	//
   230  }
   231  
   232  // String returns the po format comment string.
   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