From 5fc4bc106a7617a3615475bb28db8ff780a71b3e Mon Sep 17 00:00:00 2001 From: youthlin Date: Fri, 5 Jan 2024 17:12:53 +0800 Subject: [PATCH] sort entry --- testdata/messages.new.pot | 64 +++++++++++++++++++++++++++++++++++++++ testdata/messages.pot | 64 +++++++++++++++++++++++++++++++++++++++ translator/entry.go | 42 +++++++++++++++++++++++++ translator/file.go | 2 +- translator/file_test.go | 20 ++++++++++++ translator/po.go | 10 +++++- 6 files changed, 200 insertions(+), 2 deletions(-) create mode 100755 testdata/messages.new.pot create mode 100755 testdata/messages.pot diff --git a/testdata/messages.new.pot b/testdata/messages.new.pot new file mode 100755 index 0000000..6f8bbca --- /dev/null +++ b/testdata/messages.new.pot @@ -0,0 +1,64 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-01-05 16:04:11+0800\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" +"X-Created-By: xtpl(https://github.com/pub-go/tpl/tree/main/cmd/xtpl)\n" +"X-xTpl-Path: .\n" +"X-xTpl-Pattern: .*\\.html\n" +"X-xTpl-Keywords: T;N:1,2;N64:1,2;X:1c,2;XN:1c,2,3;XN64:1c,2,3;__;_n:1,2;_x:1c,2;_xn:1c,2,3\n" +"X-xTpl-Output: testdata/messages.pot\n" + +#: testdata/index.html:6:24 +msgid "Title" +msgstr "" + +#: testdata/index.html:9:21 +msgid "How are you?" +msgstr "" + +#: testdata/index.html:11:23 +msgid "And you?" +msgstr "" + +#: testdata/index.html:12:20 +msgid "Hello, %s" +msgstr "" + +#: testdata/index.html:13:32 +msgctxt "post new" +msgid "Post" +msgstr "" + +#: testdata/index.html:14:29 +msgctxt "posts" +msgid "Post" +msgstr "" + +#: testdata/index.html:15:20 +msgid "One Apple" +msgid_plural "%d Apples" +msgstr[0] "" +msgstr[1] "" + +#: testdata/index.html:16:28 +msgctxt "ctx" +msgid "One Book" +msgid_plural "%d Books" +msgstr[0] "" +msgstr[1] "" + diff --git a/testdata/messages.pot b/testdata/messages.pot new file mode 100755 index 0000000..ff95de3 --- /dev/null +++ b/testdata/messages.pot @@ -0,0 +1,64 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-01-05 16:04:11+0800\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" +"X-Created-By: xtpl(https://github.com/pub-go/tpl/tree/main/cmd/xtpl)\n" +"X-xTpl-Path: .\n" +"X-xTpl-Pattern: .*\\.html\n" +"X-xTpl-Keywords: T;N:1,2;N64:1,2;X:1c,2;XN:1c,2,3;XN64:1c,2,3;__;_n:1,2;_x:1c,2;_xn:1c,2,3\n" +"X-xTpl-Output: testdata/messages.pot\n" + +#: testdata/index.html:11:23 +msgid "And you?" +msgstr "" + +#: testdata/index.html:12:20 +msgid "Hello, %s" +msgstr "" + +#: testdata/index.html:9:21 +msgid "How are you?" +msgstr "" + +#: testdata/index.html:15:20 +msgid "One Apple" +msgid_plural "%d Apples" +msgstr[0] "" +msgstr[1] "" + +#: testdata/index.html:6:24 +msgid "Title" +msgstr "" + +#: testdata/index.html:16:28 +msgctxt "ctx" +msgid "One Book" +msgid_plural "%d Books" +msgstr[0] "" +msgstr[1] "" + +#: testdata/index.html:13:32 +msgctxt "post new" +msgid "Post" +msgstr "" + +#: testdata/index.html:14:29 +msgctxt "posts" +msgid "Post" +msgstr "" + diff --git a/translator/entry.go b/translator/entry.go index c76d835..8fc8d0e 100644 --- a/translator/entry.go +++ b/translator/entry.go @@ -1,5 +1,11 @@ package translator +import ( + "fmt" + "strconv" + "strings" +) + // Entry 一个翻译条目 type Entry struct { MsgCmts []string @@ -25,3 +31,39 @@ func (e *Entry) isValid() bool { // header entry: msgid == "" return e != nil && (e.MsgStr != "" || len(e.MsgStrN) > 0) } + +// getSortKey 排序 +func (e *Entry) getSortKey() string { + if e.isHeader() { + return "" // 排在最前 + } + return e.getLineString() + e.Key() +} + +// getLineString 如果有行号注释按行号排序 非行号的注释不使用 +func (e *Entry) getLineString() string { + var ss []string + for _, cmt := range e.MsgCmts { + // #: testdata/index.html:16:28 testdata/index.html:18 + if strings.HasPrefix(cmt, "#:") { // 行号注释前缀 + cmt = strings.TrimPrefix(cmt, "#:") + var s []string + s = append(s, "#:") + for _, item := range strings.Split(cmt, " ") { // 多个位置 + pair := strings.Split(item, ":") // 文件名:行号[:列号] + result := make([]string, 0, len(pair)) + for _, n := range pair { + i, err := strconv.ParseInt(n, 10, 64) + if err != nil { + result = append(result, n) + } else { // 数字添加前导 0,这样字符串比较时 012<123 + result = append(result, fmt.Sprintf("%10d", i)) + } + } + s = append(s, result...) + } + ss = append(ss, s...) + } + } + return strings.Join(ss, "") +} diff --git a/translator/file.go b/translator/file.go index fff4022..677aa9a 100644 --- a/translator/file.go +++ b/translator/file.go @@ -66,7 +66,7 @@ func (file *File) SortedEntry() (entries []*Entry) { sort.Slice(entries, func(i, j int) bool { left := entries[i] right := entries[j] - return left.Key() < right.Key() + return left.getSortKey() < right.getSortKey() }) return } diff --git a/translator/file_test.go b/translator/file_test.go index f8df0ae..5e52ace 100644 --- a/translator/file_test.go +++ b/translator/file_test.go @@ -1,6 +1,7 @@ package translator import ( + "os" "testing" ) @@ -231,3 +232,22 @@ func TestFile_N(t *testing.T) { }) } } + +func TestSortedEntry(t *testing.T) { + content, err := os.ReadFile("../testdata/messages.pot") + if err != nil { + t.Fatalf("read file failed: %v", err) + } + f, err := ReadPot(content) + if err != nil { + t.Fatalf("read .po failed: %v", err) + } + w, err := os.OpenFile("../testdata/messages.new.pot", os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0777) + if err != nil { + t.Fatalf("open save file failed: %v", err) + } + err = f.SaveAsPot(w) + if err != nil { + t.Fatalf("save file failed: %v", err) + } +} diff --git a/translator/po.go b/translator/po.go index 777af3c..ded5627 100644 --- a/translator/po.go +++ b/translator/po.go @@ -16,6 +16,14 @@ var errEmptyPo = fmt.Errorf("empty po file") // ReadPo read po file func ReadPo(content []byte) (*File, error) { + return readPo(content, false) +} + +func ReadPot(content []byte) (*File, error) { + return readPo(content, true) +} + +func readPo(content []byte, pot bool) (*File, error) { if len(content) == 0 { return nil, errors.Wrapf(errEmptyPo, "read po file failed") } @@ -25,7 +33,7 @@ func ReadPo(content []byte) (*File, error) { file := new(File) for { entry, err := readEntry(r) - if entry.isValid() { + if pot || entry.isValid() { file.AddEntry(entry) } if errors.Is(err, io.EOF) {