123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190 |
- // 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"
- )
- // A PO file is made up of many entries,
- // each entry holding the relation between an original untranslated string
- // and its corresponding translation.
- //
- // See http://www.gnu.org/software/gettext/manual/html_node/PO-Files.html
- type Message struct {
- Comment // Coments
- MsgContext string // msgctxt context
- MsgId string // msgid untranslated-string
- MsgIdPlural string // msgid_plural untranslated-string-plural
- MsgStr string // msgstr translated-string
- MsgStrPlural []string // msgstr[0] translated-string-case-0
- }
- type byMessages []Message
- func (d byMessages) Len() int {
- return len(d)
- }
- func (d byMessages) Less(i, j int) bool {
- if d[i].Comment.less(&d[j].Comment) {
- return true
- }
- if a, b := d[i].MsgContext, d[j].MsgContext; a != b {
- return a < b
- }
- if a, b := d[i].MsgId, d[j].MsgId; a != b {
- return a < b
- }
- if a, b := d[i].MsgIdPlural, d[j].MsgIdPlural; a != b {
- return a < b
- }
- return false
- }
- func (d byMessages) Swap(i, j int) {
- d[i], d[j] = d[j], d[i]
- }
- func (p *Message) readPoEntry(r *lineReader) (err error) {
- *p = Message{}
- if err = r.skipBlankLine(); err != nil {
- return
- }
- defer func(oldPos int) {
- newPos := r.currentPos()
- if newPos != oldPos && err == io.EOF {
- err = nil
- }
- }(r.currentPos())
- if err = p.Comment.readPoComment(r); err != nil {
- return
- }
- for {
- var s string
- if s, _, err = r.currentLine(); err != nil {
- return
- }
- if p.isInvalidLine(s) {
- err = fmt.Errorf("gettext: line %d, %v", r.currentPos(), "invalid line")
- return
- }
- if reComment.MatchString(s) || reBlankLine.MatchString(s) {
- return
- }
- if err = p.readMsgContext(r); err != nil {
- return
- }
- if err = p.readMsgId(r); err != nil {
- return
- }
- if err = p.readMsgIdPlural(r); err != nil {
- return
- }
- if err = p.readMsgStrOrPlural(r); err != nil {
- return
- }
- }
- }
- func (p *Message) readMsgContext(r *lineReader) (err error) {
- var s string
- if s, _, err = r.currentLine(); err != nil {
- return
- }
- if !reMsgContext.MatchString(s) {
- return
- }
- p.MsgContext, err = p.readString(r)
- return
- }
- func (p *Message) readMsgId(r *lineReader) (err error) {
- var s string
- if s, _, err = r.currentLine(); err != nil {
- return
- }
- if !reMsgId.MatchString(s) {
- return
- }
- p.MsgId, err = p.readString(r)
- return
- }
- func (p *Message) readMsgIdPlural(r *lineReader) (err error) {
- var s string
- if s, _, err = r.currentLine(); err != nil {
- return
- }
- if !reMsgIdPlural.MatchString(s) {
- return
- }
- p.MsgIdPlural, err = p.readString(r)
- return nil
- }
- func (p *Message) readMsgStrOrPlural(r *lineReader) (err error) {
- var s string
- if s, _, err = r.currentLine(); err != nil {
- return
- }
- if !reMsgStr.MatchString(s) && !reMsgStrPlural.MatchString(s) {
- return
- }
- if reMsgStrPlural.MatchString(s) {
- left, right := strings.Index(s, `[`), strings.LastIndex(s, `]`)
- idx, _ := strconv.Atoi(s[left+1 : right])
- s, err = p.readString(r)
- if n := len(p.MsgStrPlural); (idx + 1) > n {
- p.MsgStrPlural = append(p.MsgStrPlural, make([]string, (idx+1)-n)...)
- }
- p.MsgStrPlural[idx] = s
- } else {
- p.MsgStr, err = p.readString(r)
- }
- return nil
- }
- func (p *Message) 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 !reStringLine.MatchString(s) {
- r.unreadLine()
- break
- }
- msg += decodePoString(s)
- }
- return
- }
- // String returns the po format entry string.
- func (p Message) String() string {
- var buf bytes.Buffer
- fmt.Fprintf(&buf, "%s", p.Comment.String())
- fmt.Fprintf(&buf, "msgid %s", encodePoString(p.MsgId))
- if p.MsgIdPlural != "" {
- fmt.Fprintf(&buf, "msgid_plural %s", encodePoString(p.MsgIdPlural))
- }
- if p.MsgStr != "" {
- fmt.Fprintf(&buf, "msgstr %s", encodePoString(p.MsgStr))
- }
- for i := 0; i < len(p.MsgStrPlural); i++ {
- fmt.Fprintf(&buf, "msgstr[%d] %s", i, encodePoString(p.MsgStrPlural[i]))
- }
- return buf.String()
- }
|