You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@answer.apache.org by li...@apache.org on 2026/02/05 08:17:42 UTC
(answer) 01/01: fix: enhance bracket handling in formatting and add concurrency test for internationalization
This is an automated email from the ASF dual-hosted git repository.
linkinstar pushed a commit to branch dev
in repository https://gitbox.apache.org/repos/asf/answer.git
commit 638fb082c56431397a3c63d00f3fc57c6b57f08d
Author: LinkinStars <li...@foxmail.com>
AuthorDate: Thu Feb 5 16:17:32 2026 +0800
fix: enhance bracket handling in formatting and add concurrency test for internationalization
---
pkg/day/day.go | 21 +++++++++++++--
pkg/day/day_test.go | 78 +++++++++++++++++++++++++++++++++++++++++++++++++----
2 files changed, 92 insertions(+), 7 deletions(-)
diff --git a/pkg/day/day.go b/pkg/day/day.go
index 2fd86a6c..797da68b 100644
--- a/pkg/day/day.go
+++ b/pkg/day/day.go
@@ -174,13 +174,30 @@ func nextStdChunk(from []rune) (to, suffix []rune) {
case "a":
old = "a"
case "[":
- if len(from) >= 4 && string(from[:4]) == "[at]" {
- old = "[at]"
+ // treat anything inside [] as literal text, e.g. [at], [a las], [o]
+ end := -1
+ for i := 1; i < len(from); i++ {
+ if from[i] == ']' {
+ end = i
+ break
+ }
+ }
+ if end != -1 {
+ to = []rune(string(from[1:end]))
+ suffix = from[end+1:]
+ return
}
+ // no closing bracket, fall back to literal "["
+ old = "["
default:
old = s
}
+ if old == "" {
+ // safety: always consume at least one rune
+ old = s
+ }
+
tos, ok := placeholder[old]
if !ok {
to = []rune(old)
diff --git a/pkg/day/day_test.go b/pkg/day/day_test.go
index 4f945d88..1ff75766 100644
--- a/pkg/day/day_test.go
+++ b/pkg/day/day_test.go
@@ -20,17 +20,85 @@
package day
import (
+ "os"
+ "path/filepath"
+ "runtime"
"testing"
"time"
"github.com/stretchr/testify/assert"
+ "gopkg.in/yaml.v3"
)
func TestFormat(t *testing.T) {
- sec := time.Now().Unix()
- tz := "Asia/Shanghai"
- actual := Format(sec, "YYYY-MM-DD HH:mm:ss", tz)
- _, _ = time.LoadLocation(tz)
- expected := time.Unix(sec, 0).Format("2006-01-02 15:04:05")
+ sec := int64(1700000000)
+ tz := "UTC"
+
+ actual := Format(sec, "MMM D, YYYY [a las] HH:mm", tz)
+ expected := time.Unix(sec, 0).Format("Jan 2, 2006") + " a las " + time.Unix(sec, 0).Format("15:04")
assert.Equal(t, expected, actual)
}
+
+func TestFormat_AllLanguagesNoHang(t *testing.T) {
+ _, currentFile, _, ok := runtime.Caller(0)
+ if !ok {
+ t.Fatalf("unable to determine test file path")
+ }
+ i18nDir := filepath.Clean(filepath.Join(filepath.Dir(currentFile), "..", "..", "i18n"))
+ entries, err := os.ReadDir(i18nDir)
+ if err != nil {
+ t.Fatalf("read i18n dir: %v", err)
+ }
+
+ type datesConfig struct {
+ LongDate string `yaml:"long_date"`
+ LongDateWithYear string `yaml:"long_date_with_year"`
+ LongDateWithTime string `yaml:"long_date_with_time"`
+ }
+ type uiConfig struct {
+ Dates datesConfig `yaml:"dates"`
+ }
+ type fileConfig struct {
+ UI uiConfig `yaml:"ui"`
+ }
+
+ sec := int64(1700000000)
+ tz := "UTC"
+
+ for _, entry := range entries {
+ name := entry.Name()
+ if entry.IsDir() || filepath.Ext(name) != ".yaml" || name == "i18n.yaml" {
+ continue
+ }
+ data, err := os.ReadFile(filepath.Join(i18nDir, name))
+ if err != nil {
+ t.Fatalf("read %s: %v", name, err)
+ }
+ var cfg fileConfig
+ if err := yaml.Unmarshal(data, &cfg); err != nil {
+ t.Fatalf("parse %s: %v", name, err)
+ }
+
+ formats := []string{
+ cfg.UI.Dates.LongDate,
+ cfg.UI.Dates.LongDateWithYear,
+ cfg.UI.Dates.LongDateWithTime,
+ }
+ for _, format := range formats {
+ if format == "" {
+ continue
+ }
+ done := make(chan struct{})
+ go func(f string) {
+ _ = Format(sec, f, tz)
+ close(done)
+ }(format)
+
+ select {
+ case <-done:
+ case <-time.After(200 * time.Millisecond):
+ t.Fatalf("format hang in %s: %q", name, format)
+ }
+ }
+ }
+}