...

Source file src/github.com/chai2010/gettext-go/po/message.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  // A PO file is made up of many entries,
    16  // each entry holding the relation between an original untranslated string
    17  // and its corresponding translation.
    18  //
    19  // See http://www.gnu.org/software/gettext/manual/html_node/PO-Files.html
    20  type Message struct {
    21  	Comment               // Coments
    22  	MsgContext   string   // msgctxt context
    23  	MsgId        string   // msgid untranslated-string
    24  	MsgIdPlural  string   // msgid_plural untranslated-string-plural
    25  	MsgStr       string   // msgstr translated-string
    26  	MsgStrPlural []string // msgstr[0] translated-string-case-0
    27  }
    28  
    29  func (p *Message) less(q *Message) bool {
    30  	if p.Comment.less(&q.Comment) {
    31  		return true
    32  	}
    33  	if a, b := p.MsgContext, q.MsgContext; a != b {
    34  		return a < b
    35  	}
    36  	if a, b := p.MsgId, q.MsgId; a != b {
    37  		return a < b
    38  	}
    39  	if a, b := p.MsgIdPlural, q.MsgIdPlural; a != b {
    40  		return a < b
    41  	}
    42  	return false
    43  }
    44  
    45  func (p *Message) readPoEntry(r *lineReader) (err error) {
    46  	*p = Message{}
    47  	if err = r.skipBlankLine(); err != nil {
    48  		return
    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  	if err = p.Comment.readPoComment(r); err != nil {
    58  		return
    59  	}
    60  	for {
    61  		var s string
    62  		if s, _, err = r.currentLine(); err != nil {
    63  			return
    64  		}
    65  
    66  		if p.isInvalidLine(s) {
    67  			err = fmt.Errorf("gettext: line %d, %v", r.currentPos(), "invalid line")
    68  			return
    69  		}
    70  		if reComment.MatchString(s) || reBlankLine.MatchString(s) {
    71  			return
    72  		}
    73  
    74  		if err = p.readMsgContext(r); err != nil {
    75  			return
    76  		}
    77  		if err = p.readMsgId(r); err != nil {
    78  			return
    79  		}
    80  		if err = p.readMsgIdPlural(r); err != nil {
    81  			return
    82  		}
    83  		if err = p.readMsgStrOrPlural(r); err != nil {
    84  			return
    85  		}
    86  	}
    87  }
    88  
    89  func (p *Message) readMsgContext(r *lineReader) (err error) {
    90  	var s string
    91  	if s, _, err = r.currentLine(); err != nil {
    92  		return
    93  	}
    94  	if !reMsgContext.MatchString(s) {
    95  		return
    96  	}
    97  	p.MsgContext, err = p.readString(r)
    98  	return
    99  }
   100  
   101  func (p *Message) readMsgId(r *lineReader) (err error) {
   102  	var s string
   103  	if s, _, err = r.currentLine(); err != nil {
   104  		return
   105  	}
   106  	if !reMsgId.MatchString(s) {
   107  		return
   108  	}
   109  	p.MsgId, err = p.readString(r)
   110  	return
   111  }
   112  
   113  func (p *Message) readMsgIdPlural(r *lineReader) (err error) {
   114  	var s string
   115  	if s, _, err = r.currentLine(); err != nil {
   116  		return
   117  	}
   118  	if !reMsgIdPlural.MatchString(s) {
   119  		return
   120  	}
   121  	p.MsgIdPlural, err = p.readString(r)
   122  	return nil
   123  }
   124  
   125  func (p *Message) readMsgStrOrPlural(r *lineReader) (err error) {
   126  	var s string
   127  	if s, _, err = r.currentLine(); err != nil {
   128  		return
   129  	}
   130  	if !reMsgStr.MatchString(s) && !reMsgStrPlural.MatchString(s) {
   131  		return
   132  	}
   133  	if reMsgStrPlural.MatchString(s) {
   134  		left, right := strings.Index(s, `[`), strings.LastIndex(s, `]`)
   135  		idx, _ := strconv.Atoi(s[left+1 : right])
   136  		s, err = p.readString(r)
   137  		if n := len(p.MsgStrPlural); (idx + 1) > n {
   138  			p.MsgStrPlural = append(p.MsgStrPlural, make([]string, (idx+1)-n)...)
   139  		}
   140  		p.MsgStrPlural[idx] = s
   141  	} else {
   142  		p.MsgStr, err = p.readString(r)
   143  	}
   144  	return nil
   145  }
   146  
   147  func (p *Message) readString(r *lineReader) (msg string, err error) {
   148  	var s string
   149  	if s, _, err = r.readLine(); err != nil {
   150  		return
   151  	}
   152  	msg += decodePoString(s)
   153  	for {
   154  		if s, _, err = r.readLine(); err != nil {
   155  			return
   156  		}
   157  		if !reStringLine.MatchString(s) {
   158  			r.unreadLine()
   159  			break
   160  		}
   161  		msg += decodePoString(s)
   162  	}
   163  	return
   164  }
   165  
   166  // String returns the po format entry string.
   167  func (p Message) String() string {
   168  	var buf bytes.Buffer
   169  	fmt.Fprintf(&buf, "%s", p.Comment.String())
   170  	if p.MsgContext != "" {
   171  		fmt.Fprintf(&buf, "msgctxt %s", encodePoString(p.MsgContext))
   172  	}
   173  	fmt.Fprintf(&buf, "msgid %s", encodePoString(p.MsgId))
   174  	if p.MsgIdPlural != "" {
   175  		fmt.Fprintf(&buf, "msgid_plural %s", encodePoString(p.MsgIdPlural))
   176  	}
   177  	if len(p.MsgStrPlural) == 0 {
   178  		if p.MsgStr != "" {
   179  			fmt.Fprintf(&buf, "msgstr %s", encodePoString(p.MsgStr))
   180  		} else {
   181  			fmt.Fprintf(&buf, "msgstr %s", `""`+"\n")
   182  		}
   183  	} else {
   184  		for i := 0; i < len(p.MsgStrPlural); i++ {
   185  			if p.MsgStrPlural[i] != "" {
   186  				fmt.Fprintf(&buf, "msgstr[%d] %s", i, encodePoString(p.MsgStrPlural[i]))
   187  			} else {
   188  				fmt.Fprintf(&buf, "msgstr[%d] %s", i, `""`+"\n")
   189  			}
   190  		}
   191  	}
   192  	return buf.String()
   193  }
   194  

View as plain text