Split into category packages; module github.com/ZacharyZhang-NY/MujicaUI

This commit is contained in:
ZacharyZhang-NY committed 2026-10-05 16:18:48 -04:00
1 parent 5a7e921c7e
commit 22b53e9e9e
1822 files changed
+24568 -21314

No files matched your search

+56
View File
@@ -0,0 +1,56 @@
package core
import (
"testing"
"github.com/egoist/mygo/ui"
)
// TestBasesBlockedByDisabledWrapper flips a focused MyGo base's wrapper to Disabled in the frame Space arrives.
func TestBasesBlockedByDisabledWrapper(t *testing.T) {
for name, base := range map[string]func(c *ui.Context, on *bool) *ui.Element{
"CheckboxBase": func(c *ui.Context, on *bool) *ui.Element { return ui.CheckboxBase(c, on) },
"RadioBase": func(c *ui.Context, on *bool) *ui.Element { return ui.RadioBase(c, on, true) },
"SwitchBase": func(c *ui.Context, on *bool) *ui.Element { return ui.SwitchBase(c, on) },
"ToggleBase": func(c *ui.Context, on *bool) *ui.Element { return ui.ToggleBase(c, on) },
} {
for _, disable := range []bool{false, true} {
on, off := false, false
tt := ui.NewTester(func(c *ui.Context) {
ui.Row(c).Disabled(off).Children(func() {
base(c, &on).Label("Target").Size(40, 20)
})
}, 200, 100)
tt.Key(0, ui.KeyTab)
if !tt.Focused("Target") {
t.Fatalf("%s: not focused", name)
}
off = disable
tt.Key(0, ui.KeySpace)
tt.Frame()
if on == disable {
t.Errorf("%s: disabled=%v, Space left the value %v", name, disable, on)
}
}
}
}
// TestComboboxBaseIgnoresDisabledWrapper shows why Combobox hands its base a copy: a focused one still takes typing.
func TestComboboxBaseIgnoresDisabledWrapper(t *testing.T) {
q, off := "", false
tt := ui.NewTester(func(c *ui.Context) {
ui.Row(c).Disabled(off).Children(func() {
ui.ComboboxBase(c, &q).Input.Label("Target").Width(120)
})
}, 200, 100)
tt.Key(0, ui.KeyTab)
if !tt.Focused("Target") {
t.Fatal("not focused")
}
off = true
tt.Type("a")
tt.Frame()
if q != "a" {
t.Fatalf("typing left %q; the wrapper now blocks it and Combobox can drop its copy", q)
}
}
+17
View File
@@ -0,0 +1,17 @@
package core
import (
"github.com/egoist/mygo/ui"
)
// ChoiceResult is a choice control's element and whether its value changed this frame.
type ChoiceResult struct {
Element *ui.Element
changed bool
}
// Changed reports whether the user changed the value in this frame.
func (r ChoiceResult) Changed() bool { return r.changed }
// NewChoiceResult reports e and whether its value changed this frame.
func NewChoiceResult(e *ui.Element, changed bool) ChoiceResult { return ChoiceResult{e, changed} }
+180
View File
@@ -0,0 +1,180 @@
package core
import (
"fmt"
"log/slog"
"time"
"github.com/egoist/mygo/ui"
"github.com/ZacharyZhang-NY/MujicaUI/icons"
"github.com/ZacharyZhang-NY/MujicaUI/internal"
"github.com/ZacharyZhang-NY/MujicaUI/theme"
)
// Date is a calendar day without clock or location; zero means none.
type Date struct {
Year int
Month time.Month
Day int
}
// DateOf returns the day t falls on in t's own location, without converting it.
func DateOf(t time.Time) Date {
y, m, d := t.Date()
return Date{y, m, d}
}
// IsZero reports whether d is the empty date.
func (d Date) IsZero() bool { return d == Date{} }
// Valid reports whether d names a real day.
func (d Date) Valid() bool { return !d.IsZero() && DateOf(d.Civil()) == d }
// String formats d as 2006-01-02, or "" when empty.
func (d Date) String() string {
if d.IsZero() {
return ""
}
return fmt.Sprintf("%04d-%02d-%02d", d.Year, d.Month, d.Day)
}
// Format formats d with a Go time layout.
func (d Date) Format(layout string) string { return d.Civil().Format(layout) }
// Compare returns -1, 0 or 1 as d is before, equal to or after o.
func (d Date) Compare(o Date) int { return d.Civil().Compare(o.Civil()) }
// AddDays returns d moved by n days.
func (d Date) AddDays(n int) Date { return DateOf(d.Civil().AddDate(0, 0, n)) }
// AddMonths returns d moved by n months, keeping the day within the month.
func (d Date) AddMonths(n int) Date {
first := time.Date(d.Year, d.Month+time.Month(n), 1, 0, 0, 0, 0, time.UTC)
last := first.AddDate(0, 1, -1).Day()
return Date{first.Year(), first.Month(), min(d.Day, last)}
}
// Weekday returns the day of the week of d.
func (d Date) Weekday() time.Weekday { return d.Civil().Weekday() }
// Civil is d at midnight on a fixed clock, only for arithmetic.
func (d Date) Civil() time.Time { return time.Date(d.Year, d.Month, d.Day, 0, 0, 0, 0, time.UTC) }
// Within reports whether d lies inside the optional bounds lo and hi.
func (d Date) Within(lo, hi Date) bool {
return (lo.IsZero() || d.Compare(lo) >= 0) && (hi.IsZero() || d.Compare(hi) <= 0)
}
// DatetimeCheckDate panics when a non-empty date is not a real day.
func DatetimeCheckDate(name string, d Date) {
if !d.IsZero() && !d.Valid() {
panic(fmt.Sprintf("mujica: %s %v is not a calendar date", name, d))
}
}
// DatetimeCheckBounds panics on invalid or inverted Min and Max.
func DatetimeCheckBounds(name string, lo, hi Date) {
DatetimeCheckDate(name+" Min", lo)
DatetimeCheckDate(name+" Max", hi)
if !lo.IsZero() && !hi.IsZero() && lo.Compare(hi) > 0 {
panic(fmt.Sprintf("mujica: %s Min %v is after Max %v", name, lo, hi))
}
}
// DatetimeToday returns today, or the caller's fixed day when set.
func DatetimeToday(c *ui.Context, fixed Date) Date {
if !fixed.IsZero() {
DatetimeCheckDate("Today", fixed)
return fixed
}
return DateOf(c.Now())
}
// DatetimeMonthName returns the localized name of m.
func DatetimeMonthName(c *ui.Context, m time.Month) string {
return Msg(c, fmt.Sprintf("calendar.month_%d", int(m)))
}
// DatetimeMonthTitle returns the localized title of a month, as "October 2026".
func DatetimeMonthTitle(c *ui.Context, y int, m time.Month) string {
return fmt.Sprintf(Msg(c, "calendar.title"), DatetimeMonthName(c, m), y)
}
// DatetimeDayLabel returns the localized spoken name of d.
func DatetimeDayLabel(c *ui.Context, d Date) string {
wd := Msg(c, fmt.Sprintf("calendar.weekday_long_%d", int(d.Weekday())))
return fmt.Sprintf(Msg(c, "calendar.day_label"), wd, DatetimeMonthName(c, d.Month), d.Day, d.Year)
}
// DatetimeField styles row as a single-line field: solid fill and fine border.
func DatetimeField(c *ui.Context, row *ui.Element, invalid, readOnly bool) *ui.Element {
k := Tokens(c)
d := Density(c)
bg, border := k.Surface, k.ControlBorder
switch {
case invalid:
border = k.Danger
case readOnly:
bg, border = k.Background, k.Border
case row.FocusWithin():
border = k.Focus
case row.Hovered():
border = k.Text
}
return row.MinHeight(d.ControlHeight()).Padding(0, d.Unit()).PaddingX(d.Unit()*3).Gap(d.Unit()).
AlignItems(ui.Center).Radius(theme.ControlRadius).Background(bg).Border(theme.BorderWidth, border)
}
// DatetimeTrigger is the popup button inside a field; Cmd+C copies its text.
func DatetimeTrigger(c *ui.Context, text, placeholder, icon string) *ui.Element {
k := Tokens(c)
b := ui.ButtonBase(c).Grow(1).Shrink(1).Justify(ui.Start).Gap(Density(c).Unit() * 2).
MinHeight(theme.MinHitSize).Radius(theme.ControlRadius).Role(ui.RolePopUpButton)
internal.Ring(b, k.Focus, theme.ControlRadius)
if b.Shortcut(ui.Cmd, ui.KeyC) && text != "" {
c.WriteClipboard(text)
}
b.Children(func() {
ui.Icon(c, icons.Must(icon)).Size(16, 16).TextColor(k.TextMuted)
if text == "" {
ui.Text(c, placeholder).TextColor(k.TextMuted).SingleLine()
} else {
ui.Text(c, text).TextColor(k.Text).SingleLine().FontFeatures("tnum")
}
})
return b
}
// DatetimePopup shows fn below anchor while *open; a disabled or read-only anchor closes it.
func DatetimePopup(c *ui.Context, anchor *ui.Element, open *bool, readOnly bool, fn func()) *ui.Element {
d := Density(c)
if *open && (readOnly || anchor.IsDisabled()) {
slog.Debug("mujica: datetime popup closed by state", "readOnly", readOnly)
*open = false
}
return ui.PopoverBase(c, anchor, open, func(panel *ui.Element) {
OverlayStyle(c, panel, OverlayEnter(c, panel))
panel.MaxWidth(d.ControlHeight()*7+d.Unit()*6+2*theme.BorderWidth).Margin(d.Unit(), 0, 0, 0).Padding(d.Unit() * 3).Gap(d.Unit() * 3)
fn()
})
}
// DatetimeSelectedMark strokes the 1 DIP inset frame that marks a chosen cell.
func DatetimeSelectedMark(p *ui.Painter, r ui.Rect, c ui.Color) {
const inset = 2
p.Stroke(ui.Rect{X: r.X + inset, Y: r.Y + inset, W: r.W - 2*inset, H: r.H - 2*inset}, c, theme.ControlRadius/2, theme.BorderWidth)
}
// DatetimeError shows a field error in Danger beneath a control.
func DatetimeError(c *ui.Context, text string) {
if text == "" {
return
}
ui.Text(c, text).FontSize(FontSize(c, theme.CaptionSize)).TextColor(Tokens(c).Danger).Role(ui.RoleStatus)
}
// DatetimeFooter lays out popup actions at the end of a row.
func DatetimeFooter(c *ui.Context, fn func()) {
ui.Row(c).Gap(Density(c).Unit() * 2).Justify(ui.End).AlignItems(ui.Center).FillWidth().Children(fn)
}
+109
View File
@@ -0,0 +1,109 @@
package core
import (
"os"
"path/filepath"
"regexp"
"strings"
"testing"
)
var (
docsGoBlock = regexp.MustCompile("(?s)```go\n(.*?)```")
docsSpace = regexp.MustCompile(`\s+`)
docsPageID = regexp.MustCompile(`ID: "(\d{3})"`)
)
// docsLines normalizes code into its non-empty, non-comment lines without whitespace.
func docsLines(code string) []string {
var out []string
for _, l := range strings.Split(code, "\n") {
s := strings.TrimSpace(l)
if s != "" && !strings.HasPrefix(s, "//") {
out = append(out, docsSpace.ReplaceAllString(s, ""))
}
}
return out
}
// docsContains reports whether want appears in order inside have.
func docsContains(have, want []string) bool {
i := 0
for _, h := range have {
if i < len(want) && h == want[i] {
i++
}
}
return i == len(want)
}
func readGlob(t *testing.T, pattern string) map[string]string {
t.Helper()
files, err := filepath.Glob(pattern)
if err != nil {
t.Fatal(err)
}
out := map[string]string{}
for _, f := range files {
b, err := os.ReadFile(f)
if err != nil {
t.Fatal(err)
}
out[f] = string(b)
}
return out
}
// TestDocSnippetsAreCompiledExamples keeps each doc's first Go block, in order, inside one Example.
func TestDocSnippetsAreCompiledExamples(t *testing.T) {
var examples [][]string
for _, src := range readGlob(t, "../*/example_*_test.go") {
for _, fn := range strings.Split(src, "\nfunc Example")[1:] {
examples = append(examples, docsLines(fn))
}
}
for d, src := range readGlob(t, "../docs/components/*.md") {
m := docsGoBlock.FindStringSubmatch(src)
if m == nil {
t.Errorf("%s has no Go example", d)
continue
}
want, found := docsLines(m[1]), false
for _, ex := range examples {
if docsContains(ex, want) {
found = true
break
}
}
if !found {
t.Errorf("%s: its Go block is not, in order, inside any compiled Example", d)
}
}
}
// TestDocsMatchGalleryPages wants exactly one doc and one gallery page per component ID.
func TestDocsMatchGalleryPages(t *testing.T) {
if n := len(readGlob(t, "../docs/components/*.md")); n != 318 {
t.Fatalf("component docs = %d, want 318", n)
}
pages := map[string]int{}
for _, src := range readGlob(t, "../examples/gallery/pages_*.go") {
for _, m := range docsPageID.FindAllStringSubmatch(src, -1) {
pages[m[1]]++
}
}
docs := map[string]int{}
for d := range readGlob(t, "../docs/components/*.md") {
docs[filepath.Base(d)[:3]]++
}
for id, n := range pages {
if n != 1 || docs[id] != 1 {
t.Errorf("component %s: %d gallery pages, %d docs; want 1 and 1", id, n, docs[id])
}
}
for id, n := range docs {
if pages[id] == 0 {
t.Errorf("doc %s (%d files) has no gallery page", id, n)
}
}
}
+15
View File
@@ -0,0 +1,15 @@
package core_test
import (
"github.com/egoist/mygo/ui"
"github.com/ZacharyZhang-NY/MujicaUI/core"
)
func ExampleSpinner() {
view := func(c *ui.Context) {
core.Use(c, core.Settings{})
core.Spinner(c, core.SpinnerOptions{Size: 20, Label: "Syncing", ShowLabel: true})
}
ui.Render(view, 400, 300, 1)
}
+28
View File
@@ -0,0 +1,28 @@
package core
import (
"math"
"github.com/egoist/mygo/ui"
"github.com/ZacharyZhang-NY/MujicaUI/internal"
)
// ProgressArc is the arc from turn a to turn b, clockwise from twelve o'clock.
func ProgressArc(pt *ui.Painter, cx, cy, r float32, a, b float32) *ui.Path {
var p ui.Path
n := max(2, int(math.Ceil(float64((b-a)*64))))
for i := 0; i <= n; i++ {
t := float64(a + (b-a)*float32(i)/float32(n))
x := cx + r*float32(math.Sin(2*math.Pi*t))
y := cy - r*float32(math.Cos(2*math.Pi*t))
if i == 0 {
p.MoveTo(internal.Snap(pt, x), internal.Snap(pt, y))
} else {
p.LineTo(internal.Snap(pt, x), internal.Snap(pt, y))
}
}
return &p
}
func Abs32(v float32) float32 { return float32(math.Abs(float64(v))) }
+49
View File
@@ -0,0 +1,49 @@
package core
import (
"github.com/egoist/mygo/ui"
)
// Locale picks the built-in copy. The zero value is English.
type Locale string
const (
EnUS Locale = "en-US"
ZhCN Locale = "zh-CN"
)
// messages maps a key to its English and Chinese copy.
var messages = map[string][2]string{}
func addMessages(m map[string][2]string) {
for k, v := range m {
if _, dup := messages[k]; dup {
panic("mujica: duplicate message " + k)
}
messages[k] = v
}
}
// Msg returns the window's copy for key.
func Msg(c *ui.Context, key string) string {
w := current(c)
if s, ok := w.messages[key]; ok {
return s
}
m, ok := messages[key]
if !ok {
panic("mujica: unknown message " + key)
}
if w.locale == ZhCN {
return m[1]
}
return m[0]
}
// CurrentLocale returns the window's locale.
func CurrentLocale(c *ui.Context) Locale {
if l := current(c).locale; l != "" {
return l
}
return EnUS
}
+23
View File
@@ -0,0 +1,23 @@
package core
import (
"github.com/egoist/mygo/ui"
"github.com/ZacharyZhang-NY/MujicaUI/internal"
"github.com/ZacharyZhang-NY/MujicaUI/theme"
)
// IconAction is a square, borderless button showing icon, named label.
func IconAction(c *ui.Context, icon *ui.SVG, label string) *ui.Element {
k := Tokens(c)
b := ui.ButtonBase(c).Size(theme.MinHitSize, theme.MinHitSize).Radius(theme.ControlRadius).Label(label).TextColor(k.TextMuted)
internal.Ring(b, k.Focus, theme.ControlRadius)
switch {
case b.Pressed():
b.Background(k.Selection).TextColor(k.Text)
case b.Hovered():
b.Background(k.SurfaceHover).TextColor(k.Text)
}
b.Children(func() { ui.Icon(c, icon).Size(16, 16) })
return b
}
+44
View File
@@ -0,0 +1,44 @@
package core
import (
"image"
"image/color"
"testing"
"github.com/egoist/mygo/ui"
)
// mediaTestImage is a w×h picture whose left half is wine and right half ivory.
func mediaTestImage(w, h int) *image.RGBA {
img := image.NewRGBA(image.Rect(0, 0, w, h))
for y := range h {
for x := range w {
c := color.RGBA{125, 32, 52, 255}
if x >= w/2 {
c = color.RGBA{242, 235, 221, 255}
}
if y < h/8 {
c = color.RGBA{173, 145, 100, 255}
}
img.Set(x, y, c)
}
}
return img
}
func mediaTestBitmap(w, h int) *ui.Bitmap { return ui.NewBitmap(mediaTestImage(w, h)) }
// mediaPanics fails t unless fn panics.
func mediaPanics(t *testing.T, name string, fn func(c *ui.Context)) {
t.Helper()
defer func() {
if recover() == nil {
t.Errorf("%s: no panic", name)
}
}()
tt := ui.NewTester(func(c *ui.Context) {
Use(c, Settings{})
fn(c)
}, 400, 300)
tt.Frame()
}
+53
View File
@@ -0,0 +1,53 @@
package core
import (
"fmt"
"time"
"github.com/egoist/mygo/ui"
)
// MediaSVG wraps stroked 24×24 path data as an icon.
func MediaSVG(body string) *ui.SVG {
return ui.MustParseSVG([]byte(`<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">` + body + `</svg>`))
}
// Media glyphs drawn for this group.
var (
MediaPlay = MediaSVG(`<path d="M7 4.5v15l12-7.5z"/>`)
MediaPause = MediaSVG(`<path d="M8 5v14M16 5v14"/>`)
MediaPrev = MediaSVG(`<path d="M18 5v14L8 12zM6 5v14"/>`)
MediaNext = MediaSVG(`<path d="M6 5v14l10-7zM18 5v14"/>`)
MediaRepeat = MediaSVG(`<path d="M17 3l3 3-3 3M4 11V9a3 3 0 0 1 3-3h13M7 21l-3-3 3-3M20 13v2a3 3 0 0 1-3 3H4"/>`)
MediaRepeatOne = MediaSVG(`<path d="M17 3l3 3-3 3M4 11V9a3 3 0 0 1 3-3h13M7 21l-3-3 3-3M20 13v2a3 3 0 0 1-3 3H4M11 10h1v4"/>`)
MediaShuffle = MediaSVG(`<path d="M16 3h5v5M4 20 21 3M21 16v5h-5M15 15l6 6M4 4l5 5"/>`)
MediaVolume = MediaSVG(`<path d="M11 5 6 9H3v6h3l5 4zM15.5 8.5a5 5 0 0 1 0 7M18.5 5.5a9 9 0 0 1 0 13"/>`)
MediaMute = MediaSVG(`<path d="M11 5 6 9H3v6h3l5 4zM16 9l6 6M22 9l-6 6"/>`)
MediaRotate = MediaSVG(`<path d="M21 12a9 9 0 1 1-3-6.7L21 8M21 3v5h-5"/>`)
MediaRotateLeft = MediaSVG(`<path d="M3 12a9 9 0 1 0 3-6.7L3 8M3 3v5h5"/>`)
MediaMirror = MediaSVG(`<path d="M12 3v18M8 7 3 12l5 5zM16 7l5 5-5 5z"/>`)
MediaPiP = MediaSVG(`<rect x="2" y="4" width="20" height="16" rx="2"/><rect x="12" y="12" width="7" height="5" rx="1"/>`)
MediaFullscreen = MediaSVG(`<path d="M3 8V3h5M16 3h5v5M21 16v5h-5M8 21H3v-5"/>`)
MediaCaptions = MediaSVG(`<rect x="2" y="5" width="20" height="14" rx="2"/><path d="M10 10.5a2 2 0 1 0 0 3M17 10.5a2 2 0 1 0 0 3"/>`)
MediaRecord = MediaSVG(`<circle cx="12" cy="12" r="6" fill="currentColor"/>`)
MediaStop = MediaSVG(`<rect x="6" y="6" width="12" height="12" rx="1" fill="currentColor"/>`)
MediaMic = MediaSVG(`<rect x="9" y="2" width="6" height="12" rx="3"/><path d="M5 10a7 7 0 0 0 14 0M12 17v5M8 22h8"/>`)
MediaCamera = MediaSVG(`<rect x="2" y="6" width="14" height="12" rx="2"/><path d="m16 10 6-4v12l-6-4z"/>`)
MediaSpeaker = MediaSVG(`<rect x="5" y="2" width="14" height="20" rx="2"/><circle cx="12" cy="14" r="4"/><path d="M12 6h.01"/>`)
MediaRect = MediaSVG(`<rect x="4" y="6" width="16" height="12" rx="1"/>`)
MediaArrow = MediaSVG(`<path d="M5 19 19 5M10 5h9v9"/>`)
MediaText = MediaSVG(`<path d="M5 6V4h14v2M12 4v16M9 20h6"/>`)
MediaPointer = MediaSVG(`<path d="M5 3l14 7-6 2-2 6z"/>`)
)
// MediaClock writes d as m:ss, or h:mm:ss past an hour.
func MediaClock(d time.Duration) string {
if d < 0 {
d = 0
}
s := int(d / time.Second)
if s >= 3600 {
return fmt.Sprintf("%d:%02d:%02d", s/3600, s/60%60, s%60)
}
return fmt.Sprintf("%d:%02d", s/60, s%60)
}
+123
View File
@@ -0,0 +1,123 @@
package core
func init() {
addMessages(map[string][2]string{
"settings_layout.title": {"Settings", "设置"},
"settings_search.placeholder": {"Search settings", "搜索设置"},
"settings_search.none": {"No settings match", "没有匹配的设置"},
"theme_selector.label": {"Appearance", "外观"},
"theme_selector.System": {"System", "跟随系统"},
"theme_selector.Light": {"Light", "浅色"},
"theme_selector.Dark": {"Dark", "深色"},
"accent_color_picker.label": {"Accent color", "主色"},
"accent_color_picker.low": {"Low contrast", "对比度不足"},
"accent_color_picker.low_note": {"Marked colors are too faint for text on them.", "带标记的颜色对比度不足,不宜承载文字。"},
"accent_color_picker.chosen_low": {"%s has low contrast; text on it may be hard to read.", "%s 对比度不足,其上的文字可能难以阅读。"},
"shortcut_recorder.press": {"Press keys…", "请按下快捷键…"},
"shortcut_recorder.none": {"none", "未设置"},
"shortcut_recorder.conflict": {"%s is already used by %s", "%s 已被“%s”使用"},
"shortcut_recorder.needs_modifier": {"Add Ctrl, Alt or Command; F-keys may stand alone.", "请加上 Ctrl、Alt 或 Command;功能键可单独使用。"},
"keyboard_shortcuts_list.search": {"Search shortcuts", "搜索快捷键"},
"login_form.account": {"Email or username", "邮箱或用户名"},
"login_form.password": {"Password", "密码"},
"login_form.remember": {"Remember me", "记住我"},
"login_form.submit": {"Sign in", "登录"},
"oauth_buttons.continue": {"Continue with %s", "使用 %s 继续"},
"two_factor_input.label": {"Verification code", "验证码"},
"two_factor_input.resend": {"Resend code", "重新发送"},
"two_factor_input.resend_in": {"Resend in %d:%02d", "%d:%02d 后可重新发送"},
"profile_editor.avatar": {"Change picture", "更换头像"},
"profile_editor.name": {"Name", "名称"},
"profile_editor.bio": {"Bio", "简介"},
"profile_editor.unsaved": {"Unsaved changes", "有未保存的更改"},
"profile_editor.discard": {"Discard", "放弃更改"},
"profile_editor.save": {"Save", "保存"},
"account_switcher.accounts": {"Accounts", "账户"},
"account_switcher.add": {"Add account…", "添加账户…"},
"workspace_switcher.label": {"Workspaces", "工作区"},
"workspace_switcher.search": {"Find a workspace", "查找工作区"},
"workspace_switcher.none": {"No workspace matches", "没有匹配的工作区"},
"user_menu.label": {"%s, %s", "%s,%s"},
"user_menu.status0": {"Online", "在线"},
"user_menu.status1": {"Away", "离开"},
"user_menu.status2": {"Do not disturb", "勿扰"},
"user_menu.status3": {"Invisible", "隐身"},
"user_menu.settings": {"Settings", "设置"},
"user_menu.sign_out": {"Sign out", "退出登录"},
"session_list.label": {"Signed-in devices", "已登录设备"},
"session_list.current": {"This device", "本设备"},
"session_list.sign_out": {"Sign out", "注销"},
"session_list.sign_out_of": {"Sign out of %s", "注销 %s"},
"session_list.sign_out_others": {"Sign out of other sessions", "注销其他会话"},
"session_list.confirm_title": {"Sign out everywhere else?", "注销其他所有会话?"},
"session_list.confirm_text": {"%d other sessions will need to sign in again.", "其他 %d 个会话需要重新登录。"},
"session_list.now": {"Active now", "当前活跃"},
"session_list.unknown": {"Last active unknown", "最近活跃时间未知"},
"api_key_manager.create": {"Create key", "创建密钥"},
"api_key_manager.create_title": {"New API key", "新建 API 密钥"},
"api_key_manager.secret_title": {"Copy your new key", "复制新密钥"},
"api_key_manager.name": {"Key name", "密钥名称"},
"api_key_manager.cancel": {"Cancel", "取消"},
"api_key_manager.done": {"I've saved it", "我已保存"},
"api_key_manager.once": {"This key shows only once. Store it somewhere safe now.", "此密钥只显示一次,请立即妥善保存。"},
"api_key_manager.copy": {"Copy key", "复制密钥"},
"api_key_manager.copied": {"Key copied", "密钥已复制"},
"api_key_manager.empty": {"No API keys", "暂无 API 密钥"},
"api_key_manager.revoke": {"Revoke", "撤销"},
"api_key_manager.revoke_named": {"Revoke %s", "撤销 %s"},
"api_key_manager.revoke_title": {"Revoke %s?", "撤销 %s?"},
"api_key_manager.revoke_text": {"Apps using this key stop working at once.", "使用此密钥的应用将立即失效。"},
"api_key_manager.dates": {"Created %s · last used %s", "创建于 %s · 最近使用 %s"},
"api_key_manager.never": {"never", "从未"},
"usage_quota.amount": {"%s of %s %s", "%s / %s %s"},
"usage_quota.near": {"Near limit", "接近上限"},
"usage_quota.over": {"Limit reached", "已达上限"},
"usage_quota.reset_due": {"Resetting now", "正在重置"},
"usage_quota.reset_hours": {"Resets in %d h", "%d 小时后重置"},
"usage_quota.reset_on": {"Resets on %s", "%s 重置"},
"onboarding_wizard.progress": {"Setup progress", "引导进度"},
"onboarding_wizard.count": {"Step %d of %d", "第 %d 步,共 %d 步"},
"onboarding_wizard.skip": {"Skip", "跳过"},
"onboarding_wizard.back": {"Back", "上一步"},
"onboarding_wizard.next": {"Next", "下一步"},
"onboarding_wizard.finish": {"Finish", "完成"},
"coachmark.count": {"%d of %d", "%d / %d"},
"coachmark.skip": {"Skip tour", "跳过引导"},
"coachmark.back": {"Back", "上一步"},
"coachmark.next": {"Next", "下一步"},
"coachmark.done": {"Done", "完成"},
"whats_new_dialog.title": {"What's new", "更新内容"},
"whats_new_dialog.hide": {"Don't show again", "不再显示"},
"whats_new_dialog.close": {"Got it", "知道了"},
"whats_new_dialog.kind0": {"New", "新增"},
"whats_new_dialog.kind1": {"Improved", "改进"},
"whats_new_dialog.kind2": {"Fixed", "修复"},
"feedback_widget.kind": {"Feedback type", "反馈类型"},
"feedback_widget.kind0": {"Bug", "问题"},
"feedback_widget.kind1": {"Idea", "建议"},
"feedback_widget.kind2": {"Praise", "称赞"},
"feedback_widget.kind3": {"Other", "其他"},
"feedback_widget.message": {"Message", "内容"},
"feedback_widget.short": {"Write at least %d characters.", "请至少写 %d 个字。"},
"feedback_widget.send": {"Send feedback", "发送反馈"},
"feedback_widget.clear": {"Clear", "清空"},
})
}
+127
View File
@@ -0,0 +1,127 @@
package core
func init() {
addMessages(map[string][2]string{
"agent_status.pending": {"Pending", "待开始"},
"agent_status.planning": {"Planning", "规划中"},
"agent_status.running": {"Running", "执行中"},
"agent_status.waiting": {"Waiting", "等待中"},
"agent_status.done": {"Done", "已完成"},
"agent_status.failed": {"Failed", "失败"},
"agent_status.skipped": {"Skipped", "已跳过"},
"tool_call_card.args": {"Arguments", "参数"},
"tool_call_card.result": {"Result", "结果"},
"tool_call_card.error": {"Error", "错误"},
"tool_call_group.count": {"%d tool calls", "%d 次工具调用"},
"tool_call_group.failed": {"%d failed", "%d 次失败"},
"tool_approval_dialog.title": {"Allow this tool to run?", "允许运行此工具?"},
"tool_approval_dialog.tool": {"Tool", "工具"},
"tool_approval_dialog.allow": {"Allow", "允许"},
"tool_approval_dialog.deny": {"Deny", "拒绝"},
"permission_prompt.deny": {"Deny", "拒绝"},
"permission_prompt.always": {"Always allow", "始终允许"},
"permission_prompt.once": {"Allow once", "允许一次"},
"permission_prompt.scope": {"Always allowing covers", "始终允许的范围"},
"agent_step_list.current": {"Current", "当前"},
"agent_step_list.retry": {"Retry", "重试"},
"agent_progress.label": {"Progress", "进度"},
"sub_agent_tree.children": {"%d sub-agents", "%d 个子智能体"},
"file_change_card.stats": {"%d added, %d removed lines", "新增 %d 行,删除 %d 行"},
"file_change_card.pending": {"Pending", "待审阅"},
"file_change_card.accepted": {"Accepted", "已接受"},
"file_change_card.rejected": {"Rejected", "已拒绝"},
"file_change_card.new": {"New file", "新文件"},
"file_change_card.deleted": {"Deleted", "已删除"},
"file_change_card.open": {"Open diff", "打开差异"},
"file_change_card.undo": {"Undo", "撤销"},
"file_change_card.reject": {"Reject", "拒绝"},
"file_change_card.accept": {"Accept", "接受"},
"multi_file_diff_review.title": {"Review changes", "审阅变更"},
"multi_file_diff_review.progress": {"%d of %d files reviewed", "已审阅 %d / %d 个文件"},
"multi_file_diff_review.accept_all": {"Accept all", "全部接受"},
"multi_file_diff_review.empty": {"No changes to review", "没有需要审阅的变更"},
"command_execution_card.abort": {"Abort", "中止"},
"command_execution_card.exit": {"Exit %d", "退出码 %d"},
"command_execution_card.output": {"Output", "输出"},
"command_execution_card.no_output": {"No output", "没有输出"},
"screenshot_stream.label": {"Agent screen", "智能体画面"},
"screenshot_stream.waiting": {"Waiting for frames", "等待画面"},
"screenshot_stream.prev": {"Previous frame", "上一帧"},
"screenshot_stream.next": {"Next frame", "下一帧"},
"screenshot_stream.pause": {"Pause", "暂停"},
"screenshot_stream.live": {"Go live", "回到实时"},
"screenshot_stream.counter": {"Frame %d of %d", "第 %d / %d 帧"},
"screenshot_stream.following": {"Live", "实时"},
"artifact_panel.copy": {"Copy", "复制"},
"artifact_panel.copied": {"Copied", "已复制"},
"artifact_panel.export": {"Export", "导出"},
"artifact_panel.preview": {"Preview", "预览"},
"artifact_panel.source": {"Source", "源码"},
"artifact_version_switcher.label": {"Versions", "版本"},
"artifact_version_switcher.older": {"Older version", "较早版本"},
"artifact_version_switcher.newer": {"Newer version", "较新版本"},
"artifact_version_switcher.count": {"%d of %d", "%d / %d"},
"artifact_version_switcher.compare": {"Compare with %s", "与 %s 比较"},
"sandbox_status.starting": {"Starting", "启动中"},
"sandbox_status.running": {"Running", "运行中"},
"sandbox_status.stopped": {"Stopped", "已停止"},
"sandbox_status.failed": {"Failed", "故障"},
"sandbox_status.high": {"Near the limit", "接近上限"},
"sandbox_status.left": {"%s left", "剩余 %s"},
"sandbox_status.expired": {"Time is up", "已到时"},
"mcp_server_list.label": {"MCP servers", "MCP 服务器"},
"mcp_server_list.empty": {"No MCP servers", "没有 MCP 服务器"},
"mcp_server_list.stopped": {"Stopped", "已停止"},
"mcp_server_list.connecting": {"Connecting", "连接中"},
"mcp_server_list.connected": {"Connected", "已连接"},
"mcp_server_list.error": {"Connection failed", "连接失败"},
"mcp_server_list.tools": {"%d tools", "%d 个工具"},
"mcp_server_list.start": {"Start", "启动"},
"mcp_server_list.stop": {"Stop", "停止"},
"mcp_server_list.reconnect": {"Reconnect", "重新连接"},
"memory_panel.title": {"Memory", "记忆"},
"memory_panel.count": {"%d entries", "%d 条"},
"memory_panel.search": {"Search memory", "搜索记忆"},
"memory_panel.empty": {"No memories match", "没有匹配的记忆"},
"memory_panel.edit": {"Edit", "编辑"},
"memory_panel.save": {"Save", "保存"},
"memory_panel.cancel": {"Cancel", "取消"},
"memory_panel.delete": {"Delete", "删除"},
"memory_panel.confirm": {"Forget this memory?", "删除这条记忆?"},
"checkpoint_list.label": {"Checkpoints", "检查点"},
"checkpoint_list.empty": {"No checkpoints yet", "暂无检查点"},
"checkpoint_list.current": {"Current", "当前"},
"checkpoint_list.rollback": {"Roll back", "回滚"},
"checkpoint_list.confirm": {"Roll back to “%s”?", "回滚到“%s”?"},
"checkpoint_list.warning": {"Changes made after this checkpoint will be discarded.", "此检查点之后的更改将被丢弃。"},
"human_input_request.free": {"Or write your own answer", "或填写你的回答"},
"human_input_request.send": {"Send answer", "发送回答"},
"human_input_request.left": {"Answer within %s", "请在 %s 内回答"},
"human_input_request.timeout": {"The agent stopped waiting", "智能体已停止等待"},
"agent_plan.title": {"Plan", "计划"},
"agent_plan.progress": {"%d / %d done", "已完成 %d / %d"},
"agent_plan.doing": {"In progress", "进行中"},
"agent_plan.skip": {"Skip", "跳过"},
"agent_plan.restore": {"Restore", "恢复"},
"agent_plan.add": {"Add", "添加"},
"agent_plan.placeholder": {"Add a step", "新增一项"},
})
}
+195
View File
@@ -0,0 +1,195 @@
package core
import (
"fmt"
"github.com/egoist/mygo/ui"
)
// CalendarCount formats a count, using "_one" for one.
func CalendarCount(c *ui.Context, key string, n int) string {
if n == 1 {
key += "_one"
}
return fmt.Sprintf(Msg(c, key), n)
}
func init() {
addMessages(map[string][2]string{
"event_chip.all_day": {"All day", "全天"},
"event_chip.untitled": {"(No title)", "(无标题)"},
"attendee_list.label": {"Attendees", "参与者"},
"attendee_list.summary": {"%d accepted · %d maybe · %d declined · %d awaiting", "%d 人接受 · %d 人待定 · %d 人拒绝 · %d 人未回复"},
"attendee_list.empty": {"No attendees yet.", "暂无参与者。"},
"attendee_list.organizer": {"Organizer", "组织者"},
"attendee_list.optional": {"Optional", "可选"},
"attendee_list.remove": {"Remove %s", "移除 %s"},
"attendee_list.pending": {"Awaiting reply", "未回复"},
"attendee_list.accepted": {"Accepted", "已接受"},
"attendee_list.tentative": {"Maybe", "待定"},
"attendee_list.declined": {"Declined", "已拒绝"},
"recurrence_editor.label": {"Recurrence", "重复规则"},
"recurrence_editor.repeat": {"Repeat", "重复"},
"recurrence_editor.none": {"Does not repeat", "不重复"},
"recurrence_editor.daily": {"Daily", "每天"},
"recurrence_editor.weekly": {"Weekly", "每周"},
"recurrence_editor.monthly": {"Monthly", "每月"},
"recurrence_editor.yearly": {"Yearly", "每年"},
"recurrence_editor.custom": {"Custom", "自定义"},
"recurrence_editor.every": {"Every", "每"},
"recurrence_editor.interval": {"Interval", "间隔"},
"recurrence_editor.unit": {"Unit", "单位"},
"recurrence_editor.days": {"days", "天"},
"recurrence_editor.weeks": {"weeks", "周"},
"recurrence_editor.months": {"months", "个月"},
"recurrence_editor.years": {"years", "年"},
"recurrence_editor.on_days": {"On days", "重复于"},
"recurrence_editor.ends": {"Ends", "结束"},
"recurrence_editor.forever": {"Never", "永不"},
"recurrence_editor.after": {"After", "次数"},
"recurrence_editor.until": {"On date", "截止日期"},
"recurrence_editor.count": {"Occurrences", "重复次数"},
"recurrence_editor.until_date": {"End date", "结束日期"},
"recurrence_editor.no_days": {"Choose at least one day.", "请至少选择一天。"},
"recurrence_editor.bad_count": {"Repeat at least once.", "重复次数至少为 1。"},
"recurrence_editor.bad_until": {"The end date must not precede the start.", "结束日期不能早于开始日期。"},
"recurrence_editor.never": {"Does not repeat", "不重复"},
"recurrence_editor.every_n": {"Every %d %s", "每 %d %s"},
"recurrence_editor.on": {" on %s", ",于%s"},
"recurrence_editor.list_sep": {", ", "、"},
"recurrence_editor.times": {", %d times", ",共 %d 次"},
"recurrence_editor.times_one": {", %d time", ",共 %d 次"},
"recurrence_editor.until_text": {", until %v", ",至 %v"},
"reminder_picker.label": {"Reminders", "提醒"},
"reminder_picker.at_start": {"At start", "开始时"},
"reminder_picker.minutes": {"%d minutes before", "提前 %d 分钟"},
"reminder_picker.minutes_one": {"%d minute before", "提前 %d 分钟"},
"reminder_picker.hours": {"%d hours before", "提前 %d 小时"},
"reminder_picker.hours_one": {"%d hour before", "提前 %d 小时"},
"reminder_picker.days": {"%d days before", "提前 %d 天"},
"reminder_picker.days_one": {"%d day before", "提前 %d 天"},
"reminder_picker.weeks": {"%d weeks before", "提前 %d 周"},
"reminder_picker.weeks_one": {"%d week before", "提前 %d 周"},
"calendar_month_view.more": {"+%d", "+%d"},
"calendar_month_view.more_label": {"%d more events", "另有 %d 项"},
"calendar_month_view.more_label_one": {"%d more event", "另有 %d 项"},
"current_time_indicator.label": {"Now, %s", "当前时间 %s"},
"calendar_week_view.all_day": {"All day", "全天"},
"calendar_week_view.prev": {"Previous week", "上一周"},
"calendar_week_view.next": {"Next week", "下一周"},
"calendar_week_view.title": {"%[1]s %[2]d – %[3]s %[4]d, %[5]d", "%[5]d年%[1]s%[2]d日 – %[3]s%[4]d日"},
"calendar_week_view.resize": {"Resize %s", "调整 %s 的时长"},
"calendar_week_view.too_short": {"An event must end after it starts.", "结束时间须晚于开始时间。"},
"calendar_week_view.column": {"Schedule, %s", "%s 日程"},
"calendar_day_view.prev": {"Previous day", "前一天"},
"calendar_day_view.next": {"Next day", "后一天"},
"agenda_view.label": {"Agenda", "日程"},
"agenda_view.today": {"Today", "今天"},
"agenda_view.empty": {"No events in the next %d days.", "未来 %d 天没有日程。"},
"year_view.events": {"%d events", "%d 项日程"},
"year_view.events_one": {"%d event", "%d 项日程"},
"event_popover.close": {"Close", "关闭"},
"event_popover.edit": {"Edit", "编辑"},
"event_popover.delete": {"Delete", "删除"},
"event_popover.guests": {"%d guests", "%d 位参与者"},
"event_popover.guests_one": {"%d guest", "%d 位参与者"},
"week_picker.label": {"Week", "周"},
"week_picker.placeholder": {"Select week", "选择周"},
"duration_picker.label": {"Duration", "时长"},
"duration_picker.hours": {"Hours", "小时数"},
"duration_picker.minutes": {"Minutes", "分钟数"},
"duration_picker.seconds": {"Seconds", "秒数"},
"duration_picker.hours_unit": {"h", "小时"},
"duration_picker.minutes_unit": {"min", "分"},
"duration_picker.seconds_unit": {"s", "秒"},
"duration_picker.range": {"Choose a duration from %s to %s.", "请选择 %s 至 %s 之间的时长。"},
"timezone_select.label": {"Time zone", "时区"},
"timezone_select.placeholder": {"Select time zone", "选择时区"},
"timezone_select.search": {"Search city or offset", "搜索城市或偏移"},
"timezone_select.empty": {"No matching time zone.", "没有匹配的时区。"},
"timezone_select.common": {"Common", "常用"},
"timezone_select.all": {"All time zones", "全部时区"},
"availability_picker.label": {"Availability", "空闲时段"},
"availability_picker.mine": {"you are free", "你有空"},
"availability_picker.others": {"%d of %d others free", "其他 %[2]d 人中 %[1]d 人有空"},
"event_editor.label": {"Event", "日程"},
"event_editor.title": {"Title", "标题"},
"event_editor.all_day": {"All day", "全天"},
"event_editor.starts": {"Starts", "开始"},
"event_editor.ends": {"Ends", "结束"},
"event_editor.where": {"Location", "地点"},
"event_editor.guests": {"Guests", "参与者"},
"event_editor.guests_help": {"Type a name and press Enter.", "输入姓名后按回车。"},
"event_editor.reminders": {"Reminders", "提醒"},
"event_editor.save": {"Save", "保存"},
"event_editor.need_title": {"Enter a title.", "请输入标题。"},
"event_editor.need_start": {"Choose a start.", "请选择开始时间。"},
"event_editor.end_order": {"The end must be after the start.", "结束须晚于开始。"},
"cron_editor.expression": {"Expression", "表达式"},
"cron_editor.label": {"Cron schedule", "Cron 表达式"},
"cron_editor.next": {"Next runs", "下次运行"},
"cron_editor.never": {"No run in the next five years.", "未来五年内不会运行。"},
"cron_editor.repeated": {"repeated hour, first run", "重复时段,取首次"},
"cron_editor.minute": {"Minute", "分钟"},
"cron_editor.hour": {"Hour", "小时"},
"cron_editor.dom": {"Day of month", "日"},
"cron_editor.month": {"Month", "月"},
"cron_editor.dow": {"Day of week", "星期"},
"cron_editor.err_count": {"Use five fields, not %s.", "需要 5 个字段,而不是 %s 个。"},
"cron_editor.err_empty": {"an empty list item", "列表项为空"},
"cron_editor.err_step": {"step %q must be a positive number", "步长 %q 须为正整数"},
"cron_editor.err_number": {"%q is not a number", "%q 不是数字"},
"cron_editor.err_range": {"%s is outside %d–%d", "%s 超出 %d–%d"},
"cron_editor.err_backwards": {"range %s runs backwards", "范围 %s 起止颠倒"},
"cron_editor.field_error": {"%s: %s.", "%s:%s。"},
"cron_editor.invalid": {"Invalid", "无效"},
"cron_editor.any": {"Every value", "任意"},
"cron_editor.every": {"Every %s", "每 %s"},
"cron_editor.every_in": {"Every %s in %s", "%[2]s 内每 %[1]s"},
"relative_time.now": {"just now", "刚刚"},
"relative_time.ago": {"%s ago", "%s前"},
"relative_time.in": {"in %s", "%s后"},
"relative_time.minutes": {"%d minutes", "%d 分钟"},
"relative_time.minutes_one": {"%d minute", "%d 分钟"},
"relative_time.hours": {"%d hours", "%d 小时"},
"relative_time.hours_one": {"%d hour", "%d 小时"},
"relative_time.days": {"%d days", "%d 天"},
"relative_time.days_one": {"%d day", "%d 天"},
"relative_time.months": {"%d months", "%d 个月"},
"relative_time.months_one": {"%d month", "%d 个月"},
"relative_time.years": {"%d years", "%d 年"},
"relative_time.years_one": {"%d year", "%d 年"},
"countdown.label": {"Time left", "剩余时间"},
"countdown.done": {"%s: time is up.", "%s:时间到。"},
"countdown.days_clock": {"%dd", "%d天"},
"countdown.d": {"%d d", "%d 天"},
"countdown.h": {"%d h", "%d 小时"},
"countdown.m": {"%d min", "%d 分"},
"countdown.s": {"%d s", "%d 秒"},
"stopwatch.label": {"Stopwatch", "秒表"},
"stopwatch.start": {"Start", "开始"},
"stopwatch.pause": {"Pause", "暂停"},
"stopwatch.resume": {"Resume", "继续"},
"stopwatch.lap": {"Lap", "计次"},
"stopwatch.reset": {"Reset", "复位"},
"stopwatch.lap_n": {"Lap %d", "第 %d 圈"},
})
}
+30
View File
@@ -0,0 +1,30 @@
package core
func init() {
addMessages(map[string][2]string{
"chart.empty": {"No data", "暂无数据"},
"chart.hint": {"Focus the chart and use the arrow keys to read values", "聚焦图表后用方向键读取数值"},
"chart.missing": {"no value", "无数值"},
"pie_chart.other": {"Other", "其他"},
"pie_chart.total": {"Total", "总计"},
"scatter_chart.size": {"size", "大小"},
"scatter_chart.selected": {"selected", "已选"},
"calendar_heatmap.prev": {"Previous year", "上一年"},
"calendar_heatmap.next": {"Next year", "下一年"},
"calendar_heatmap.less": {"Less", "少"},
"calendar_heatmap.more": {"More", "多"},
"box_plot.readout": {"%s · median %s · quartiles %s–%s · whiskers %s–%s · %d outliers", "%s · 中位数 %s · 四分位 %s–%s · 须线 %s–%s · 离群点 %d 个"},
"waterfall_chart.running": {"running total", "累计"},
"funnel_chart.readout": {"%s · %s · %s of the stage before · %s of the first", "%s · %s · 较上一阶段 %s · 占首阶段 %s"},
"bullet_chart.actual": {"Actual", "实际"},
"bullet_chart.target": {"Target", "目标"},
"bullet_chart.band": {"Range %d: %s–%s", "区间 %d:%s–%s"},
"chart.back": {"Back", "返回"},
"chart.opens": {"Enter opens", "回车展开"},
"sankey_chart.in": {"in", "流入"},
"sankey_chart.out": {"out", "流出"},
"network_graph.readout": {"%s · %d links: %s", "%s · %d 条连线:%s"},
"realtime_chart.pause": {"Pause", "暂停"},
"realtime_chart.resume": {"Resume", "继续"},
})
}
+24
View File
@@ -0,0 +1,24 @@
package core
func init() {
addMessages(map[string][2]string{
"violin_plot.readout": {"%s · median %s · quartiles %s–%s · %d values", "%s · 中位数 %s · 四分位 %s–%s · %d 个值"},
"parallel_coordinates.filtered": {"filtered out", "已筛除"},
"parallel_coordinates.brush": {"%s filter %s–%s", "%s 筛选 %s–%s"},
"chord_diagram.out": {"out", "流出"},
"chord_diagram.in": {"in", "流入"},
"chart_annotation.readout": {"Annotation %d · %s", "标注 %d · %s"},
"chart_annotation.x": {"x %s", "x %s"},
"chart_annotation.y": {"y %s", "y %s"},
"spark_bar.empty": {"No data", "暂无数据"},
"chart_empty_state.empty": {"No data", "暂无数据"},
"chart_legend.more": {"+%d more", "另有 %d 项"},
"chart_legend.fewer": {"Show fewer", "收起"},
"chart_brush.window": {"%s: %s to %s", "%s:%s 至 %s"},
"chart_brush.start": {"Range start %s", "区间起点 %s"},
"chart_brush.end": {"Range end %s", "区间终点 %s"},
"trend_indicator.up": {"up", "上升"},
"trend_indicator.down": {"down", "下降"},
"trend_indicator.flat": {"unchanged", "持平"},
})
}
+65
View File
@@ -0,0 +1,65 @@
package core
func init() {
addMessages(map[string][2]string{
"prompt_composer.label": {"Message", "消息"},
"slash_command_menu.label": {"Commands", "命令"},
"slash_command_menu.empty": {"No matching commands", "没有匹配的命令"},
"context_mention_menu.label": {"Add context", "添加上下文"},
"context_mention_menu.empty": {"No matches", "无匹配"},
"context_mention_menu.loading": {"Searching…", "搜索中…"},
"context_mention_menu.file": {"Files", "文件"},
"context_mention_menu.doc": {"Documents", "文档"},
"context_mention_menu.web": {"Web pages", "网页"},
"attachment_chip.remove": {"Remove %s", "移除 %s"},
"attachment_chip.retry": {"Retry upload of %s", "重试上传 %s"},
"attachment_chip.uploading": {"Uploading %d%%", "上传中 %d%%"},
"attachment_chip.failed": {"Upload failed", "上传失败"},
"paste_image_preview.remove": {"Remove image %s", "移除图片 %s"},
"paste_image_preview.label": {"Pasted images", "粘贴的图片"},
"drag_drop_overlay.hint": {"Drop files to attach", "松开以添加文件"},
"drag_drop_overlay.rejected": {"Not accepted: %s", "不支持:%s"},
"voice_input_button.start": {"Start voice input", "开始语音输入"},
"voice_input_button.stop": {"Stop recording, %s", "停止录音,%s"},
"voice_input_button.denied": {"Microphone access denied", "麦克风权限被拒绝"},
"voice_waveform.label": {"Input level", "输入电平"},
"voice_waveform.silent": {"No sound detected", "未检测到声音"},
"context_chips.label": {"Attached context", "已附加的上下文"},
"context_chips.remove": {"Remove %s", "移除 %s"},
"context_chips.more": {"+%d more", "另有 %d 项"},
"context_chips.less": {"Show less", "收起"},
"model_selector.label": {"Model", "模型"},
"model_selector.context": {"%s context", "%s 上下文"},
"model_selector.placeholder": {"Choose a model", "选择模型"},
"mode_selector.label": {"Mode", "模式"},
"mode_selector.chat": {"Chat", "对话"},
"mode_selector.search": {"Search", "搜索"},
"mode_selector.research": {"Deep research", "深度研究"},
"mode_selector.agent": {"Agent", "智能体"},
"tool_toggle_menu.label": {"Tools", "工具"},
"tool_toggle_menu.count": {"Tools, %d on", "工具,已开 %d 个"},
"tool_toggle_menu.needs_auth": {"Needs authorization", "需要授权"},
"tool_toggle_menu.authorize_short": {"Authorize", "授权"},
"tool_toggle_menu.authorize": {"Authorize %s", "授权 %s"},
"parameter_panel.label": {"Parameters", "参数"},
"parameter_panel.reset": {"Reset %s", "重置 %s"},
"parameter_panel.reset_all": {"Reset all", "全部重置"},
"parameter_panel.default": {"Default %s", "默认 %s"},
"token_counter.label": {"About %s of %s tokens", "约 %s / %s 个 token"},
"token_counter.over": {"%s over the limit", "超出 %s"},
"context_window_meter.label": {"Context window", "上下文窗口"},
"context_window_meter.used": {"%s of %s tokens (%d%%)", "%s / %s token(%d%%)"},
"context_window_meter.warn": {"Context is %d%% full", "上下文已用 %d%%"},
"context_window_meter.free": {"Free", "剩余"},
"send_button.send": {"Send", "发送"},
"send_button.stop": {"Stop generating", "停止生成"},
"citation_badge.label": {"Source %d: %s", "来源 %d:%s"},
"citation_badge.preview": {"Source preview", "来源预览"},
"source_card.open": {"Open %s", "打开 %s"},
"sources_panel.label": {"Sources", "来源"},
"sources_panel.empty": {"No sources", "没有来源"},
"search_progress.searching": {"Searching for “%s”", "正在搜索“%s”"},
"search_progress.read": {"Read %d of %d sources", "已读 %d / %d 个来源"},
"search_progress.done": {"Searched “%s”, read %d sources", "已搜索“%s”,读了 %d 个来源"},
})
}
+57
View File
@@ -0,0 +1,57 @@
package core
func init() {
addMessages(map[string][2]string{
"message_bubble.user": {"You", "你"},
"message_bubble.assistant": {"Assistant", "助手"},
"message_bubble.system": {"System", "系统"},
"message_bubble.error": {"Error", "错误"},
"message_header.time": {"15:04", "15:04"},
"message_header.sending": {"Sending", "发送中"},
"message_header.streaming": {"Generating", "生成中"},
"message_header.sent": {"Sent", "已发送"},
"message_header.failed": {"Failed", "失败"},
"message_list.label": {"Messages", "消息"},
"message_list.date": {"Jan 2, 2006", "2006年1月2日"},
"message_list.today": {"Today", "今天"},
"message_list.yesterday": {"Yesterday", "昨天"},
"scroll_to_bottom_button.label": {"Scroll to latest", "回到最新"},
"scroll_to_bottom_button.unread": {"Scroll to latest, %d new", "回到最新,%d 条新消息"},
"code_block.plain": {"text", "文本"},
"code_block.wrap": {"Wrap lines", "自动换行"},
"code_block.copy": {"Copy code", "复制代码"},
"code_block.copied": {"Copied", "已复制"},
"code_block.collapse": {"Collapse", "折叠"},
"code_block.expand": {"Show %d lines", "展开 %d 行"},
"table_block.title": {"Table", "表格"},
"table_block.copy": {"Copy as TSV", "复制为 TSV"},
"file_message.open": {"Open %s, %s", "打开 %s,%s"},
"file_message.download": {"Download %s", "下载 %s"},
"file_message.bytes": {"%d B", "%d 字节"},
"audio_message.play": {"Play", "播放"},
"audio_message.pause": {"Pause", "暂停"},
"audio_message.seek": {"Playback position", "播放位置"},
"quote_reply.label": {"Reply to %s: %s", "回复 %s:%s"},
"message_actions.label": {"Message actions", "消息操作"},
"message_actions.copy": {"Copy", "复制"},
"message_actions.regenerate": {"Regenerate", "重新生成"},
"message_actions.edit": {"Edit", "编辑"},
"message_actions.like": {"Good response", "赞"},
"message_actions.dislike": {"Bad response", "踩"},
"message_actions.speak": {"Read aloud", "朗读"},
"message_actions.share": {"Share", "分享"},
"message_editor.label": {"Edit message", "编辑消息"},
"message_editor.cancel": {"Cancel", "取消"},
"message_editor.save": {"Save", "保存"},
"branch_navigator.label": {"Branch %d of %d", "第 %d 个分支,共 %d 个"},
"branch_navigator.previous": {"Previous branch", "上一个分支"},
"branch_navigator.next": {"Next branch", "下一个分支"},
"error_message.title": {"Something went wrong", "出错了"},
"error_message.retry": {"Retry", "重试"},
"error_message.wait": {"Retry in %d s", "%d 秒后重试"},
"error_message.limited": {"Rate limited", "已限流"},
"thinking_block.done": {"Thought for %d s", "思考了 %d 秒"},
"thinking_block.thinking": {"Thinking… %d s", "思考中… %d 秒"},
"typing_indicator.label": {"%s is typing…", "%s 正在输入…"},
})
}
+123
View File
@@ -0,0 +1,123 @@
package core
func init() {
addMessages(map[string][2]string{
"conversation_list.pinned": {"Pinned", "置顶"},
"conversation_list.today": {"Today", "今天"},
"conversation_list.yesterday": {"Yesterday", "昨天"},
"conversation_list.week": {"Previous 7 days", "7 天内"},
"conversation_list.older": {"Older", "更早"},
"conversation_list.untitled": {"New conversation", "新对话"},
"conversation_item.actions": {"Conversation actions", "对话操作"},
"conversation_item.rename": {"Rename", "重命名"},
"conversation_item.pin": {"Pin", "置顶"},
"conversation_item.unpin": {"Unpin", "取消置顶"},
"conversation_item.pinned": {"Pinned", "已置顶"},
"conversation_item.export": {"Export", "导出"},
"conversation_item.delete": {"Delete", "删除"},
"conversation_search.searching": {"Searching", "正在搜索"},
"conversation_search.no_results": {"No conversations match", "没有匹配的对话"},
"conversation_search.results": {"Search results", "搜索结果"},
"conversation_search.retry": {"Retry", "重试"},
"project_list.expanded": {"expanded", "已展开"},
"project_list.collapsed": {"collapsed", "已收起"},
"project_list.expand": {"Show conversations in %s", "展开 %s 的对话"},
"project_list.collapse": {"Hide conversations in %s", "收起 %s 的对话"},
"project_list.move_to": {"Move %s", "移动 %s"},
"project_list.move_group": {"Move to project", "移入项目"},
"project_knowledge_panel.title": {"Project knowledge", "项目知识"},
"project_knowledge_panel.add": {"Add files", "添加文件"},
"project_knowledge_panel.empty": {"No files yet", "暂无文件"},
"project_knowledge_panel.tokens": {"%d tokens", "%d tokens"},
"project_knowledge_panel.remove": {"Remove %s", "移除 %s"},
"project_knowledge_panel.usage": {"%d of %d tokens (%d%%)", "已用 %d / %d tokens(%d%%)"},
"project_knowledge_panel.near": {"Nearly full", "即将用满"},
"project_knowledge_panel.over": {"Over capacity", "超出容量"},
"prompt_library.all": {"All", "全部"},
"prompt_library.search": {"Search prompts", "搜索提示"},
"prompt_library.no_results": {"No prompts match", "没有匹配的提示"},
"prompt_library.pick": {"Choose a prompt to preview", "选择一个提示以预览"},
"prompt_library.insert": {"Insert", "插入"},
"feedback_form.up.title": {"What did you like?", "哪里令你满意?"},
"feedback_form.down.title": {"What went wrong?", "哪里出了问题?"},
"feedback_form.up.accurate": {"Accurate", "准确"},
"feedback_form.up.helpful": {"Helpful", "有帮助"},
"feedback_form.up.clear": {"Clear", "清晰"},
"feedback_form.down.wrong": {"Incorrect", "内容错误"},
"feedback_form.down.unhelpful": {"Not helpful", "没有帮助"},
"feedback_form.down.unsafe": {"Harmful or unsafe", "有害或不安全"},
"feedback_form.down.style": {"Too long or unclear", "冗长或不清楚"},
"feedback_form.comment": {"Tell us more (optional)", "补充说明(可选)"},
"feedback_form.submit": {"Submit", "提交"},
"feedback_form.cancel": {"Cancel", "取消"},
"date_separator.today": {"Today", "今天"},
"date_separator.yesterday": {"Yesterday", "昨天"},
"date_separator.short": {"%s %d", "%s%d日"},
"thinking_indicator.thinking": {"Thinking", "正在思考"},
"stop_generating_button.stop": {"Stop generating", "停止生成"},
"system_prompt_editor.title": {"System prompt", "系统提示"},
"system_prompt_editor.unsaved": {"Unsaved changes", "未保存"},
"system_prompt_editor.count": {"%d characters", "%d 字"},
"system_prompt_editor.restore": {"Restore default", "恢复默认"},
"system_prompt_editor.save": {"Save", "保存"},
"cost_estimator.kind": {"Kind", "类别"},
"cost_estimator.tokens": {"Tokens", "Tokens"},
"cost_estimator.cost": {"Cost", "费用"},
"cost_estimator.input": {"Input", "输入"},
"cost_estimator.output": {"Output", "输出"},
"cost_estimator.total": {"Total", "合计"},
"cost_estimator.total_label": {"Estimated cost %s", "预计费用 %s"},
"cost_estimator.rates": {"Rates per million tokens: input %s, output %s", "每百万 tokens 单价:输入 %s,输出 %s"},
"shared_conversation_view.shared_by": {"Shared by %s", "分享者:%s"},
"shared_conversation_view.someone": {"someone", "未知"},
"shared_conversation_view.read_only": {"Read only", "只读"},
"shared_conversation_view.copy_link": {"Copy link", "复制链接"},
"shared_conversation_view.user": {"You", "你"},
"shared_conversation_view.assistant": {"Assistant", "助手"},
"shared_conversation_view.system": {"System", "系统"},
"conversation_export.format": {"Format", "格式"},
"conversation_export.text": {"Plain text", "纯文本"},
"conversation_export.range": {"Messages", "消息范围"},
"conversation_export.all": {"All (%d)", "全部(%d)"},
"conversation_export.last": {"Last", "最近"},
"conversation_export.selected": {"Selected (%d)", "已选(%d)"},
"conversation_export.preview": {"Preview", "预览"},
"conversation_export.export": {"Export", "导出"},
"regenerate_menu.regenerate": {"Regenerate", "重新生成"},
"regenerate_menu.again": {"Try again", "重试"},
"regenerate_menu.model": {"Try another model", "换模型重试"},
"regenerate_menu.variants": {"Rewrite", "改写"},
"regenerate_menu.longer": {"Longer", "更长"},
"regenerate_menu.shorter": {"Shorter", "更短"},
"regenerate_menu.simpler": {"Simpler", "更简单"},
"regenerate_menu.detailed": {"More detailed", "更详细"},
"artifact_card.code": {"Code", "代码"},
"artifact_card.document": {"Document", "文档"},
"artifact_card.web": {"Web page", "网页"},
"artifact_card.open": {"Open", "打开"},
"artifact_card.writing": {"Writing", "正在生成"},
"chat_empty_state.new.title": {"Start a conversation", "开始新对话"},
"chat_empty_state.new.description": {"Ask a question or pick a suggestion.", "提出问题,或选择一个建议。"},
"chat_empty_state.new.action": {"New conversation", "新建对话"},
"chat_empty_state.no_results.action": {"Clear search", "清除搜索"},
"chat_empty_state.offline.title": {"You are offline", "当前离线"},
"chat_empty_state.offline.description": {"Messages will send when the connection returns.", "恢复连接后即可发送消息。"},
"chat_empty_state.offline.action": {"Retry", "重试"},
})
}
+33
View File
@@ -0,0 +1,33 @@
package core
func init() {
addMessages(map[string][2]string{
"range_slider.min": {"minimum", "最小值"},
"range_slider.max": {"maximum", "最大值"},
"select.placeholder": {"Select…", "请选择…"},
"select.empty": {"No options", "暂无选项"},
"select.clear": {"Clear", "清空"},
"multi_select.search": {"Search", "搜索"},
"multi_select.all": {"Select all", "全选"},
"multi_select.no_results": {"No results", "无匹配结果"},
"multi_select.limit": {"%d of %d chosen", "已选 %d / %d"},
"multi_select.more": {"+%d", "+%d"},
"multi_select.remove": {"Remove %s", "移除 %s"},
"combobox.toggle": {"Show options", "显示选项"},
"combobox.loading": {"Loading…", "加载中…"},
"combobox.no_results": {"No matches", "无匹配项"},
"combobox.use": {"Use “%s”", "使用“%s”"},
"cascader.loading": {"Loading…", "加载中…"},
"cascader.failed": {"Couldn't load", "加载失败"},
"cascader.retry": {"Retry", "重试"},
"cascader.empty": {"Nothing here", "暂无数据"},
"tree_select.search": {"Search", "搜索"},
"tree_select.no_results": {"No results", "无匹配结果"},
"tree_select.expand": {"Expand %s", "展开 %s"},
"tree_select.collapse": {"Collapse %s", "收起 %s"},
"tree_select.expanded": {"expanded", "已展开"},
"tree_select.collapsed": {"collapsed", "已收起"},
"tree_select.mixed": {"partly selected", "部分选中"},
"multi_select.mixed": {"partly selected", "部分选中"},
})
}
+101
View File
@@ -0,0 +1,101 @@
package core
func init() {
addMessages(map[string][2]string{
"terminal.label": {"Terminal", "终端"},
"terminal_search.label": {"Find in terminal", "在终端中查找"},
"terminal_tabs.label": {"Terminals", "终端"},
"terminal_tabs.empty": {"No terminals open", "没有打开的终端"},
"terminal_tabs.confirm": {"Close “%s”?", "关闭“%s”?"},
"terminal_tabs.busy": {"A process is still running in this terminal and will be ended.", "此终端中仍有进程在运行,关闭后将结束它。"},
"terminal_tabs.close": {"Close", "关闭"},
"terminal_tabs.running": {"Process running", "进程运行中"},
"terminal_tabs.rename": {"Terminal name", "终端名称"},
"terminal_tabs.closeTab": {"Close %s", "关闭 %s"},
"command_history.search": {"Search history", "搜索历史"},
"command_history.empty": {"No commands yet", "暂无命令"},
"command_history.none": {"No matching commands", "没有匹配的命令"},
"command_history.replay": {"Run %s again", "重新运行 %s"},
"command_history.exit": {"exit %d", "退出码 %d"},
"log_viewer.highlight": {"Highlight", "高亮关键字"},
"log_viewer.follow": {"Follow", "跟随"},
"log_viewer.empty": {"No log lines", "没有日志"},
"log_viewer.debug": {"DEBUG", "调试"},
"log_viewer.info": {"INFO", "信息"},
"log_viewer.warn": {"WARN", "警告"},
"log_viewer.error": {"ERROR", "错误"},
"process_list.empty": {"No processes", "没有进程"},
"process_list.name": {"Name", "名称"},
"process_list.pid": {"PID", "PID"},
"process_list.cpu": {"CPU", "CPU"},
"process_list.memory": {"Memory", "内存"},
"process_list.actions": {"End", "结束"},
"process_list.end": {"End %s", "结束 %s"},
"process_list.confirm": {"End “%s” (PID %d)?", "结束“%s”(PID %d)?"},
"process_list.warning": {"Unsaved work in this process will be lost.", "该进程中未保存的内容将会丢失。"},
"process_list.endButton": {"End process", "结束进程"},
"code_viewer.empty": {"No code", "没有代码"},
"code_viewer.fold": {"Fold line %d", "折叠第 %d 行"},
"code_viewer.unfold": {"Unfold line %d", "展开第 %d 行"},
"minimap.label": {"Minimap", "代码缩略图"},
"minimap.range": {"Lines %d to %d of %d", "第 %d 至 %d 行,共 %d 行"},
"find_widget.toggleReplace": {"Toggle replace", "切换替换"},
"find_widget.case": {"Match case", "区分大小写"},
"find_widget.word": {"Whole word", "全字匹配"},
"find_widget.regex": {"Regular expression", "正则表达式"},
"find_widget.invalid": {"Invalid pattern: %s", "表达式无效:%s"},
"find_widget.replace": {"Replace with", "替换为"},
"find_widget.replaceOne": {"Replace", "替换"},
"find_widget.replaceAll": {"Replace all", "全部替换"},
"search_panel.include": {"Files to include", "包含的文件"},
"search_panel.exclude": {"Files to exclude", "排除的文件"},
"search_panel.idle": {"Type to search in files", "输入内容以在文件中搜索"},
"search_panel.none": {"No results", "没有结果"},
"search_panel.summary": {"%d results in %d files", "%d 个结果,位于 %d 个文件"},
"search_panel.fold": {"Fold %s", "收起 %s"},
"search_panel.unfold": {"Unfold %s", "展开 %s"},
"problems_panel.errors": {"Errors %d", "错误 %d"},
"problems_panel.warnings": {"Warnings %d", "警告 %d"},
"problems_panel.infos": {"Info %d", "信息 %d"},
"problems_panel.error": {"Error", "错误"},
"problems_panel.warning": {"Warning", "警告"},
"problems_panel.info": {"Info", "信息"},
"problems_panel.empty": {"No problems", "没有问题"},
"problems_panel.at": {"Ln %d, Col %d", "第 %d 行,第 %d 列"},
"output_panel.channel": {"Output channel", "输出通道"},
"output_panel.clear": {"Clear output", "清空输出"},
"output_panel.empty": {"No output", "没有输出"},
"symbol_outline.filter": {"Filter symbols", "筛选符号"},
"symbol_outline.empty": {"No symbols", "没有符号"},
"completion_menu.label": {"Suggestions", "补全建议"},
"debug_toolbar.label": {"Debug", "调试"},
"debug_toolbar.start": {"Start", "开始"},
"debug_toolbar.continue": {"Continue", "继续"},
"debug_toolbar.pause": {"Pause", "暂停"},
"debug_toolbar.stepOver": {"Step over", "单步跳过"},
"debug_toolbar.stepInto": {"Step into", "单步进入"},
"debug_toolbar.stepOut": {"Step out", "单步跳出"},
"debug_toolbar.restart": {"Restart", "重启"},
"debug_toolbar.stop": {"Stop", "停止"},
"breakpoint_list.label": {"Breakpoints", "断点"},
"breakpoint_list.empty": {"No breakpoints", "没有断点"},
"breakpoint_list.enable": {"Enable %s:%d", "启用 %s:%d"},
"breakpoint_list.edit": {"Edit condition of %s:%d", "编辑 %s:%d 的条件"},
"breakpoint_list.condition": {"Condition", "条件"},
"breakpoint_list.placeholder": {"Break when expression is true", "表达式为真时中断"},
"breakpoint_list.when": {"when %s", "当 %s"},
"call_stack.empty": {"Not paused", "未暂停"},
"call_stack.frames": {"depth %d", "深度 %d"},
"variables_panel.empty": {"No variables", "没有变量"},
"variables_panel.value": {"Value", "值"},
"variables_panel.changed": {"Changed", "已变化"},
"hex_viewer.label": {"Hex view", "十六进制视图"},
"hex_viewer.empty": {"No bytes", "没有数据"},
"hex_viewer.at": {"Offset %d, %d bytes selected", "偏移 %d,已选 %d 字节"},
"flamegraph.search": {"Highlight frames", "高亮帧"},
"flamegraph.empty": {"No profile", "没有性能数据"},
"flamegraph.label": {"Flame graph", "火焰图"},
"flamegraph.hint": {"Point at a frame, or focus the graph and use the arrows", "指向一帧,或聚焦图表后用方向键"},
"flamegraph.readout": {"%s: %.1f %s, %.1f%% of total", "%s:%.1f %s,占总计 %.1f%%"},
})
}
+42
View File
@@ -0,0 +1,42 @@
package core
func init() {
addMessages(map[string][2]string{
"list.empty": {"No items", "暂无数据"},
"list.loading": {"Loading", "加载中"},
"list.loadingMore": {"Loading more", "正在加载更多"},
"list.failed": {"Could not load", "加载失败"},
"list.retry": {"Retry", "重试"},
"data_table.noMatch": {"No matching rows", "没有匹配的行"},
"data_table.selectRow": {"Select row", "选择行"},
"data_table.columns": {"Columns", "列"},
"data_table.sortAsc": {"Sort %s ascending", "按%s升序排序"},
"data_table.sortDesc": {"Sort %s descending", "按%s降序排序"},
"data_table.moveLeft": {"Move %s left", "将%s左移"},
"data_table.moveRight": {"Move %s right", "将%s右移"},
"data_table.narrower": {"Make %s narrower", "减小%s列宽"},
"data_table.wider": {"Make %s wider", "增大%s列宽"},
"timeline.done": {"Done", "已完成"},
"timeline.active": {"Current", "进行中"},
"timeline.warning": {"Warning", "警告"},
"timeline.error": {"Error", "错误"},
"description_list.copy": {"Copy", "复制"},
"description_list.copied": {"Copied", "已复制"},
"statistic.up": {"up", "上升"},
"statistic.down": {"down", "下降"},
"statistic.flat": {"unchanged", "持平"},
"carousel.prev": {"Previous slide", "上一项"},
"carousel.next": {"Next slide", "下一项"},
"carousel.pause": {"Pause autoplay", "暂停自动播放"},
"carousel.play": {"Resume autoplay", "继续自动播放"},
"carousel.position": {"Slide %d of %d", "第 %d 项,共 %d 项"},
"image_viewer.title": {"Image viewer", "图片查看器"},
"image_viewer.position": {"Image %d of %d", "第 %d 张,共 %d 张"},
"image_viewer.zoomIn": {"Zoom in", "放大"},
"image_viewer.zoomOut": {"Zoom out", "缩小"},
"image_viewer.fit": {"Fit to window", "适应窗口"},
"image_viewer.close": {"Close", "关闭"},
"image_viewer.prev": {"Previous image", "上一张"},
"image_viewer.next": {"Next image", "下一张"},
})
}
+88
View File
@@ -0,0 +1,88 @@
package core
func init() {
addMessages(map[string][2]string{
"calendar.label": {"Calendar", "日历"},
"calendar.title": {"%[1]s %[2]d", "%[2]d年%[1]s"},
"calendar.day_label": {"%[1]s, %[2]s %[3]d, %[4]d", "%[4]d年%[2]s%[3]d日 %[1]s"},
"calendar.prev_month": {"Previous month", "上个月"},
"calendar.next_month": {"Next month", "下个月"},
"calendar.prev_year": {"Previous year", "上一年"},
"calendar.next_year": {"Next year", "下一年"},
"calendar.month_1": {"January", "1月"},
"calendar.month_2": {"February", "2月"},
"calendar.month_3": {"March", "3月"},
"calendar.month_4": {"April", "4月"},
"calendar.month_5": {"May", "5月"},
"calendar.month_6": {"June", "6月"},
"calendar.month_7": {"July", "7月"},
"calendar.month_8": {"August", "8月"},
"calendar.month_9": {"September", "9月"},
"calendar.month_10": {"October", "10月"},
"calendar.month_11": {"November", "11月"},
"calendar.month_12": {"December", "12月"},
"calendar.weekday_0": {"Su", "日"},
"calendar.weekday_1": {"Mo", "一"},
"calendar.weekday_2": {"Tu", "二"},
"calendar.weekday_3": {"We", "三"},
"calendar.weekday_4": {"Th", "四"},
"calendar.weekday_5": {"Fr", "五"},
"calendar.weekday_6": {"Sa", "六"},
"calendar.weekday_long_0": {"Sunday", "星期日"},
"calendar.weekday_long_1": {"Monday", "星期一"},
"calendar.weekday_long_2": {"Tuesday", "星期二"},
"calendar.weekday_long_3": {"Wednesday", "星期三"},
"calendar.weekday_long_4": {"Thursday", "星期四"},
"calendar.weekday_long_5": {"Friday", "星期五"},
"calendar.weekday_long_6": {"Saturday", "星期六"},
"calendar.before_min": {"Choose %s or later.", "请选择 %s 或之后。"},
"calendar.after_max": {"Choose %s or earlier.", "请选择 %s 或之前。"},
"calendar.unavailable": {"%s is not available.", "%s 不可选。"},
"calendar.clear": {"Clear", "清空"},
"calendar.confirm": {"Confirm", "确定"},
"calendar.cancel": {"Cancel", "取消"},
"date_picker.placeholder": {"Select date", "选择日期"},
"date_picker.open": {"Open calendar", "打开日历"},
"date_picker.invalid": {"Enter a date like %s.", "请按 %s 的格式输入日期。"},
"date_range_picker.label": {"Date range", "日期范围"},
"date_range_picker.placeholder": {"Start date – End date", "开始日期 – 结束日期"},
"date_range_picker.pick_start": {"Choose the start date.", "请选择开始日期。"},
"date_range_picker.pick_end": {"From %s, choose the end date.", "自 %s 起,请选择结束日期。"},
"date_range_picker.summary": {"%s – %s · %d days", "%s – %s · 共 %d 天"},
"date_range_picker.blocked": {"The range cannot include %s.", "范围不能包含 %s。"},
"time_picker.hours": {"Hours", "时"},
"time_picker.minutes": {"Minutes", "分"},
"time_picker.seconds": {"Seconds", "秒"},
"time_picker.period": {"AM/PM", "上午/下午"},
"time_picker.am": {"AM", "上午"},
"time_picker.pm": {"PM", "下午"},
"time_picker.with_period": {"%[1]s %[2]s", "%[2]s %[1]s"},
"time_picker.open": {"Choose time", "选择时间"},
"time_picker.minute_step": {"Minutes must be a multiple of %d.", "分钟须为 %d 的倍数。"},
"time_picker.second_step": {"Seconds must be a multiple of %d.", "秒须为 %d 的倍数。"},
"time_picker.segment": {"%[1]s, from %[2]d to %[3]d", "%[1]s,范围 %[2]d–%[3]d"},
"time_picker.part_range": {"%[1]s must be from %[2]d to %[3]d.", "%[1]s须在 %[2]d 至 %[3]d 之间。"},
"time_picker.out_of_range": {"Choose a time from %s to %s.", "请选择 %s 至 %s 之间的时间。"},
"time_range_picker.start": {"Start time", "开始时间"},
"time_range_picker.end": {"End time", "结束时间"},
"time_range_picker.next_day": {"+1 day", "次日"},
"time_range_picker.same": {"Start and end must differ.", "开始与结束时间不能相同。"},
"time_range_picker.order": {"End must be after start; overnight ranges are off.", "结束须晚于开始;未开启跨午夜。"},
"date_time_picker.placeholder": {"Select date and time", "选择日期和时间"},
"date_time_picker.time": {"Time", "时间"},
"date_time_picker.gap": {"%s does not exist in %s: the clocks skip it.", "%s 在 %s 不存在:该时段因夏令时被跳过。"},
"date_time_picker.ambiguous": {"%s happens twice in %s: the clocks repeat it.", "%s 在 %s 出现两次:该时段因夏令时重复。"},
"month_picker.placeholder": {"Select month", "选择月份"},
"month_picker.year": {"%d", "%d年"},
"year_picker.placeholder": {"Select year", "选择年份"},
"year_picker.prev": {"Previous decade", "上一个十年"},
"year_picker.next": {"Next decade", "下一个十年"},
})
}
+121
View File
@@ -0,0 +1,121 @@
package core
func init() {
addMessages(map[string][2]string{
"key_value_input.key": {"Key", "键"},
"key_value_input.value": {"Value", "值"},
"key_value_input.row": {"Row %d", "第 %d 行"},
"key_value_input.remove": {"Remove row %d", "删除第 %d 行"},
"key_value_input.add": {"Add row", "添加一行"},
"system_monitor.empty": {"No resources", "没有资源"},
"stat_card.change": {"Change %s", "变化 %s"},
"devtools.ago": {"%s ago", "%s 前"},
"alert_list.info": {"Info", "提示"},
"alert_list.warning": {"Warning", "警告"},
"alert_list.critical": {"Critical", "严重"},
"alert_list.ack": {"Acknowledge", "确认"},
"alert_list.acked": {"Acknowledged", "已确认"},
"alert_list.silence": {"Silence 1 h", "静默 1 小时"},
"alert_list.silenced": {"Silenced until %s", "静默至 %s"},
"incident_card.investigating": {"Investigating", "调查中"},
"incident_card.identified": {"Identified", "已定位"},
"incident_card.monitoring": {"Monitoring", "观察中"},
"incident_card.resolved": {"Resolved", "已解决"},
"incident_card.none": {"none", "无"},
"incident_card.minor": {"minor", "轻微"},
"incident_card.major": {"major", "严重"},
"incident_card.critical": {"critical", "致命"},
"incident_card.impact": {"Impact: %s", "影响:%s"},
"incident_card.started": {"Started %s", "开始于 %s"},
"service_status.operational": {"Operational", "正常"},
"service_status.degraded": {"Degraded", "降级"},
"service_status.outage": {"Outage", "中断"},
"service_status.all_ok": {"All systems operational", "所有服务正常"},
"service_status.some_degraded": {"Some services degraded", "部分服务降级"},
"service_status.some_down": {"Some services down", "部分服务中断"},
"service_status.counts": {"%d up · %d degraded · %d down", "%d 正常 · %d 降级 · %d 中断"},
"service_status.empty": {"No services", "没有服务"},
"uptime_bar.ok": {"Operational", "正常"},
"uptime_bar.degraded": {"Degraded", "降级"},
"uptime_bar.down": {"Outage", "中断"},
"uptime_bar.nodata": {"No data", "无数据"},
"resource_gauge.empty": {"No resources", "没有资源"},
"resource_gauge.normal": {"Normal", "正常"},
"resource_gauge.high": {"High", "偏高"},
"resource_gauge.critical": {"Critical", "危险"},
"refresh_interval_selector.off": {"Auto refresh off", "不自动刷新"},
"refresh_interval_selector.refresh": {"Refresh", "刷新"},
"refresh_interval_selector.refreshing": {"Refreshing", "正在刷新"},
"refresh_interval_selector.seconds": {"Every %d s", "每 %d 秒"},
"refresh_interval_selector.minutes": {"Every %d min", "每 %d 分钟"},
"refresh_interval_selector.label": {"Refresh interval", "刷新间隔"},
"dashboard_filter_bar.label": {"Dashboard filters", "仪表盘过滤"},
"dashboard_filter_bar.range": {"Time range", "时间范围"},
"dashboard_filter_bar.default_range": {"Default range", "默认范围"},
"dashboard_filter_bar.last": {"Last %s", "最近 %s"},
"dashboard_filter_bar.minutes": {"%d min", "%d 分钟"},
"dashboard_filter_bar.hours": {"%d h", "%d 小时"},
"dashboard_filter_bar.days": {"%d d", "%d 天"},
"dashboard_filter_bar.env": {"Environment", "环境"},
"dashboard_filter_bar.all_envs": {"All environments", "全部环境"},
"dashboard_filter_bar.tags": {"Tags", "标签"},
"dashboard_filter_bar.clear": {"Clear filters", "清除过滤"},
"log_stream.pause": {"Pause", "暂停"},
"log_stream.resume": {"Resume", "继续"},
"log_stream.level": {"Minimum level", "最低级别"},
"log_stream.waiting": {"%d new lines", "%d 条新日志"},
"log_stream.empty": {"No log lines", "没有日志"},
"trace_waterfall.label": {"Trace", "调用链"},
"trace_waterfall.empty": {"No spans", "没有跨度"},
"trace_waterfall.summary": {"%d spans · %s", "%d 个跨度 · %s"},
"trace_waterfall.detail": {"%s · starts at %s · takes %s", "%s · 起于 %s · 耗时 %s"},
"trace_waterfall.error": {"Error", "错误"},
"json_viewer.invalid": {"Invalid JSON: %v", "JSON 无效:%v"},
"json_viewer.copy": {"Copy path", "复制路径"},
"json_viewer.items": {"%s %d items %s", "%s %d 项 %s"},
"json_editor.label": {"JSON", "JSON"},
"json_editor.format": {"Format", "格式化"},
"json_editor.valid": {"Valid JSON", "JSON 有效"},
"json_editor.at": {"Error at line %d, column %d", "错误位于第 %d 行第 %d 列"},
"schema_tree.label": {"Schema", "数据库结构"},
"schema_tree.empty": {"No databases", "没有数据库"},
"schema_tree.database": {"Database", "数据库"},
"schema_tree.table": {"Table", "表"},
"schema_tree.view": {"View", "视图"},
"schema_tree.column": {"Column", "列"},
"schema_tree.index": {"Index", "索引"},
"api_request_builder.invalid_url": {"Enter a valid HTTP or HTTPS URL", "请输入有效的 HTTP 或 HTTPS 地址"},
"api_request_builder.method": {"Method", "方法"},
"api_request_builder.url": {"Request URL", "请求地址"},
"api_request_builder.send": {"Send", "发送"},
"api_request_builder.params": {"Params (%d)", "参数(%d)"},
"api_request_builder.params_label": {"Query parameters", "查询参数"},
"api_request_builder.headers": {"Headers (%d)", "请求头(%d)"},
"api_request_builder.headers_label": {"Request headers", "请求头"},
"api_request_builder.body": {"Body", "正文"},
"api_request_builder.no_body": {"GET and HEAD requests usually carry no body.", "GET 与 HEAD 请求通常不带正文。"},
"api_request_builder.parts": {"Request parts", "请求组成"},
"response_viewer.label": {"Response", "响应"},
"response_viewer.none": {"Send a request to see its response", "发送请求后在此查看响应"},
"response_viewer.body": {"Body", "正文"},
"response_viewer.empty": {"Empty body", "正文为空"},
"response_viewer.headers": {"Headers (%d)", "响应头(%d)"},
"response_viewer.no_headers": {"No headers", "没有响应头"},
"alert_list.empty": {"No alerts", "没有告警"},
})
}
+16
View File
@@ -0,0 +1,16 @@
package core
func init() {
addMessages(map[string][2]string{
"editable_text.saving": {"Saving", "正在保存"},
"icon.missing": {"Missing icon: %s", "缺少图标:%s"},
"image.placeholder": {"No image", "暂无图片"},
"image.loading": {"Loading image", "正在加载图片"},
"image.error": {"Image failed to load", "图片加载失败"},
"image.retry": {"Retry", "重试"},
"avatar.unnamed": {"Unnamed", "未命名"},
"avatar_group.more": {"Show all %d people", "显示全部 %d 人"},
"tag.remove": {"Remove %s", "移除%s"},
"link.invalid": {"This link cannot be opened: %s", "无法打开此链接:%s"},
})
}
+48
View File
@@ -0,0 +1,48 @@
package core
func init() {
addMessages(map[string][2]string{
"copy_button.copy": {"Copy", "复制"},
"copy_button.copied": {"Copied", "已复制"},
"split_button.more": {"More options", "更多选项"},
"hold_to_confirm.hint": {"Press and hold, or hold Space, to confirm", "按住鼠标或空格键以确认"},
"hold_to_confirm.left": {"Keep holding… %.1f s", "继续按住… %.1f 秒"},
"hold_to_confirm.done": {"Confirmed", "已确认"},
"bulk_action_bar.selected": {"%d selected", "已选 %d 项"},
"bulk_action_bar.clear": {"Clear selection", "清除选择"},
"color_palette.custom": {"Custom color", "自定义颜色"},
"knob.label": {"Knob", "旋钮"},
"currency_input.invalid": {"Enter an amount, such as 1,234.50", "请输入金额,例如 1,234.50"},
"currency_input.precision": {"Use at most %d decimal places", "最多保留 %d 位小数"},
"signature_pad.label": {"Signature", "签名"},
"signature_pad.hint": {"Draw with the pointer; Delete clears", "用鼠标书写;Delete 键清除"},
"signature_pad.empty": {"Sign here", "请在此签名"},
"signature_pad.clear": {"Clear", "清除"},
"undo_toast.undo": {"Undo", "撤销"},
"resizable_panel_group.divider": {"Resize %s and %s", "调整 %s 与 %s 的大小"},
"dock_panel.zone0": {"Center dock", "中央停靠区"},
"dock_panel.zone1": {"Left dock", "左侧停靠区"},
"dock_panel.zone2": {"Right dock", "右侧停靠区"},
"dock_panel.zone3": {"Bottom dock", "底部停靠区"},
"dock_panel.hint": {"Drag to an edge, or Shift+Alt+arrow, to dock", "拖到边缘,或按 Shift+Alt+方向键停靠"},
"activity_feed.label": {"Activity", "活动"},
"activity_feed.today": {"Today", "今天"},
"activity_feed.yesterday": {"Yesterday", "昨天"},
"activity_feed.empty": {"No activity yet", "暂无活动"},
"activity_feed.empty_hint": {"Changes people make will show here.", "成员的操作会显示在这里。"},
"qr_code.label": {"QR code", "二维码"},
"qr_code.too_long": {"Text too long for a QR code", "文字过长,无法生成二维码"},
})
}
+51
View File
@@ -0,0 +1,51 @@
package core
func init() {
addMessages(map[string][2]string{
"loading": {"Loading", "加载中"},
"alert.close": {"Dismiss", "关闭"},
"alert.info": {"Information", "信息"},
"alert.success": {"Success", "成功"},
"alert.warning": {"Warning", "警告"},
"alert.error": {"Error", "错误"},
"toast.close": {"Dismiss notification", "关闭通知"},
"toast.region": {"Notifications", "通知"},
"progress.indeterminate": {"In progress", "进行中"},
"meter.normal": {"Normal", "正常"},
"meter.warning": {"High", "偏高"},
"meter.critical": {"Critical", "严重"},
"meter.low_warning": {"Low", "偏低"},
"empty_state.no_data.title": {"Nothing here yet", "暂无内容"},
"empty_state.no_data.description": {"Items you add will appear here.", "添加的内容会显示在这里。"},
"empty_state.no_results.title": {"No results", "没有结果"},
"empty_state.no_results.description": {"Try other words or clear the filters.", "请换个关键词,或清除筛选条件。"},
"empty_state.no_results.query": {"Nothing matches “%s”.", "没有与“%s”匹配的内容。"},
"result.success.title": {"Done", "操作成功"},
"result.failure.title": {"Something went wrong", "操作失败"},
"result.forbidden.title": {"No access", "无访问权限"},
"status_indicator.success": {"Healthy", "正常"},
"status_indicator.warning": {"Degraded", "警告"},
"status_indicator.error": {"Failing", "错误"},
"status_indicator.offline": {"Offline", "离线"},
"status_indicator.busy": {"Working", "处理中"},
"notification_center.title": {"Notifications", "通知"},
"notification_center.unread": {"%d unread", "%d 条未读"},
"notification_center.unread_mark": {"Unread", "未读"},
"notification_center.mark_read": {"Mark read", "标为已读"},
"notification_center.mark_unread": {"Mark unread", "标为未读"},
"notification_center.mark_all_read": {"Mark all read", "全部已读"},
"notification_center.clear": {"Clear", "清除"},
"notification_center.clear_all": {"Clear all", "全部清除"},
"notification_center.empty": {"You're all caught up", "没有新通知"},
"notification_center.empty_hint": {"New notifications will appear here.", "新的通知会显示在这里。"},
"loading_overlay.label": {"Loading…", "正在加载…"},
})
}
+98
View File
@@ -0,0 +1,98 @@
package core
func init() {
addMessages(map[string][2]string{
"file_icon.file": {"file", "文件"},
"file_icon.folder": {"Folder", "文件夹"},
"file_icon.open": {"Open folder", "打开的文件夹"},
"path_bar.label": {"Path", "路径"},
"path_bar.more": {"Hidden folders", "折叠的文件夹"},
"path_bar.current": {"Current folder", "当前文件夹"},
"rename_inline.label": {"Name", "名称"},
"rename_inline.empty": {"A name is required", "名称不能为空"},
"file_explorer.back": {"Back", "后退"},
"file_explorer.forward": {"Forward", "前进"},
"file_explorer.up": {"Enclosing folder", "上级文件夹"},
"file_explorer.empty": {"This folder is empty", "此文件夹为空"},
"file_grid.empty": {"This folder is empty", "此文件夹为空"},
"file_preview.label": {"Preview of %s", "%s 的预览"},
"file_preview.open": {"Open", "打开"},
"file_preview.close": {"Close preview", "关闭预览"},
"file_preview.unsupported": {"No preview for %s files", "无法预览 %s 文件"},
"file_operation_progress.copying": {"Copying %d of %d items", "正在复制 %d / %d 项"},
"file_operation_progress.moving": {"Moving %d of %d items", "正在移动 %d / %d 项"},
"file_operation_progress.deleting": {"Deleting %d of %d items", "正在删除 %d / %d 项"},
"file_operation_progress.cancel": {"Cancel", "取消"},
"file_operation_progress.bytes": {"%s of %s", "%s / %s"},
"file_operation_progress.conflict": {"“%s” already exists here.", "此处已存在“%s”。"},
"file_operation_progress.all": {"Do this for all conflicts", "对所有冲突执行此操作"},
"file_operation_progress.skip": {"Skip", "跳过"},
"file_operation_progress.keepBoth": {"Keep both", "保留两者"},
"file_operation_progress.replace": {"Replace", "替换"},
"transfer_queue.summary": {"%d in progress, %d failed", "%d 项进行中,%d 项失败"},
"transfer_queue.empty": {"No transfers", "没有传输"},
"transfer_queue.upload": {"Upload", "上传"},
"transfer_queue.download": {"Download", "下载"},
"transfer_queue.queued": {"Waiting", "等待中"},
"transfer_queue.paused": {"Paused at %.0f%%", "已暂停于 %.0f%%"},
"transfer_queue.failed": {"Failed: %s", "失败:%s"},
"transfer_queue.done": {"Done", "已完成"},
"transfer_queue.pause": {"Pause %s", "暂停 %s"},
"transfer_queue.resume": {"Resume %s", "继续 %s"},
"transfer_queue.retry": {"Retry %s", "重试 %s"},
"transfer_queue.remove": {"Remove %s", "移除 %s"},
"storage_usage.used": {"%s of %s used", "已用 %s,共 %s"},
"storage_usage.free": {"Free: %s (%.1f%%)", "可用:%s(%.1f%%)"},
"storage_usage.freeLabel": {"Free", "可用"},
"recent_files.title": {"Recent", "最近使用"},
"recent_files.clear": {"Clear", "清除"},
"recent_files.empty": {"No recent files", "没有最近使用的文件"},
"recent_files.remove": {"Remove %s from recent", "从最近使用中移除 %s"},
"recent_files.today": {"Today", "今天"},
"recent_files.yesterday": {"Yesterday", "昨天"},
"recent_files.week": {"This week", "本周"},
"recent_files.earlier": {"Earlier", "更早"},
"archive_viewer.summary": {"%d files, %s unpacked, %s packed (%s smaller)", "%d 个文件,解压后 %s,压缩后 %s(减小 %s)"},
"archive_viewer.empty": {"The archive is empty", "压缩包为空"},
"archive_viewer.name": {"Name", "名称"},
"archive_viewer.size": {"Size", "大小"},
"archive_viewer.packed": {"Packed", "压缩后"},
"archive_viewer.ratio": {"Saved", "压缩率"},
"presence_avatars.label": {"%d people here", "%d 人在线"},
"presence_avatars.more": {"%d more people", "另有 %d 人"},
"presence_avatars.others": {"Others here", "其他在线者"},
"presence_avatars.follow": {"Follow %s", "跟随 %s"},
"presence_avatars.unfollow": {"Stop following %s", "停止跟随 %s"},
"presence_avatars.away": {"Away", "离开"},
"permission_select.view": {"Can view", "可查看"},
"permission_select.comment": {"Can comment", "可评论"},
"permission_select.edit": {"Can edit", "可编辑"},
"permission_select.label": {"Permission", "权限"},
"share_dialog.title": {"Share “%s”", "分享“%s”"},
"share_dialog.placeholder": {"Add people by email", "通过邮箱添加成员"},
"share_dialog.invite": {"Email to invite", "要邀请的邮箱"},
"share_dialog.invitePermission": {"Permission for the invite", "邀请的权限"},
"share_dialog.send": {"Invite", "邀请"},
"share_dialog.people": {"People with access", "有权访问的成员"},
"share_dialog.owner": {"Owner", "所有者"},
"share_dialog.remove": {"Remove %s", "移除 %s"},
"share_dialog.copy": {"Copy link", "复制链接"},
"share_dialog.copied": {"Link copied", "链接已复制"},
"reactions.label": {"Reactions", "表情回应"},
"reactions.add": {"Add reaction", "添加回应"},
"reactions.pick": {"Choose a reaction", "选择回应"},
"reactions.count": {"%s %d", "%s %d"},
"reactions.mine": {"including you", "包括你"},
"live_indicator.synced": {"All changes saved", "所有更改已保存"},
"live_indicator.syncing": {"Saving…", "正在保存…"},
"live_indicator.reconnecting": {"Reconnecting…", "正在重新连接…"},
"live_indicator.offline": {"Offline, changes kept on this device", "已离线,更改保存在本机"},
"live_indicator.error": {"Sync failed", "同步失败"},
"live_indicator.retry": {"Retry", "重试"},
"live_indicator.justNow": {"just now", "刚刚"},
"live_indicator.minutes": {"%d min ago", "%d 分钟前"},
"live_indicator.hours": {"%d h ago", "%d 小时前"},
"live_indicator.days": {"%d days ago", "%d 天前"},
"remote_cursor.label": {"Also editing: %s", "同时编辑:%s"},
})
}
+54
View File
@@ -0,0 +1,54 @@
package core
func init() {
addMessages(map[string][2]string{
"rating.label": {"Rating", "评分"},
"pin_input.label": {"Verification code", "验证码"},
"pin_input.filled": {"%d of %d digits entered", "已输入 %d / %d 位"},
"rating.value": {"%s of %d", "%s / %d 分"},
"tags_input.duplicate": {"“%s” is already added", "“%s”已添加"},
"tags_input.max": {"At most %d tags", "最多 %d 个标签"},
"tags_input.remove": {"Remove %s", "移除 %s"},
"color_picker.label": {"Color", "颜色"},
"color_picker.red": {"Red", "红"},
"color_picker.green": {"Green", "绿"},
"color_picker.blue": {"Blue", "蓝"},
"color_picker.percent": {"Opacity percent", "不透明度百分比"},
"color_picker.hue": {"Hue", "色相"},
"color_picker.alpha": {"Opacity", "不透明度"},
"color_picker.square": {"Saturation and brightness", "饱和度与亮度"},
"color_picker.sv": {"%.0f%% saturation, %.0f%% brightness", "饱和度 %.0f%%,亮度 %.0f%%"},
"color_picker.invalid": {"Use HEX RGB, RRGGBB or RRGGBBAA; channels 0–255; opacity 0–100.", "HEX 须为 RGB、RRGGBB 或 RRGGBBAA;通道 0–255;不透明度 0–100。"},
"file_picker.failed": {"Could not open the file dialog: %v", "无法打开文件对话框:%v"},
"file_picker.choose_file": {"Choose file…", "选择文件…"},
"file_picker.choose_folder": {"Choose folder…", "选择文件夹…"},
"file_picker.none": {"Nothing chosen", "未选择"},
"file_drop_zone.hint": {"Drop files here", "将文件拖到此处"},
"file_drop_zone.browse": {"Browse…", "浏览…"},
"file_drop_zone.any": {"Any file", "任意文件"},
"file_drop_zone.max_files": {"up to %d files", "最多 %d 个文件"},
"file_drop_zone.max_size": {"%s each", "每个不超过 %s"},
"file_drop_zone.type": {"Only %s files", "仅接受 %s 文件"},
"file_drop_zone.size": {"Larger than %s", "超过 %s"},
"file_drop_zone.count": {"More than %d files", "超过 %d 个文件"},
"file_drop_zone.folder": {"Folders are not accepted", "不接受文件夹"},
"file_drop_zone.unreadable": {"Cannot read: %v", "无法读取:%v"},
"file_drop_zone.checking": {"Checking…", "检查中…"},
"file_drop_zone.remove": {"Remove %s", "移除 %s"},
"file_drop_zone.dialog": {"File dialog", "文件对话框"},
"transfer.source": {"Available", "可选"},
"transfer.target": {"Chosen", "已选"},
"transfer.to": {"Move to %s", "移到%s"},
"transfer.all": {"Select all in %s", "全选%s"},
"transfer.search": {"Search", "搜索"},
"transfer.search_in": {"Search %s", "搜索%s"},
"transfer.partial": {"%d of %d selected", "已选 %d / %d 项"},
"transfer.empty": {"No items", "暂无条目"},
"transfer.no_match": {"No matches", "无匹配结果"},
"form.submit": {"Submit", "提交"},
"form.reset": {"Reset", "重置"},
"form.required": {"Required", "必填"},
"form.checking": {"Checking…", "校验中…"},
"form.failed": {"Some fields need attention", "部分字段需要修改"},
})
}
+114
View File
@@ -0,0 +1,114 @@
package core
func init() {
addMessages(map[string][2]string{
"git_status_badge.modified": {"Modified", "已修改"},
"git_status_badge.added": {"Added", "已添加"},
"git_status_badge.deleted": {"Deleted", "已删除"},
"git_status_badge.untracked": {"Untracked", "未跟踪"},
"git_status_badge.renamed": {"Renamed", "已重命名"},
"git_status_badge.copied": {"Copied", "已复制"},
"diff_stat.label": {"%d additions, %d deletions", "新增 %d 行,删除 %d 行"},
"command_block.copy_command": {"Copy command", "复制命令"},
"command_block.copy_output": {"Copy output", "复制输出"},
"command_block.exit": {"exit %d", "退出码 %d"},
"command_block.no_output": {"No output", "无输出"},
"command_block.output": {"Command output", "命令输出"},
"command_block.running": {"Running", "运行中"},
"commit_list.empty": {"No commits", "没有提交"},
"branch_list.ahead": {"%d ahead of upstream", "领先上游 %d 个提交"},
"branch_list.behind": {"%d behind upstream", "落后上游 %d 个提交"},
"branch_list.current": {"current", "当前"},
"branch_list.empty": {"No branches", "没有分支"},
"branch_selector.create": {"Create branch", "新建分支"},
"branch_selector.empty": {"No matching branches", "没有匹配的分支"},
"branch_selector.label": {"Branch", "分支"},
"branch_selector.search": {"Search branches", "搜索分支"},
"branch_selector.local": {"Local", "本地"},
"branch_selector.remote": {"Remote", "远端"},
"tag_list.empty": {"No tags", "没有标签"},
"tag_list.jump": {"Go to commit", "跳转到提交"},
"stash_list.apply": {"Apply", "应用"},
"stash_list.pop": {"Pop", "弹出"},
"stash_list.drop": {"Drop", "删除"},
"stash_list.empty": {"No stashes", "没有贮藏"},
"blame_view.line": {"Line %d, %s, %s", "第 %d 行,%s,%s"},
"file_history.title": {"History", "历史"},
"file_history.diff": {"View changes", "查看差异"},
"file_history.empty": {"No history for this file", "此文件没有历史"},
"pull_request_card.open": {"Open", "开放"},
"pull_request_card.draft": {"Draft", "草稿"},
"pull_request_card.merged": {"Merged", "已合并"},
"pull_request_card.closed": {"Closed", "已关闭"},
"pull_request_card.files": {"%d files", "%d 个文件"},
"pull_request_card.passed": {"%d checks passed", "%d 项检查通过"},
"pull_request_card.failed": {"%d checks failed", "%d 项检查失败"},
"pull_request_card.pending": {"%d checks pending", "%d 项检查进行中"},
"pull_request_card.approved": {"approved", "已批准"},
"pull_request_card.changes": {"changes requested", "要求修改"},
"pull_request_card.review_pending": {"review pending", "待评审"},
"review_comment.placeholder": {"Write a reply", "写下回复"},
"review_comment.reply": {"Reply", "回复"},
"review_comment.field": {"Reply text", "回复内容"},
"review_comment.resolve": {"Resolve", "解决"},
"review_comment.reopen": {"Reopen", "重新打开"},
"review_comment.resolved": {"Resolved", "已解决"},
"changes_list.staged": {"Staged changes (%d)", "已暂存的更改(%d)"},
"changes_list.unstaged": {"Changes (%d)", "更改(%d)"},
"changes_list.stage": {"Stage", "暂存"},
"changes_list.unstage": {"Unstage", "取消暂存"},
"changes_list.stage_all": {"Stage all", "全部暂存"},
"changes_list.unstage_all": {"Unstage all", "全部取消暂存"},
"diff_viewer.added": {"Added", "新增"},
"diff_viewer.deleted": {"Deleted", "删除"},
"diff_viewer.fold": {"%d unchanged lines", "%d 行未更改"},
"inline_diff.removed": {"Old", "原文"},
"inline_diff.added": {"New", "新文"},
"three_way_merge.resolved": {"%d of %d conflicts resolved", "已解决 %d / %d 个冲突"},
"three_way_merge.ours": {"Local", "本地"},
"three_way_merge.base": {"Base", "基准"},
"three_way_merge.theirs": {"Remote", "远端"},
"three_way_merge.result": {"Result", "结果"},
"three_way_merge.unresolved": {"Unresolved", "未解决"},
"three_way_merge.empty": {"No lines", "无内容"},
"three_way_merge.take_ours": {"Take local", "采纳本地"},
"three_way_merge.take_theirs": {"Take remote", "采纳远端"},
"three_way_merge.take_both": {"Take both", "两者都要"},
"three_way_merge.take_base": {"Keep base", "保留基准"},
"conflict_resolver.resolved": {"%d of %d conflicts resolved", "已解决 %d / %d 个冲突"},
"conflict_resolver.broken": {"Conflict markers are not closed after line %d", "第 %d 行起的冲突标记未闭合"},
"conflict_resolver.none": {"No conflicts", "没有冲突"},
"conflict_resolver.title": {"Conflict %d · line %d", "冲突 %d · 第 %d 行"},
"conflict_resolver.open": {"unresolved", "未解决"},
"conflict_resolver.done": {"resolved", "已解决"},
"conflict_resolver.current": {"Current", "当前"},
"conflict_resolver.incoming": {"Incoming", "传入"},
"conflict_resolver.take_current": {"Accept current", "采纳当前"},
"conflict_resolver.take_incoming": {"Accept incoming", "采纳传入"},
"conflict_resolver.take_both": {"Accept both", "两者都采纳"},
"conflict_resolver.reset": {"Undo", "撤销"},
"commit_input.title": {"Summary", "提交标题"},
"commit_input.body": {"Description", "提交说明"},
"commit_input.count": {"%d of %d characters", "%d / %d 字符"},
"commit_input.long": {"Summary is %d characters over the suggested length", "标题超出建议长度 %d 个字符"},
"commit_input.commit": {"Commit", "提交"},
"commit_input.amend": {"Amend", "修订"},
})
}
+22
View File
@@ -0,0 +1,22 @@
package core
func init() {
addMessages(map[string][2]string{
"text_input.clear": {"Clear", "清空"},
"number_input.increase": {"Increase", "增加"},
"number_input.decrease": {"Decrease", "减少"},
"number_input.invalid": {"Enter a number", "请输入数字"},
"number_input.range": {"Enter a number from %s to %s", "请输入 %s 到 %s 之间的数字"},
"password_input.show": {"Show password", "显示密码"},
"password_input.hide": {"Hide password", "隐藏密码"},
"search_input.search": {"Search", "搜索"},
"search_input.find": {"Find", "查找"},
"search_input.previous": {"Previous match", "上一项"},
"search_input.next": {"Next match", "下一项"},
"search_input.count": {"%d of %d", "第 %d 项,共 %d 项"},
"search_input.none": {"No matches", "无匹配"},
"checkbox.mixed": {"Partly selected", "部分选中"},
"text_area.count": {"%d of %d characters", "%d / %d 字"},
"text_area.over": {"%d characters over the limit", "超出 %d 字"},
})
}
+12
View File
@@ -0,0 +1,12 @@
package core
func init() {
addMessages(map[string][2]string{
"app_shell.collapse": {"Collapse sidebar", "收起侧栏"},
"app_shell.expand": {"Expand sidebar", "展开侧栏"},
"status_bar.label": {"Status bar", "状态栏"},
"status_bar.hidden": {"%d more items", "另有 %d 项"},
"split_pane.divider": {"Divider", "分隔条"},
"split_pane.collapsed": {"Collapsed", "已折叠"},
})
}
+145
View File
@@ -0,0 +1,145 @@
package core
func init() {
addMessages(map[string][2]string{
"option_chain.expiry": {"Expiry", "到期日"},
"option_chain.spot": {"Spot %s", "现价 %s"},
"option_chain.calls": {"Calls", "认购"},
"option_chain.puts": {"Puts", "认沽"},
"option_chain.strike": {"Strike", "行权价"},
"option_chain.bid": {"Bid", "买价"},
"option_chain.ask": {"Ask", "卖价"},
"option_chain.last": {"Last", "最新"},
"option_chain.empty": {"No strikes for this expiry", "该到期日没有合约"},
"option_chain.call_name": {"Call %s: bid %s, ask %s, last %s", "认购 %s:买 %s,卖 %s,最新 %s"},
"option_chain.put_name": {"Put %s: bid %s, ask %s, last %s", "认沽 %s:买 %s,卖 %s,最新 %s"},
"option_chain.itm": {"in the money", "价内"},
"greeks_table.title": {"Greeks", "希腊值"},
"greeks_table.contract": {"Contract", "合约"},
"greeks_table.note_delta": {"Price change per 1 move in the underlying.", "标的每变动 1 时期权价格的变化。"},
"greeks_table.note_gamma": {"Delta change per 1 move in the underlying.", "标的每变动 1 时 Delta 的变化。"},
"greeks_table.note_theta": {"Price change per day as time passes.", "每过一天期权价格的变化。"},
"greeks_table.note_vega": {"Price change per 1 point of volatility.", "波动率每变动 1 个百分点时价格的变化。"},
"greeks_table.note_rho": {"Price change per 1 point of interest rate.", "利率每变动 1 个百分点时价格的变化。"},
"payoff_diagram.readout": {"Price %s · %s %s", "价格 %s · %s %s"},
"payoff_diagram.spot": {"Spot", "现价"},
"payoff_diagram.profit": {"profit", "盈利"},
"payoff_diagram.loss": {"loss", "亏损"},
"payoff_diagram.even": {"break even", "持平"},
"payoff_diagram.breakevens": {"Breakeven:", "盈亏平衡点:"},
"watchlist.groups": {"Watchlists", "自选分组"},
"watchlist.columns": {"Columns", "列设置"},
"watchlist.price": {"Price", "价格"},
"watchlist.change": {"Change", "涨跌"},
"watchlist.volume": {"Volume", "成交量"},
"watchlist.empty": {"No symbols in this list", "该分组没有自选"},
"symbol_search.placeholder": {"Search code or name", "搜索代码或名称"},
"symbol_search.market": {"Market", "市场"},
"symbol_search.all_markets": {"All markets", "全部市场"},
"symbol_search.recent": {"Recent", "最近搜索"},
"symbol_search.searching": {"Searching", "正在搜索"},
"symbol_search.no_results": {"No symbols match", "没有匹配的代码"},
"symbol_search.retry": {"Retry", "重试"},
"market_overview.as_of": {"As of %s", "截至 %s"},
"market_overview.breadth": {"%d advancing, %d declining, %d unchanged", "上涨 %d 家,下跌 %d 家,平盘 %d 家"},
"market_overview.up": {"%d up", "上涨 %d"},
"market_overview.flat": {"%d flat", "平盘 %d"},
"market_overview.down": {"%d down", "下跌 %d"},
"market_status.closed": {"Closed", "已收盘"},
"market_status.pre": {"Pre-market", "盘前"},
"market_status.open": {"Open", "交易中"},
"market_status.after": {"After hours", "盘后"},
"market_status.holiday": {"Holiday", "休市"},
"market_status.next": {"%s at %s (in %s)", "%[2]s %[1]s(%[3]s后)"},
"market_status.now": {"now", "即将"},
"market_status.hm": {"%dh %02dm", "%d小时%02d分"},
"market_status.m": {"%dm", "%d分钟"},
"economic_calendar.countries": {"Countries", "国家或地区"},
"economic_calendar.all_countries": {"All countries", "全部国家或地区"},
"economic_calendar.importance": {"Importance", "重要性"},
"economic_calendar.all": {"All", "全部"},
"economic_calendar.medium_up": {"Medium and high", "中高"},
"economic_calendar.high": {"High", "高"},
"economic_calendar.level_1": {"Low", "低"},
"economic_calendar.level_2": {"Medium", "中"},
"economic_calendar.level_3": {"High", "高"},
"economic_calendar.time": {"Time", "时间"},
"economic_calendar.country": {"Country", "地区"},
"economic_calendar.event": {"Event", "事件"},
"economic_calendar.actual": {"Actual", "实际"},
"economic_calendar.forecast": {"Forecast", "预期"},
"economic_calendar.previous": {"Previous", "前值"},
"economic_calendar.empty": {"No events", "没有事件"},
"earnings_calendar.date": {"Date", "日期"},
"earnings_calendar.timing": {"Timing", "时段"},
"earnings_calendar.symbol": {"Symbol", "代码"},
"earnings_calendar.name": {"Company", "公司"},
"earnings_calendar.estimate": {"EPS est.", "EPS 预期"},
"earnings_calendar.actual": {"EPS actual", "EPS 实际"},
"earnings_calendar.surprise": {"Surprise", "超预期"},
"earnings_calendar.unknown": {"Time not set", "时间未定"},
"earnings_calendar.before": {"Before open", "盘前"},
"earnings_calendar.after": {"After close", "盘后"},
"earnings_calendar.empty": {"No reports", "没有财报"},
"news_feed.unread": {"%d unread", "%d 条未读"},
"news_feed.mark_all": {"Mark all read", "全部标为已读"},
"news_feed.empty": {"No news", "暂无新闻"},
"sentiment_gauge.extreme_fear": {"Extreme fear", "极度恐惧"},
"sentiment_gauge.fear": {"Fear", "恐惧"},
"sentiment_gauge.neutral": {"Neutral", "中性"},
"sentiment_gauge.greed": {"Greed", "贪婪"},
"sentiment_gauge.extreme_greed": {"Extreme greed", "极度贪婪"},
"portfolio_summary.accounts": {"Accounts", "账户"},
"portfolio_summary.all": {"All accounts", "全部账户"},
"portfolio_summary.total": {"Total assets", "总资产"},
"portfolio_summary.day": {"Today's P/L", "当日盈亏"},
"portfolio_summary.return": {"Total return", "累计收益"},
"asset_allocation_chart.asset": {"Asset", "资产"},
"asset_allocation_chart.weight": {"Weight", "占比"},
"asset_allocation_chart.target": {"Target", "目标"},
"asset_allocation_chart.drift": {"Drift", "偏离"},
"asset_allocation_chart.over": {"Over", "超配"},
"asset_allocation_chart.under": {"Under", "低配"},
"performance_chart.portfolio": {"Portfolio", "组合"},
"performance_chart.benchmark": {"Benchmark", "基准"},
"performance_chart.drawdown": {"Max drawdown %s", "最大回撤 %s"},
"performance_chart.drawdown_range": {"Max drawdown %s, from %s to %s", "最大回撤 %s,%s 至 %s"},
"currency_converter.amount": {"Amount", "金额"},
"currency_converter.from": {"From", "源币种"},
"currency_converter.to": {"To", "目标币种"},
"currency_converter.swap": {"Swap currencies", "互换币种"},
"currency_converter.no_rate": {"Rate unavailable", "暂无汇率"},
"currency_converter.rate": {"1 %s = %g %s", "1 %s = %g %s"},
"screener.conditions": {"Conditions", "筛选条件"},
"screener.none": {"No conditions: every symbol passes.", "暂无条件:全部代码通过。"},
"screener.field": {"Field", "字段"},
"screener.compare": {"Comparison", "比较"},
"screener.value": {"Value", "数值"},
"screener.remove": {"Remove condition %d", "删除条件 %d"},
"screener.add": {"Add condition", "添加条件"},
"screener.save": {"Save conditions", "保存条件"},
"screener.matches": {"%d of %d match", "%d / %d 符合"},
"screener.symbol": {"Symbol", "代码"},
"screener.empty": {"No symbols match", "没有符合的代码"},
"screener.op_0": {"above", "大于"},
"screener.op_1": {"at least", "大于等于"},
"screener.op_2": {"below", "小于"},
"screener.op_3": {"at most", "小于等于"},
"screener.op_4": {"equal to", "等于"},
})
}
+106
View File
@@ -0,0 +1,106 @@
package core
func init() {
addMessages(map[string][2]string{
"image_cropper.label": {"Crop area", "裁剪区域"},
"image_cropper.rotateLeft": {"Rotate left", "向左旋转"},
"image_cropper.rotateRight": {"Rotate right", "向右旋转"},
"image_annotator.label": {"Annotations", "标注"},
"image_annotator.tool": {"Tool", "工具"},
"image_annotator.select": {"Select", "选择"},
"image_annotator.rect": {"Rectangle", "矩形"},
"image_annotator.arrow": {"Arrow", "箭头"},
"image_annotator.text": {"Text", "文字"},
"image_annotator.textLabel": {"Annotation text", "标注文字"},
"image_annotator.note": {"Note", "注释"},
"image_annotator.delete": {"Delete annotation", "删除标注"},
"image_annotator.count": {"%d annotations", "%d 个标注"},
"image_annotator.selected": {"Annotation %d of %d selected: %s", "已选中第 %d 个标注(共 %d 个):%s"},
"image_thumbnail.failed": {"Failed to load", "加载失败"},
"image_thumbnail.loading": {"Loading", "加载中"},
"lightbox.title": {"Image", "图片"},
"lightbox.close": {"Close", "关闭"},
"lightbox.position": {"%d of %d", "第 %d 张,共 %d 张"},
"lightbox.previous": {"Previous image", "上一张"},
"lightbox.next": {"Next image", "下一张"},
"video_player.label": {"Video", "视频"},
"video_player.empty": {"No video", "暂无视频"},
"video_player.subtitles": {"Subtitles", "字幕"},
"video_player.pip": {"Picture in picture", "画中画"},
"video_player.fullscreen": {"Full screen", "全屏"},
"video_scrubber.label": {"Timeline", "时间轴"},
"video_thumbnail_strip.label": {"Frames", "缩略帧"},
"video_thumbnail_strip.position": {"Frame %d of %d, %s", "第 %d 帧,共 %d 帧,%s"},
"video_thumbnail_strip.previous": {"Previous frame", "上一帧"},
"video_thumbnail_strip.next": {"Next frame", "下一帧"},
"audio_waveform.label": {"Waveform", "波形"},
"audio_waveform.empty": {"No audio", "暂无音频"},
"audio_spectrum.label": {"Spectrum", "频谱"},
"audio_spectrum.empty": {"No signal", "无信号"},
"audio_spectrum.band": {"Band %d", "第 %d 段"},
"volume_control.label": {"Volume", "音量"},
"volume_control.mute": {"Mute", "静音"},
"volume_control.unmute": {"Unmute", "取消静音"},
"playback_speed_control.label": {"Playback speed", "播放速度"},
"media_controls.label": {"Playback", "播放控制"},
"media_controls.play": {"Play", "播放"},
"media_controls.pause": {"Pause", "暂停"},
"media_controls.previous": {"Previous", "上一首"},
"media_controls.next": {"Next", "下一首"},
"media_controls.shuffle": {"Shuffle", "随机播放"},
"media_controls.loopOff": {"Repeat off", "不循环"},
"media_controls.loopAll": {"Repeat all", "列表循环"},
"media_controls.loopOne": {"Repeat one", "单曲循环"},
"playlist.empty": {"The playlist is empty", "播放列表为空"},
"playlist.playing": {"Playing", "正在播放"},
"playlist.remove": {"Remove", "移除"},
"subtitle_editor.start": {"Start", "开始"},
"subtitle_editor.end": {"End", "结束"},
"subtitle_editor.text": {"Text", "文本"},
"subtitle_editor.add": {"Add cue", "添加字幕"},
"subtitle_editor.remove": {"Remove cue", "删除字幕"},
"subtitle_editor.empty": {"No cues yet", "还没有字幕"},
"subtitle_editor.badTime": {"Use m:ss.mmm, as 1:05.250", "请使用 m:ss.mmm 格式,例如 1:05.250"},
"subtitle_editor.order": {"End must be after start", "结束时间须晚于开始时间"},
"subtitle_editor.overlap": {"Overlaps cue %d", "与第 %d 条重叠"},
"screen_recorder_controls.label": {"Screen recording", "屏幕录制"},
"screen_recorder_controls.idle": {"Ready", "就绪"},
"screen_recorder_controls.recording": {"Recording", "录制中"},
"screen_recorder_controls.paused": {"Paused", "已暂停"},
"screen_recorder_controls.start": {"Record", "开始录制"},
"screen_recorder_controls.pause": {"Pause", "暂停"},
"screen_recorder_controls.resume": {"Resume", "继续"},
"screen_recorder_controls.stop": {"Stop", "停止"},
"camera_preview.label": {"Camera", "摄像头"},
"camera_preview.noSignal": {"No signal", "无信号"},
"camera_preview.mirror": {"Mirror", "镜像"},
"mic_level_meter.label": {"Microphone level", "麦克风电平"},
"mic_level_meter.peak": {"peak", "峰值"},
"device_selector.label": {"Devices", "设备"},
"device_selector.microphone": {"Microphone", "麦克风"},
"device_selector.camera": {"Camera", "摄像头"},
"device_selector.speaker": {"Speaker", "扬声器"},
"device_selector.choose": {"Choose a device", "选择设备"},
"device_selector.none": {"No devices found", "未找到设备"},
"image_compare.before": {"Before", "之前"},
"image_compare.after": {"After", "之后"},
})
}
+256
View File
@@ -0,0 +1,256 @@
package core
import (
"strconv"
"strings"
"time"
"github.com/egoist/mygo/ui"
)
func init() {
addMessages(map[string][2]string{
"channel_list.label": {"Channels", "频道"},
"channel_list.unread": {"%s, %d unread", "%s,%d 条未读"},
"channel_list.pinned": {"Pinned", "已置顶"},
"channel_list.muted": {"Muted", "已静音"},
"chat_message.time": {"15:04", "15:04"},
"chat_message.edited": {"(edited)", "(已编辑)"},
"unread_divider.new": {"New", "新消息"},
"unread_divider.count": {"%d new messages", "%d 条新消息"},
"read_receipt.sent": {"Sent", "已发送"},
"read_receipt.delivered": {"Delivered", "已送达"},
"read_receipt.read": {"Read", "已读"},
"read_receipt.readBy": {"Read by %s", "%s 已读"},
"member_list.empty": {"No members", "没有成员"},
"user_profile_card.label": {"User profile", "用户资料"},
"recipient_input.label": {"Recipients", "收件人"},
"member_list.online": {"Online — %d", "在线 — %d"},
"member_list.offline": {"Offline — %d", "离线 — %d"},
"online_status.online": {"Online", "在线"},
"online_status.away": {"Away", "离开"},
"online_status.busy": {"Busy", "忙碌"},
"online_status.offline": {"Offline", "离线"},
"status_setter.label": {"Status", "状态"},
"status_setter.emoji": {"Choose an emoji", "选择表情"},
"status_setter.text": {"Status text", "状态文字"},
"status_setter.placeholder": {"What is your status?", "你现在的状态是?"},
"status_setter.clearAfter": {"Clear after", "清除时间"},
"status_setter.never": {"Don't clear", "不清除"},
"status_setter.30m": {"30 minutes", "30 分钟"},
"status_setter.1h": {"1 hour", "1 小时"},
"status_setter.4h": {"4 hours", "4 小时"},
"status_setter.today": {"Today", "今天"},
"status_setter.week": {"This week", "本周"},
"status_setter.clear": {"Clear status", "清除状态"},
"call_controls.label": {"Call controls", "通话控制"},
"call_controls.mute": {"Mute", "静音"},
"call_controls.unmute": {"Unmute", "取消静音"},
"call_controls.cameraOff": {"Turn camera off", "关闭摄像头"},
"call_controls.cameraOn": {"Turn camera on", "打开摄像头"},
"call_controls.share": {"Share screen", "共享屏幕"},
"call_controls.stopShare": {"Stop sharing", "停止共享"},
"call_controls.hangUp": {"Leave", "挂断"},
"video_call_grid.label": {"Participants", "参与者"},
"video_call_grid.speaking": {"speaking", "正在发言"},
"video_call_grid.muted": {"muted", "已静音"},
"video_call_grid.cameraOff": {"camera off", "摄像头已关闭"},
"incoming_call_dialog.title": {"%s is calling", "%s 来电"},
"incoming_call_dialog.voice": {"Incoming voice call", "语音来电"},
"incoming_call_dialog.video": {"Incoming video call", "视频来电"},
"incoming_call_dialog.accept": {"Accept", "接听"},
"incoming_call_dialog.acceptVideo": {"With video", "视频接听"},
"incoming_call_dialog.decline": {"Decline", "拒绝"},
"emoji_picker.label": {"Emoji", "表情"},
"emoji_picker.search": {"Search emoji", "搜索表情"},
"emoji_picker.none": {"No emoji found", "没有找到表情"},
"emoji_picker.tone": {"Skin tone", "肤色"},
"emoji_picker.toneN": {"Skin tone %d", "肤色 %d"},
"emoji_picker.recent": {"Recent", "最近使用"},
"emoji_picker.smileys": {"Smileys", "表情"},
"emoji_picker.people": {"People", "人物"},
"emoji_picker.nature": {"Nature", "自然"},
"emoji_picker.food": {"Food and drink", "食物"},
"emoji_picker.activities": {"Activities", "活动"},
"emoji_picker.travel": {"Places", "地点"},
"emoji_picker.objects": {"Objects", "物品"},
"emoji_picker.symbols": {"Symbols", "符号"},
"emoji_picker.name_grinning_face": {"grinning face", "笑脸"},
"emoji_picker.name_smiling_face_with_open_mouth": {"smiling face with open mouth", "张嘴笑脸"},
"emoji_picker.name_face_with_tears_of_joy": {"face with tears of joy", "笑哭"},
"emoji_picker.name_slightly_smiling_face": {"slightly smiling face", "微笑"},
"emoji_picker.name_winking_face": {"winking face", "眨眼"},
"emoji_picker.name_smiling_face_with_smiling_eyes": {"smiling face with smiling eyes", "眉眼带笑"},
"emoji_picker.name_smiling_face_with_heart_eyes": {"smiling face with heart eyes", "爱心眼睛"},
"emoji_picker.name_face_blowing_a_kiss": {"face blowing a kiss", "飞吻"},
"emoji_picker.name_thinking_face": {"thinking face", "思考"},
"emoji_picker.name_neutral_face": {"neutral face", "面无表情"},
"emoji_picker.name_face_with_rolling_eyes": {"face with rolling eyes", "翻白眼"},
"emoji_picker.name_sleeping_face": {"sleeping face", "睡觉"},
"emoji_picker.name_smiling_face_with_sunglasses": {"smiling face with sunglasses", "墨镜笑脸"},
"emoji_picker.name_star_struck": {"star struck", "星星眼"},
"emoji_picker.name_crying_face": {"crying face", "哭泣"},
"emoji_picker.name_pouting_face": {"pouting face", "生气"},
"emoji_picker.name_face_screaming_in_fear": {"face screaming in fear", "惊恐"},
"emoji_picker.name_partying_face": {"partying face", "庆祝"},
"emoji_picker.name_waving_hand": {"waving hand", "挥手"},
"emoji_picker.name_thumbs_up": {"thumbs up", "赞"},
"emoji_picker.name_thumbs_down": {"thumbs down", "踩"},
"emoji_picker.name_clapping_hands": {"clapping hands", "鼓掌"},
"emoji_picker.name_raising_hands": {"raising hands", "举双手"},
"emoji_picker.name_folded_hands": {"folded hands", "合十"},
"emoji_picker.name_ok_hand": {"ok hand", "好手势"},
"emoji_picker.name_victory_hand": {"victory hand", "胜利手势"},
"emoji_picker.name_handshake": {"handshake", "握手"},
"emoji_picker.name_flexed_biceps": {"flexed biceps", "肌肉"},
"emoji_picker.name_writing_hand": {"writing hand", "写字"},
"emoji_picker.name_eyes": {"eyes", "眼睛"},
"emoji_picker.name_person": {"person", "人物"},
"emoji_picker.name_crown": {"crown", "王冠"},
"emoji_picker.name_performing_arts_masks": {"performing arts masks", "戏剧面具"},
"emoji_picker.name_woman_dancing": {"woman dancing", "跳舞"},
"emoji_picker.name_rose": {"rose", "玫瑰"},
"emoji_picker.name_wilted_flower": {"wilted flower", "枯萎的花"},
"emoji_picker.name_cherry_blossom": {"cherry blossom", "樱花"},
"emoji_picker.name_crescent_moon": {"crescent moon", "新月"},
"emoji_picker.name_star": {"star", "星星"},
"emoji_picker.name_fire": {"fire", "火"},
"emoji_picker.name_cloud_with_rain": {"cloud with rain", "雨云"},
"emoji_picker.name_snowflake": {"snowflake", "雪花"},
"emoji_picker.name_black_cat": {"black cat", "黑猫"},
"emoji_picker.name_bat": {"bat", "蝙蝠"},
"emoji_picker.name_black_bird": {"black bird", "黑鸟"},
"emoji_picker.name_dove": {"dove", "鸽子"},
"emoji_picker.name_fallen_leaf": {"fallen leaf", "落叶"},
"emoji_picker.name_evergreen_tree": {"evergreen tree", "常青树"},
"emoji_picker.name_water_wave": {"water wave", "海浪"},
"emoji_picker.name_rainbow": {"rainbow", "彩虹"},
"emoji_picker.name_wine_glass": {"wine glass", "红酒杯"},
"emoji_picker.name_clinking_glasses": {"clinking glasses", "碰杯"},
"emoji_picker.name_hot_beverage": {"hot beverage", "热饮"},
"emoji_picker.name_teacup": {"teacup", "茶杯"},
"emoji_picker.name_shortcake": {"shortcake", "蛋糕"},
"emoji_picker.name_chocolate_bar": {"chocolate bar", "巧克力"},
"emoji_picker.name_strawberry": {"strawberry", "草莓"},
"emoji_picker.name_grapes": {"grapes", "葡萄"},
"emoji_picker.name_red_apple": {"red apple", "红苹果"},
"emoji_picker.name_cheese_wedge": {"cheese wedge", "奶酪"},
"emoji_picker.name_baguette": {"baguette", "法棍"},
"emoji_picker.name_bread": {"bread", "面包"},
"emoji_picker.name_violin": {"violin", "小提琴"},
"emoji_picker.name_musical_keyboard": {"musical keyboard", "键盘"},
"emoji_picker.name_guitar": {"guitar", "吉他"},
"emoji_picker.name_drum": {"drum", "鼓"},
"emoji_picker.name_microphone": {"microphone", "麦克风"},
"emoji_picker.name_musical_note": {"musical note", "音符"},
"emoji_picker.name_musical_notes": {"musical notes", "多个音符"},
"emoji_picker.name_party_popper": {"party popper", "礼花"},
"emoji_picker.name_trophy": {"trophy", "奖杯"},
"emoji_picker.name_artist_palette": {"artist palette", "调色盘"},
"emoji_picker.name_chess_pawn": {"chess pawn", "棋子"},
"emoji_picker.name_clapper_board": {"clapper board", "场记板"},
"emoji_picker.name_castle": {"castle", "城堡"},
"emoji_picker.name_church": {"church", "教堂"},
"emoji_picker.name_tower": {"tower", "塔"},
"emoji_picker.name_night_with_stars": {"night with stars", "星夜"},
"emoji_picker.name_locomotive": {"locomotive", "火车"},
"emoji_picker.name_airplane": {"airplane", "飞机"},
"emoji_picker.name_automobile": {"automobile", "汽车"},
"emoji_picker.name_sailboat": {"sailboat", "帆船"},
"emoji_picker.name_world_map": {"world map", "世界地图"},
"emoji_picker.name_snow_capped_mountain": {"snow capped mountain", "雪山"},
"emoji_picker.name_sunrise": {"sunrise", "日出"},
"emoji_picker.name_ferris_wheel": {"ferris wheel", "摩天轮"},
"emoji_picker.name_candle": {"candle", "蜡烛"},
"emoji_picker.name_old_key": {"old key", "旧钥匙"},
"emoji_picker.name_scroll": {"scroll", "卷轴"},
"emoji_picker.name_envelope": {"envelope", "信封"},
"emoji_picker.name_paperclip": {"paperclip", "回形针"},
"emoji_picker.name_pushpin": {"pushpin", "图钉"},
"emoji_picker.name_calendar": {"calendar", "日历"},
"emoji_picker.name_light_bulb": {"light bulb", "灯泡"},
"emoji_picker.name_bell": {"bell", "铃铛"},
"emoji_picker.name_locked": {"locked", "锁"},
"emoji_picker.name_gem_stone": {"gem stone", "宝石"},
"emoji_picker.name_hourglass": {"hourglass", "沙漏"},
"emoji_picker.name_red_heart": {"red heart", "红心"},
"emoji_picker.name_black_heart": {"black heart", "黑心"},
"emoji_picker.name_broken_heart": {"broken heart", "心碎"},
"emoji_picker.name_sparkles": {"sparkles", "闪光"},
"emoji_picker.name_check_mark_button": {"check mark button", "勾选"},
"emoji_picker.name_cross_mark": {"cross mark", "叉号"},
"emoji_picker.name_exclamation_mark": {"exclamation mark", "感叹号"},
"emoji_picker.name_question_mark": {"question mark", "问号"},
"emoji_picker.name_hundred_points": {"hundred points", "满分"},
"emoji_picker.name_diamond_suit": {"diamond suit", "方块"},
"emoji_picker.name_fleur_de_lis": {"fleur de lis", "鸢尾花纹"},
"emoji_picker.name_red_triangle": {"red triangle", "红三角"},
"pinned_messages.title": {"Pinned messages (%d)", "置顶消息(%d)"},
"pinned_messages.empty": {"No pinned messages", "没有置顶消息"},
"pinned_messages.unpin": {"Unpin %s's message", "取消置顶 %s 的消息"},
"thread_panel.title": {"Thread", "话题"},
"thread_panel.close": {"Close thread", "关闭话题"},
"thread_panel.replies": {"%d replies", "%d 条回复"},
"thread_panel.reply": {"Reply in thread", "在话题中回复"},
"thread_panel.send": {"Send", "发送"},
"mail_list.empty": {"No mail", "没有邮件"},
"mail_list.star": {"Star %s", "星标 %s"},
"mail_list.starred": {"Starred", "已加星标"},
"mail_list.unread": {"Unread", "未读"},
"mail_list.attachments": {"%d attachments", "%d 个附件"},
"mail_list.date": {"Jan 2", "1月2日"},
"mail_reader.to": {"To:", "收件人:"},
"mail_reader.cc": {"Cc:", "抄送:"},
"mail_reader.date": {"Mon, Jan 2 2006 15:04", "2006年1月2日 {weekday} 15:04"},
"mail_reader.attachments": {"Attachments", "附件"},
"mail_composer.label": {"New message", "新邮件"},
"mail_composer.to": {"To", "收件人"},
"mail_composer.cc": {"Cc", "抄送"},
"mail_composer.bcc": {"Bcc", "密送"},
"mail_composer.subject": {"Subject", "主题"},
"mail_composer.body": {"Message", "正文"},
"mail_composer.send": {"Send", "发送"},
"mail_composer.attach": {"Attach", "添加附件"},
"mail_composer.discard": {"Discard", "舍弃"},
"mail_composer.unsaved": {"Unsaved changes", "有未保存的更改"},
"mail_composer.saved": {"Draft saved %s", "草稿已于 %s 保存"},
"recipient_input.invalid": {"%q is not an email address", "“%s”不是有效的邮箱地址"},
"recipient_input.suggestions": {"Contacts", "联系人"},
"quoted_text.showOne": {"Show quoted text (1 line)", "显示引用内容(1 行)"},
"quoted_text.show": {"Show quoted text (%d lines)", "显示引用内容(%d 行)"},
"quoted_text.hide": {"Hide quoted text", "隐藏引用内容"},
"snooze_picker.label": {"Snooze until", "稍后提醒"},
"snooze_picker.later": {"Later today", "今天稍晚"},
"snooze_picker.tomorrow": {"Tomorrow", "明天"},
"snooze_picker.weekend": {"This weekend", "本周末"},
"snooze_picker.nextWeek": {"Next week", "下周"},
"snooze_picker.custom": {"Pick date and time", "选择日期和时间"},
"snooze_picker.set": {"Snooze", "设定提醒"},
"snooze_picker.when": {"Mon 15:04", "{weekday} 15:04"},
"status_setter.until": {"Mon 15:04", "{weekday} 15:04"},
})
}
func MessagingDate(c *ui.Context, date time.Time, key string) string {
weekday := Msg(c, "calendar.weekday_long_"+strconv.Itoa(int(date.Weekday())))
return strings.ReplaceAll(date.Format(Msg(c, key)), "{weekday}", weekday)
}
+76
View File
@@ -0,0 +1,76 @@
package core
func init() {
addMessages(map[string][2]string{
"candlestick_chart.daily_time": {"Jan 2", "1月2日"},
"candlestick_chart.ohlc": {"O %s H %s L %s C %s", "开 %s 高 %s 低 %s 收 %s"},
"candlestick_chart.volume": {"Vol", "量"},
"heikin_ashi_chart.smoothed": {"Heikin-Ashi", "平均 K 线"},
"heikin_ashi_chart.raw": {"Candles", "原 K 线"},
"heikin_ashi_chart.switch": {"Candle style", "K 线样式"},
"compare_symbol.label": {"Compared symbols", "对比品种"},
"compare_symbol.remove": {"Remove %s", "移除 %s"},
"price_alert_line.tag": {"Alert %s", "预警 %s"},
"chart_sync.link": {"Sync with other charts", "与其他图表同步"},
"chart_sync.linked": {"Synced", "已同步"},
"chart_sync.unlinked": {"Not synced", "未同步"},
"indicator_pane.remove": {"Remove %s", "移除 %s"},
"line_quote_chart.price": {"Price", "价格"},
"line_quote_chart.average": {"Average", "均价"},
"line_quote_chart.pre": {"Pre-market", "盘前"},
"line_quote_chart.after": {"After hours", "盘后"},
"depth_chart.bids": {"Bids", "买盘"},
"depth_chart.asks": {"Asks", "卖盘"},
"depth_chart.bid": {"Bid", "买"},
"depth_chart.ask": {"Ask", "卖"},
"depth_chart.total": {"cumulative %s", "累计 %s"},
"depth_chart.mid": {"Mid", "中间价"},
"volume_profile.value_area": {"Value area", "价值区"},
"volume_profile.other": {"Outside", "区外"},
"volume_profile.poc": {"POC", "控制点"},
"volume_profile.vah": {"VAH", "价值区上沿"},
"volume_profile.val": {"VAL", "价值区下沿"},
"time_range_selector.custom": {"Custom", "自定义"},
"time_range_selector.label": {"Time range", "时间范围"},
"interval_selector.label": {"Interval", "周期"},
"interval_selector.all": {"All intervals", "全部周期"},
"interval_selector.minutes": {"Minutes", "分钟"},
"interval_selector.hours": {"Hours", "小时"},
"interval_selector.days": {"Days and longer", "日及以上"},
"interval_selector.favorite": {"Add %s to favorites", "收藏 %s"},
"interval_selector.unfavorite": {"Remove %s from favorites", "取消收藏 %s"},
"chart_type_switcher.label": {"Chart type", "图表类型"},
"chart_type_switcher.type0": {"Candles", "K 线"},
"chart_type_switcher.type1": {"OHLC", "美国线"},
"chart_type_switcher.type2": {"Line", "折线"},
"chart_type_switcher.type3": {"Area", "面积"},
"chart_type_switcher.type4": {"Heikin-Ashi", "平均 K 线"},
"candle_countdown.label": {"%s candle closes in %s", "%s K 线 %s 后收盘"},
"multi_chart_layout.label": {"Chart layout", "图表布局"},
"multi_chart_layout.count": {"%d charts", "%d 宫格"},
"multi_chart_layout.cell": {"Chart %d %s", "图表 %d %s"},
"drawing_toolbar.label": {"Drawing tools", "画线工具"},
"drawing_toolbar.tool0": {"Select", "选择"},
"drawing_toolbar.tool1": {"Trend line", "趋势线"},
"drawing_toolbar.tool2": {"Horizontal line", "水平线"},
"drawing_toolbar.tool3": {"Fibonacci", "斐波那契"},
"drawing_toolbar.tool4": {"Rectangle", "矩形"},
"drawing_toolbar.tool5": {"Text", "文字"},
"drawing_toolbar.lock": {"Lock drawings", "锁定画线"},
"drawing_toolbar.unlock": {"Unlock drawings", "解锁画线"},
"drawing_toolbar.undo": {"Undo", "撤销"},
"drawing_toolbar.clear": {"Clear drawings", "清除画线"},
"indicator_selector.button": {"Indicators (%d)", "指标(%d)"},
"indicator_selector.title": {"Indicators", "指标"},
"indicator_selector.search": {"Search indicators", "搜索指标"},
"indicator_selector.available": {"Available", "可添加"},
"indicator_selector.active": {"On the chart", "已添加"},
"indicator_selector.overlay": {"Over prices", "主图叠加"},
"indicator_selector.pane": {"Own pane", "副图"},
"indicator_selector.add": {"Add", "添加"},
"indicator_selector.add_named": {"Add %s", "添加 %s"},
"indicator_selector.none": {"No indicator matches", "没有匹配的指标"},
"drawing_tools.selected": {"Drawing %d selected", "已选择画线 %d"},
"drawing_tools.note": {"Note", "标注"},
})
}
+63
View File
@@ -0,0 +1,63 @@
package core
func init() {
addMessages(map[string][2]string{
"interrupt_button.stop": {"Stop", "停止"},
"interrupt_button.stopping": {"Stopping", "正在停止"},
"interrupt_button.confirm": {"Stop the agent?", "停止智能体?"},
"interrupt_button.detail": {"Work in progress will be lost.", "进行中的工作将会丢失。"},
"interrupt_button.keep": {"Keep running", "继续运行"},
"token_usage_chart.label": {"Token usage", "Token 用量"},
"token_usage_chart.input": {"Input", "输入"},
"token_usage_chart.output": {"Output", "输出"},
"cost_breakdown.model": {"Model", "模型"},
"cost_breakdown.tool": {"Tool", "工具"},
"cost_breakdown.step": {"Step", "步骤"},
"cost_breakdown.calls": {"Calls", "调用"},
"cost_breakdown.input": {"Input tokens", "输入 token"},
"cost_breakdown.output": {"Output tokens", "输出 token"},
"cost_breakdown.cost": {"Cost", "费用"},
"cost_breakdown.empty": {"No costs yet", "暂无费用"},
"cost_breakdown.unnamed": {"(unnamed)", "(未命名)"},
"cost_breakdown.total": {"Total", "合计"},
"cost_breakdown.total_name": {"Total %s over %d calls", "合计 %s,共 %d 次调用"},
"cost_breakdown.tokens": {"%d in · %d out", "输入 %d · 输出 %d"},
"trace_viewer.span": {"Span", "跨度"},
"trace_viewer.duration": {"Duration", "耗时"},
"trace_viewer.timeline": {"Timeline", "时间轴"},
"trace_viewer.start": {"Start", "开始"},
"trace_viewer.failed": {"failed", "失败"},
"trace_viewer.empty": {"No spans", "没有跨度"},
"eval_result_table.case": {"Case", "用例"},
"eval_result_table.score": {"Score", "得分"},
"eval_result_table.result": {"Result", "结果"},
"eval_result_table.pass": {"Pass", "通过"},
"eval_result_table.fail": {"Fail", "失败"},
"eval_result_table.diff": {"View differences for %s", "查看 %s 的差异"},
"eval_result_table.view": {"View differences", "查看差异"},
"eval_result_table.summary": {"%d of %d passed", "通过 %d / %d"},
"eval_result_table.empty": {"No eval cases", "没有评测用例"},
"tool_registry_panel.empty": {"No tools", "没有工具"},
"tool_registry_panel.choose": {"Choose a tool to see its parameters", "选择工具查看参数"},
"tool_registry_panel.no_params": {"No parameters", "无参数"},
"tool_registry_panel.enable": {"Enable %s", "启用 %s"},
"tool_registry_panel.required": {"required", "必填"},
"dots_loader.loading": {"Loading", "加载中"},
"bars_loader.loading": {"Loading", "加载中"},
"pulse_loader.loading": {"Loading", "加载中"},
"orbit_loader.loading": {"Loading", "加载中"},
"wave_loader.loading": {"Loading", "加载中"},
"shimmer.loading": {"Loading", "加载中"},
"typewriter.skip": {"Skip", "跳过"},
"blink_highlight.up": {"up", "上升"},
"blink_highlight.down": {"down", "下降"},
})
}
+36
View File
@@ -0,0 +1,36 @@
package core
func init() {
addMessages(map[string][2]string{
"breadcrumb.label": {"Breadcrumb", "路径导航"},
"breadcrumb.current": {"current page", "当前页"},
"breadcrumb.more": {"Show hidden path", "显示折叠的路径"},
"pagination.label": {"Pagination", "分页"},
"pagination.total": {"%d items", "共 %d 条"},
"pagination.prev": {"Previous page", "上一页"},
"pagination.next": {"Next page", "下一页"},
"pagination.page": {"Page %d", "第 %d 页"},
"pagination.current": {"current", "当前"},
"pagination.size": {"Page size", "每页条数"},
"pagination.per_page": {"%d / page", "%d 条/页"},
"pagination.jump": {"Go to", "跳至"},
"pagination.field": {"Page number", "页码"},
"pagination.range": {"1–%d", "1–%d"},
"steps.item": {"Step %d of %d: %s, %s", "第 %d 步,共 %d 步:%s,%s"},
"steps.waiting": {"waiting", "等待"},
"steps.current": {"current", "进行中"},
"steps.done": {"done", "已完成"},
"steps.error": {"failed", "出错"},
"navigation_menu.label": {"Site navigation", "导航菜单"},
"navigation_menu.back": {"Back", "后退"},
"navigation_menu.forward": {"Forward", "前进"},
"menubar.label": {"Menu bar", "菜单栏"},
"menubar.checked": {"checked", "已勾选"},
"command_palette.label": {"Command palette", "命令面板"},
"command_palette.search": {"Search commands", "搜索命令"},
"command_palette.empty": {"No matching commands", "没有匹配的命令"},
"command_palette.hint_move": {"↑↓ choose", "↑↓ 选择"},
"command_palette.hint_run": {"Enter run", "Enter 执行"},
"command_palette.hint_close": {"Esc close", "Esc 关闭"},
})
}
+13
View File
@@ -0,0 +1,13 @@
package core
func init() {
addMessages(map[string][2]string{
"dialog.close": {"Close", "关闭"},
"alert_dialog.cancel": {"Cancel", "取消"},
"alert_dialog.confirm": {"Delete", "删除"},
"alert_dialog.type_to_unlock": {"Type “%s” to confirm", "输入“%s”以确认"},
"drawer.close": {"Close", "关闭"},
"popconfirm.confirm": {"Confirm", "确定"},
"popconfirm.cancel": {"Cancel", "取消"},
})
}
+120
View File
@@ -0,0 +1,120 @@
package core
func init() {
addMessages(map[string][2]string{
"projects.overdue": {"Overdue by %d days", "逾期 %d 天"},
"projects.overdue_one": {"Overdue by %d day", "逾期 %d 天"},
"projects.due_today": {"Due today", "今天到期"},
"projects.due_tomorrow": {"Due tomorrow", "明天到期"},
"projects.due": {"Due %s %d", "%s%d日到期"},
"priority_indicator.none": {"No priority", "无优先级"},
"priority_indicator.low": {"Low", "低"},
"priority_indicator.medium": {"Medium", "中"},
"priority_indicator.high": {"High", "高"},
"priority_indicator.urgent": {"Urgent", "紧急"},
"issue_card.description": {"%s, %s", "%s,%s"},
"issue_id_badge.copy": {"Copy %s", "复制 %s"},
"issue_id_badge.copied": {"Copied", "已复制"},
"issue_id_badge.copied_label": {"%s copied", "已复制 %s"},
"status_select.label": {"Status", "状态"},
"status_select.backlog": {"Backlog", "待规划"},
"status_select.unstarted": {"To do", "未开始"},
"status_select.started": {"In progress", "进行中"},
"status_select.completed": {"Done", "已完成"},
"status_select.canceled": {"Canceled", "已取消"},
"assignee_picker.label": {"Assignees", "负责人"},
"assignee_picker.placeholder": {"Unassigned", "未分配"},
"due_date_picker.label": {"Due date", "截止日期"},
"due_date_picker.today": {"Today", "今天"},
"due_date_picker.tomorrow": {"Tomorrow", "明天"},
"due_date_picker.next_week": {"Next week", "下周"},
"task_item.rename": {"Task title", "任务标题"},
"subtask_list.label": {"Subtasks", "子任务"},
"subtask_list.progress": {"%d of %d done", "已完成 %d / %d"},
"subtask_list.drag": {"Drag %s", "拖动 %s"},
"subtask_list.remove": {"Remove %s", "删除 %s"},
"subtask_list.add": {"Add a subtask", "添加子任务"},
"label_manager.label": {"Labels", "标签"},
"label_manager.edit": {"Edit %s", "编辑 %s"},
"label_manager.delete": {"Delete %s", "删除 %s"},
"label_manager.empty": {"No labels yet.", "暂无标签。"},
"label_manager.new": {"New label", "新建标签"},
"label_manager.name": {"Label name", "标签名称"},
"label_manager.color": {"Color", "颜色"},
"label_manager.taken": {"A label named %q exists.", "已有名为 %q 的标签。"},
"label_manager.accent": {"Crimson", "酒红"},
"label_manager.info": {"Blue", "蓝"},
"label_manager.success": {"Green", "绿"},
"label_manager.warning": {"Amber", "琥珀"},
"label_manager.danger": {"Red", "红"},
"label_manager.neutral": {"Gray", "灰"},
"task_list.label": {"Tasks", "任务"},
"task_list.filter": {"Show", "显示"},
"task_list.all": {"All %d", "全部 %d"},
"task_list.open": {"Open %d", "未完成 %d"},
"task_list.done": {"Done %d", "已完成 %d"},
"task_list.empty": {"No tasks here.", "这里没有任务。"},
"task_detail_panel.close": {"Close details", "关闭详情"},
"task_detail_panel.title": {"Title", "标题"},
"task_detail_panel.status": {"Status", "状态"},
"task_detail_panel.priority": {"Priority", "优先级"},
"task_detail_panel.activity": {"Activity", "活动记录"},
"kanban_board.label": {"Board", "看板"},
"kanban_board.full": {"%s is at its limit of %d cards.", "%s 已达 %d 张卡片的上限。"},
"kanban_board.wip": {"%d of %d cards", "%d / %d 张卡片"},
"kanban_board.over": {"%d over the limit", "超出上限 %d 张"},
"kanban_board.empty": {"No cards", "暂无卡片"},
"sprint_board.time": {"Time", "时间"},
"sprint_board.done": {"%d of %d done", "已完成 %d / %d"},
"sprint_board.progress": {"Sprint progress", "迭代进度"},
"sprint_board.starts_in": {"Starts in %d days", "%d 天后开始"},
"sprint_board.starts_in_one": {"Starts in %d day", "%d 天后开始"},
"sprint_board.ended": {"Ended", "已结束"},
"sprint_board.left": {"%d days left", "剩余 %d 天"},
"sprint_board.left_one": {"%d day left", "剩余 %d 天"},
"milestone_progress.count": {"%d of %d tasks done", "已完成 %d / %d 个任务"},
"milestone_progress.reached": {"Reached", "已达成"},
"workload_view.label": {"Workload", "工作负载"},
"workload_view.hours": {"h", "小时"},
"workload_view.over": {"over by %s %s", "超出 %s %s"},
"workload_view.overloaded": {"%d people are over capacity", "%d 人超出负荷"},
"workload_view.overloaded_one": {"%d person is over capacity", "%d 人超出负荷"},
"time_tracker.label": {"Time tracked", "已记录时间"},
"time_tracker.start": {"Start", "开始"},
"time_tracker.stop": {"Stop", "停止"},
"time_tracker.running": {"Tracking…", "计时中…"},
"time_tracker.correct": {"Correct the total", "修正总时长"},
"time_tracker.apply": {"Apply", "应用"},
"pomodoro_timer.label": {"Pomodoro timer", "番茄钟"},
"pomodoro_timer.focus": {"Focus", "专注"},
"pomodoro_timer.break": {"Short break", "短休息"},
"pomodoro_timer.long_break": {"Long break", "长休息"},
"pomodoro_timer.done": {"%s finished.", "%s结束。"},
"pomodoro_timer.left": {"%s, %s left", "%s,剩余 %s"},
"pomodoro_timer.sessions": {"%d of %d sessions before a long break", "距长休息:%d / %d 轮"},
"pomodoro_timer.start": {"Start", "开始"},
"pomodoro_timer.pause": {"Pause", "暂停"},
"pomodoro_timer.skip": {"Skip", "跳过"},
"pomodoro_timer.reset": {"Reset", "重置"},
"burndown_chart.actual": {"Remaining", "剩余"},
"burndown_chart.ideal": {"Ideal", "理想"},
})
}
+161
View File
@@ -0,0 +1,161 @@
package core
func init() {
addMessages(map[string][2]string{
"price_text.up": {"up", "上涨"},
"price_text.down": {"down", "下跌"},
"price_text.flat": {"unchanged", "平"},
"ticker_tape.label": {"Market ticker", "行情滚动条"},
"ticker_tape.pause_hint": {"Pauses under the pointer or keyboard focus", "指针悬停或键盘聚焦时暂停"},
"ticker_tape.previous": {"Previous page", "上一页"},
"ticker_tape.next": {"Next page", "下一页"},
"spread_indicator.title": {"Spread", "价差"},
"spread_indicator.value": {"%s (%s%%)", "%s(%s%%)"},
"spread_indicator.wide": {"Wide spread", "价差过大"},
"spread_indicator.crossed": {"Crossed market", "买卖价倒挂"},
"bid_ask_bar.label": {"Bid and ask volume", "买卖力量"},
"bid_ask_bar.buy": {"Buy %s%% · %s", "买 %s%% · %s"},
"bid_ask_bar.sell": {"%s · Sell %s%%", "%s · 卖 %s%%"},
"risk_meter.label": {"Risk level", "风险等级"},
"risk_meter.value": {"Level %d of %d, %s.", "第 %d 级,共 %d 级,%s。"},
"risk_meter.level1": {"Low", "低"},
"risk_meter.level2": {"Moderately low", "中低"},
"risk_meter.level3": {"Medium", "中"},
"risk_meter.level4": {"Moderately high", "中高"},
"risk_meter.level5": {"High", "高"},
"margin_indicator.label": {"Margin ratio", "保证金率"},
"margin_indicator.safe": {"Safe", "安全"},
"margin_indicator.warning": {"Margin call", "追加保证金"},
"margin_indicator.liquidation": {"Liquidation", "强制平仓"},
"margin_indicator.warning_line": {"Warning line", "警戒线"},
"margin_indicator.liquidation_line": {"Liquidation line", "强平线"},
"margin_indicator.spoken": {"%s, %s. Warning at %s, liquidation at %s.", "%s,%s。警戒线 %s,强平线 %s。"},
"pnl_display.label": {"Profit and loss", "盈亏"},
"pnl_display.realized": {"Realized", "已实现"},
"pnl_display.unrealized": {"Unrealized", "未实现"},
"pnl_display.today": {"Today", "当日"},
"pnl_display.masked": {"hidden", "已隐藏"},
"pnl_display.hide": {"Hide amounts", "隐藏金额"},
"pnl_display.show": {"Show amounts", "显示金额"},
"order_book.label": {"Order book", "盘口"},
"order_book.group": {"Group", "合并档位"},
"order_book.price": {"Price", "价格"},
"order_book.size": {"Size", "数量"},
"order_book.total": {"Total", "累计"},
"order_book.side1": {"Bid", "买"},
"order_book.side2": {"Ask", "卖"},
"order_book.level": {"%s %s, size %s", "%s %s,数量 %s"},
"level2_quotes.label": {"Level 2 quotes", "多档行情"},
"level2_quotes.side1": {"B%d", "买%d"},
"level2_quotes.side2": {"S%d", "卖%d"},
"level2_quotes.orders": {"%d orders", "%d 笔委托"},
"time_and_sales.title": {"Time and sales", "逐笔成交"},
"time_and_sales.pause": {"Pause", "暂停跟随"},
"time_and_sales.resume": {"Resume", "继续跟随"},
"time_and_sales.resume_count": {"Resume (%d new)", "继续跟随(%d 笔新成交)"},
"time_and_sales.time": {"Time", "时间"},
"time_and_sales.price": {"Price", "价格"},
"time_and_sales.size": {"Size", "数量"},
"time_and_sales.large": {"large trade", "大单"},
"time_and_sales.empty": {"No trades yet", "暂无成交"},
"depth_ladder.label": {"Price ladder", "价格阶梯"},
"depth_ladder.bid": {"Bid", "买量"},
"depth_ladder.price": {"Price", "价格"},
"depth_ladder.ask": {"Ask", "卖量"},
"depth_ladder.last": {"Last price", "最新价"},
"depth_ladder.order1": {"Buy at %s", "以 %s 买入"},
"depth_ladder.order2": {"Sell at %s", "以 %s 卖出"},
"depth_ladder.recenter": {"Center on last price", "回到最新价"},
"order_entry.label": {"Order entry", "下单"},
"order_entry.side": {"Side", "方向"},
"order_entry.buy": {"Buy", "买入"},
"order_entry.sell": {"Sell", "卖出"},
"order_entry.side1": {"Buy", "买入"},
"order_entry.side2": {"Sell", "卖出"},
"order_entry.type": {"Order type", "订单类型"},
"order_entry.type0": {"Limit", "限价"},
"order_entry.type1": {"Market", "市价"},
"order_entry.type2": {"Stop", "止损"},
"order_entry.type3": {"Stop limit", "条件限价"},
"order_entry.quantity": {"Quantity", "数量"},
"order_entry.price": {"Limit price", "限价"},
"order_entry.trigger": {"Trigger price", "触发价"},
"order_entry.tif": {"Time in force", "有效期"},
"order_entry.tif0": {"Day", "当日有效"},
"order_entry.tif1": {"Good till canceled", "撤销前有效"},
"order_entry.tif2": {"Immediate or cancel", "立即成交剩余撤销"},
"order_entry.tif3": {"Fill or kill", "全部成交否则撤销"},
"order_entry.estimate": {"Estimated amount", "预估金额"},
"order_entry.submit1": {"Buy %s", "买入 %s"},
"order_entry.submit2": {"Sell %s", "卖出 %s"},
"order_entry.quantity_positive": {"Enter a quantity above zero.", "请输入大于零的数量。"},
"order_entry.quantity_max": {"At most %s.", "最多 %s。"},
"order_entry.price_positive": {"Enter a price above zero.", "请输入大于零的价格。"},
"order_entry.trigger_positive": {"Enter a trigger price above zero.", "请输入大于零的触发价。"},
"order_entry.trigger_above": {"A buy stop triggers above the last price.", "买入止损的触发价须高于最新价。"},
"order_entry.trigger_below": {"A sell stop triggers below the last price.", "卖出止损的触发价须低于最新价。"},
"quick_trade_buttons.label": {"Quick trade", "快速交易"},
"quick_trade_buttons.quantity": {"Quantity", "数量"},
"quick_trade_buttons.side1": {"Buy %s", "买入 %s"},
"quick_trade_buttons.side2": {"Sell %s", "卖出 %s"},
"quick_trade_buttons.confirm1": {"Buy %s %s?", "买入 %s %s?"},
"quick_trade_buttons.confirm2": {"Sell %s %s?", "卖出 %s %s?"},
"quick_trade_buttons.market": {"The order fills at the market price.", "订单将以市价成交。"},
"position_table.symbol": {"Symbol", "代码"},
"position_table.quantity": {"Quantity", "数量"},
"position_table.cost": {"Avg cost", "成本价"},
"position_table.price": {"Price", "现价"},
"position_table.value": {"Market value", "市值"},
"position_table.pnl": {"Unrealized P/L", "浮动盈亏"},
"position_table.pnl_percent": {"P/L %", "盈亏比例"},
"position_table.action": {"Action", "操作"},
"position_table.close": {"Close", "平仓"},
"position_table.empty": {"No positions", "暂无持仓"},
"order_table.side": {"Side", "方向"},
"order_table.market": {"Market", "市价"},
"order_table.filled": {"Filled", "成交"},
"order_table.status": {"Status", "状态"},
"order_table.status0": {"Open", "未成交"},
"order_table.status1": {"Partly filled", "部分成交"},
"order_table.status2": {"Filled", "已成交"},
"order_table.status3": {"Canceled", "已撤销"},
"order_table.status4": {"Rejected", "已拒绝"},
"order_table.filter": {"Order status", "委托状态"},
"order_table.filter0": {"All", "全部"},
"order_table.filter1": {"Working", "进行中"},
"order_table.filter2": {"Filled", "已成交"},
"order_table.filter3": {"Closed", "已关闭"},
"order_table.cancel": {"Cancel", "撤单"},
"order_table.empty": {"No orders", "暂无委托"},
"trade_history_table.time": {"Time", "时间"},
"trade_history_table.fee": {"Fee", "手续费"},
"trade_history_table.range": {"Date range", "日期范围"},
"trade_history_table.all": {"All dates", "全部日期"},
"trade_history_table.export": {"Export", "导出"},
"trade_history_table.empty": {"No trades in this range", "该范围内无成交"},
"leverage_slider.label": {"Leverage", "杠杆"},
"leverage_slider.warning": {"High risk", "高风险"},
"leverage_slider.danger": {"Very high risk", "极高风险"},
"leverage_slider.apply": {"Apply", "确认"},
"order_confirm_dialog.title": {"Confirm order", "确认下单"},
"order_confirm_dialog.confirm": {"Place order", "确认下单"},
"order_confirm_dialog.cancel": {"Cancel", "取消"},
})
}
+57
View File
@@ -0,0 +1,57 @@
package core
import (
"go/ast"
"go/parser"
"go/token"
"os"
"path/filepath"
"strings"
"testing"
)
func TestMotionDocsMatchExampleBodies(t *testing.T) {
src, err := os.ReadFile("../feedback/example_motion_test.go")
if err != nil {
t.Fatal(err)
}
fs := token.NewFileSet()
file, err := parser.ParseFile(fs, "../feedback/example_motion_test.go", src, 0)
if err != nil {
t.Fatal(err)
}
examples := map[string]string{}
for _, d := range file.Decls {
fn, ok := d.(*ast.FuncDecl)
if !ok {
continue
}
body := string(src[fs.Position(fn.Body.Lbrace).Offset+1 : fs.Position(fn.Body.Rbrace).Offset])
lines := strings.Split(strings.Trim(body, "\n"), "\n")
for i := range lines {
lines[i] = strings.TrimPrefix(lines[i], "\t")
}
examples[strings.TrimPrefix(fn.Name.Name, "Example")] = strings.TrimSpace(strings.Join(lines, "\n"))
}
count := 0
for path, doc := range readGlob(t, "../docs/components/*.md") {
id := filepath.Base(path)[:3]
if id < "281" || id > "300" {
continue
}
name := strings.Fields(strings.SplitN(doc, "\n", 2)[0])[2]
block := docsGoBlock.FindStringSubmatch(doc)
if len(block) != 2 || strings.TrimSpace(block[1]) != examples[name] {
t.Errorf("%s differs from Example%s body", path, name)
}
for _, section := range []string{"用途", "最小示例", "参数", "状态", "事件", "键盘操作", "限制"} {
if !strings.Contains(doc, "## "+section) {
t.Errorf("%s missing %s", path, section)
}
}
count++
}
if count != 20 || len(examples) != 20 {
t.Fatalf("docs %d examples %d", count, len(examples))
}
}
+115
View File
@@ -0,0 +1,115 @@
package core
import (
"log/slog"
"time"
"github.com/egoist/mygo/ui"
)
// overlayLayers is the window's open MujicaUI layers, oldest first.
type overlayLayers struct {
frame, prev time.Time
keys []any
seen []time.Time
}
type overlayLayersKey struct{}
// OverlayLayer marks the layer key open in this frame and reports whether it is on top.
func OverlayLayer(c *ui.Context, key any) bool {
s := ui.Local(c.Root(), overlayLayersKey{}, func() overlayLayers { return overlayLayers{} })
if now := c.Now(); now != s.frame {
s.prev, s.frame = s.frame, now
n := 0
for i, k := range s.keys {
if !s.seen[i].Before(s.prev) { // drop layers the last frame did not build
s.keys[n], s.seen[n] = k, s.seen[i]
n++
}
}
clear(s.keys[n:])
s.keys, s.seen = s.keys[:n], s.seen[:n]
}
at := -1
for i, k := range s.keys {
if k == key {
at = i
}
}
if at < 0 {
s.keys, s.seen = append(s.keys, key), append(s.seen, s.frame)
at = len(s.keys) - 1
}
s.seen[at] = s.frame
return at == len(s.keys)-1
}
// OverlayEscape reports Escape for a window-level layer, delivered only while it is on top.
func OverlayEscape(c *ui.Context, key any) bool {
if !OverlayLayer(c, key) {
return false
}
// The root is around every focus, so it takes Escape before MyGo's overlays.
byFocus := c.Root().Shortcut(0, ui.KeyEscape)
byWindow := c.Shortcut(0, ui.KeyEscape)
if byFocus || byWindow {
s := ui.Local(c.Root(), overlayLayersKey{}, func() overlayLayers { return overlayLayers{} })
for i, k := range s.keys {
if k == key {
s.keys = append(s.keys[:i], s.keys[i+1:]...)
s.seen = append(s.seen[:i], s.seen[i+1:]...)
break
}
}
c.Invalidate()
return true
}
return false
}
// overlaySiteState follows the focus of a layer after it closes.
type overlaySiteState struct {
focusIn bool // the focus was inside the layer when it last showed
wait int // frames left to check the focus after a close
holding bool // the site holds the fallback focus
}
// OverlaySite builds the invisible focus fallback at a layer's call site.
func OverlaySite(c *ui.Context) (*ui.Element, *overlaySiteState) {
site := ui.Box(c).Size(0, 0).FocusRing(false)
st := ui.Local(site, "mujica.overlay.site", func() overlaySiteState { return overlaySiteState{} })
st.holding = st.holding && site.FocusWithin()
if st.holding {
site.Focusable() // in flow, so Tab goes on from the layer's place
} else {
site.Absolute()
}
return site, st
}
// Shown records whether the focus is in the open layer's panel.
func (st *overlaySiteState) Shown(panel *ui.Element) {
st.focusIn, st.wait = panel != nil && panel.FocusWithin(), 0
}
// Closed moves a lost focus to the site once MyGo has had its chance to restore it.
func (st *overlaySiteState) Closed(c *ui.Context, site *ui.Element) {
if st.focusIn {
st.focusIn, st.wait = false, 2 // MyGo prunes the panel at the end of the next frame
}
if st.wait == 0 {
return
}
st.wait--
if st.wait > 0 {
c.AnimationFrame()
return
}
// The site itself counts as lost: it may inherit a vanished opener's positional ID.
if !c.Root().FocusWithin() || site.FocusWithin() {
slog.Debug("mujica: overlay focus fallback")
site.Focus()
st.holding = true
}
}
+44
View File
@@ -0,0 +1,44 @@
package core
import (
"time"
"github.com/egoist/mygo/ui"
"github.com/ZacharyZhang-NY/MujicaUI/theme"
)
// OverlayEnter returns how far, 0 to 1, the popup born with e has entered.
func OverlayEnter(c *ui.Context, e *ui.Element) float32 {
born := ui.Local(e, "mujica.overlay.born", func() time.Time { return c.Now() })
d := Motion(c, theme.PopupDuration)
if d == 0 {
return 1
}
t := float32(c.Now().Sub(*born)) / float32(d)
if t >= 1 {
return 1
}
c.AnimationFrame()
return ui.EaseOut(t)
}
// OverlayStyle gives a popup panel the surface, edge and shadow of the theme.
func OverlayStyle(c *ui.Context, panel *ui.Element, p float32) {
k := Tokens(c)
panel.Background(k.Surface).Border(theme.BorderWidth, k.Border).Radius(theme.PopupRadius).
TextColor(k.Text).Opacity(p).Shadow(0, 6, 18, 0, ui.RGBA(0, 0, 0, 0.16*p))
}
// PlaceOverlay puts a w×h box below anchor a, above when there is no room, inside the window.
func PlaceOverlay(c *ui.Context, a ui.Rect, w, h, gap float32) (x, y float32) {
ww, wh := c.Size()
const edge = 4
x, y = a.X, a.Y+a.H+gap
if y+h > wh-edge && a.Y-gap-h >= edge {
y = a.Y - gap - h
}
x = max(edge, min(x, ww-edge-w))
y = max(edge, min(y, wh-edge-h))
return x, y
}
+59
View File
@@ -0,0 +1,59 @@
package core
import (
"fmt"
"github.com/egoist/mygo/ui"
"github.com/ZacharyZhang-NY/MujicaUI/icons"
"github.com/ZacharyZhang-NY/MujicaUI/theme"
)
// Severity is the meaning of a message. The zero value is SeverityInfo.
type Severity int
const (
SeverityInfo Severity = iota
SeveritySuccess
SeverityWarning
SeverityError
)
func (s Severity) String() string {
switch s {
case SeverityInfo:
return "info"
case SeveritySuccess:
return "success"
case SeverityWarning:
return "warning"
case SeverityError:
return "error"
}
panic(fmt.Sprintf("mujica: unknown Severity %d", int(s)))
}
// SeverityLook returns the color and icon that, with text, mark s.
func SeverityLook(k theme.Tokens, s Severity) (ui.Color, *ui.SVG) {
switch s {
case SeveritySuccess:
return k.Success, icons.Must("circle-check")
case SeverityWarning:
return k.Warning, icons.Must("triangle-alert")
case SeverityError:
return k.Danger, icons.Must("circle-x")
case SeverityInfo:
return k.Info, icons.Must("info")
}
panic(fmt.Sprintf("mujica: unknown Severity %d", int(s)))
}
// AlertResult is what an Alert built and reported this frame.
type AlertResult struct {
// Element is nil while the alert is closed.
Element *ui.Element
// Action reports a click on the action button.
Action bool
// Closed reports the user dismissing the alert.
Closed bool
}
+35
View File
@@ -0,0 +1,35 @@
package core
import (
"image"
"testing"
"github.com/egoist/mygo/ui"
"github.com/ZacharyZhang-NY/MujicaUI/internal/snaptest"
)
// snapshot compares view in both themes with testdata/snapshots/<os>/<name>-<mode>.png.
func snapshot(t *testing.T, name string, w, h int, view func(c *ui.Context)) {
t.Helper()
snaptest.Run(t, name, w, h, snapshotTheme, view, nil)
}
// snapshotAfter is snapshot with drive sending input before the capture.
func snapshotAfter(t *testing.T, name string, w, h int, view func(c *ui.Context), drive func(tt *ui.Tester)) {
t.Helper()
snaptest.Run(t, name, w, h, snapshotTheme, view, drive)
}
func snapshotTheme(c *ui.Context, mode string) {
m := Light
if mode == "dark" {
m = Dark
}
Use(c, Settings{Mode: m})
}
func encode(t *testing.T, img image.Image) []byte {
t.Helper()
return snaptest.Encode(t, img)
}
+68
View File
@@ -0,0 +1,68 @@
package core
import (
"fmt"
"math"
"github.com/egoist/mygo/ui"
"github.com/ZacharyZhang-NY/MujicaUI/internal"
)
// SpinnerOptions configure a Spinner. Size is 16 DIPs when zero.
type SpinnerOptions struct {
Size float32
// Label is read out and shown beside the mark; empty uses "Loading" unread on screen.
Label string
ShowLabel bool
// Color paints the mark; zero uses AccentText.
Color ui.Color
}
// Spinner turns four diamonds only while painted; hidden or under reduced motion it stops.
func Spinner(c *ui.Context, opts SpinnerOptions) *ui.Element {
if !(opts.Size >= 0) || math.IsInf(float64(opts.Size), 1) {
panic(fmt.Sprintf("mujica: Spinner Size %v invalid", opts.Size))
}
k := Tokens(c)
size := opts.Size
if size == 0 {
size = 16
}
label := opts.Label
if label == "" {
label = Msg(c, "loading")
}
color := opts.Color
if color.A == 0 {
color = k.AccentText
}
still := c.Preferences().ReduceMotion
row := ui.Row(c).Gap(Density(c).Unit() * 2).AlignItems(ui.Center)
row.Children(func() {
// Keyed by motion so a flip repaints; MyGo's spinner carries the progress role.
ui.Box(c).Key(still).Shrink(0).Children(func() { spinnerMark(c, label, size, color, still) })
if opts.ShowLabel {
ui.Text(c, label).TextColor(k.TextMuted).SingleLine()
}
})
return row
}
func spinnerMark(c *ui.Context, label string, size float32, color ui.Color, still bool) {
ui.Spinner(c).Label(label).Size(size, size).Draw(func(p *ui.Painter, r ui.Rect) {
turn := 0.0
if !still {
turn = float64(p.Now().UnixMilli()%1200) / 1200
p.AnimationFrame()
}
cx, cy, rad := r.X+r.W/2, r.Y+r.H/2, r.W*0.32
for i := range 4 {
a := 2 * math.Pi * (turn + float64(i)/4)
x := cx + rad*float32(math.Cos(a))
y := cy + rad*float32(math.Sin(a))
alpha := 1 - float32(i)*0.22
p.FillPath(internal.Diamond(internal.Snap(p, x), internal.Snap(p, y), internal.Snap(p, r.W*0.3)), color.Alpha(alpha))
}
})
}
+157
View File
@@ -0,0 +1,157 @@
// Package core holds MujicaUI's theme, copy and the types and helpers every category shares.
package core
import (
"fmt"
"time"
"github.com/egoist/mygo/ui"
"github.com/ZacharyZhang-NY/MujicaUI/theme"
)
// Mode chooses the appearance of a window.
type Mode int
const (
System Mode = iota
Light
Dark
)
func (m Mode) String() string {
switch m {
case Light:
return "Light"
case Dark:
return "Dark"
}
return "System"
}
// Settings are a window's theme. Nil token sets use the library defaults.
type Settings struct {
Mode Mode
Density theme.Density
Light *theme.Tokens
Dark *theme.Tokens
Locale Locale
// Messages overrides built-in copy by key.
Messages map[string]string
}
type windowTheme struct {
tokens theme.Tokens
density theme.Density
locale Locale
messages map[string]string
set bool
}
type themeKey struct{}
// Use applies s to the window. Call it first in every frame of the view.
func Use(c *ui.Context, s Settings) {
if s.Mode < System || s.Mode > Dark {
panic(fmt.Sprintf("mujica: invalid Mode %d", s.Mode))
}
if s.Density < theme.Default || s.Density > theme.Comfortable {
panic(fmt.Sprintf("mujica: invalid Density %d", s.Density))
}
if s.Locale != "" && s.Locale != EnUS && s.Locale != ZhCN {
panic("mujica: unsupported Locale " + string(s.Locale))
}
dark := c.Theme().Dark
switch s.Mode {
case Light:
dark = false
case Dark:
dark = true
}
k := theme.Light()
if s.Light != nil {
k = *s.Light
}
if dark {
k = theme.Dark()
if s.Dark != nil {
k = *s.Dark
}
}
p := c.Preferences()
if p.HighContrast {
k = k.HighContrast()
}
size := FontSize(c, theme.BodySize)
c.SetTheme(&ui.Theme{
Dark: k.Dark,
Background: k.Background,
Surface: k.Surface,
SurfaceHover: k.SurfaceHover,
SurfacePressed: k.Selection,
Border: k.ControlBorder,
Text: k.Text,
TextMuted: k.TextMuted,
Accent: k.Accent,
AccentHover: k.AccentHover,
AccentPressed: k.AccentPressed,
AccentText: k.OnAccent,
Danger: k.Danger,
Warning: k.Warning,
Success: k.Success,
Selection: k.Selection,
Focus: k.Focus,
Scrollbar: k.TextMuted.Alpha(0.5),
Radius: theme.ControlRadius,
Spacing: s.Density.Unit(),
FontSize: size,
})
c.Root().LineHeight(theme.LineHeight)
*ui.Local(c.Root(), themeKey{}, func() windowTheme { return windowTheme{} }) = windowTheme{k, s.Density, s.Locale, s.Messages, true}
}
func current(c *ui.Context) windowTheme {
w := *ui.Local(c.Root(), themeKey{}, func() windowTheme { return windowTheme{} })
if !w.set {
panic("mujica: call mujica.Use at the start of the view")
}
return w
}
// CurrentSettings returns settings that rebuild the window's theme, its tokens pinned, for offscreen renders.
func CurrentSettings(c *ui.Context) Settings {
w := current(c)
s := Settings{Mode: Light, Density: w.density, Locale: w.locale, Messages: w.messages}
t := w.tokens
if t.Dark {
s.Mode, s.Dark = Dark, &t
} else {
s.Light = &t
}
return s
}
// Tokens returns the window's colors.
func Tokens(c *ui.Context) theme.Tokens { return current(c).tokens }
// Density returns the window's density.
func Density(c *ui.Context) theme.Density { return current(c).density }
// ColorFade eases background and border colors between states; MyGo skips it under reduced motion.
var ColorFade = ui.ElementTransition{Colors: true, Duration: theme.StateDuration}
// Motion returns d, or zero when the desktop asks for reduced motion.
func Motion(c *ui.Context, d time.Duration) time.Duration {
if c.Preferences().ReduceMotion {
return 0
}
return d
}
// FontSize scales a design size by the desktop's text scale.
func FontSize(c *ui.Context, size float32) float32 {
if s := c.Preferences().TextScale; s > 0 {
return size * s
}
return size
}
+55
View File
@@ -0,0 +1,55 @@
package core
import (
"testing"
"github.com/egoist/mygo/ui"
"github.com/ZacharyZhang-NY/MujicaUI/theme"
)
func TestUseLineHeight(t *testing.T) {
var h float32
tt := ui.NewTester(func(c *ui.Context) {
Use(c, Settings{})
h = ui.Text(c, "one\ntwo").Bounds().H
}, 300, 200)
tt.Frame()
if want := 2 * theme.BodySize * theme.LineHeight; h < want-0.5 || h > want+0.5 {
t.Fatalf("two lines are %v DIPs, want %v", h, want)
}
}
func TestUseRejectsInvalidSettings(t *testing.T) {
for _, s := range []Settings{{Mode: 9}, {Density: 9}, {Locale: "fr-FR"}} {
func() {
defer func() {
if recover() == nil {
t.Errorf("%+v accepted", s)
}
}()
ui.NewTester(func(c *ui.Context) { Use(c, s) }, 100, 100)
}()
}
}
func TestTokensWithoutUsePanics(t *testing.T) {
defer func() {
if recover() == nil {
t.Fatal("Tokens before Use did not panic")
}
}()
ui.NewTester(func(c *ui.Context) { Tokens(c) }, 100, 100)
}
func TestFontSizeFollowsTextScale(t *testing.T) {
var got float32
tt := ui.NewTester(func(c *ui.Context) {
Use(c, Settings{})
got = FontSize(c, theme.CaptionSize)
}, 100, 100)
tt.SetPreferences(ui.Preferences{TextScale: 2})
if got != 2*theme.CaptionSize {
t.Fatalf("FontSize = %v, want %v", got, 2*theme.CaptionSize)
}
}
+96
View File
@@ -0,0 +1,96 @@
package core
import (
"fmt"
"math"
"github.com/egoist/mygo/ui"
"github.com/ZacharyZhang-NY/MujicaUI/icons"
)
// Trend picks the rise color: green, or red (China).
type Trend int
type trendKey struct{}
// UseTrend sets the window's rise and fall colors.
func UseTrend(c *ui.Context, t Trend) {
if t != GreenUp && t != RedUp {
panic(fmt.Sprintf("mujica: unknown Trend %d", t))
}
*ui.Local(c.Root(), trendKey{}, func() Trend { return GreenUp }) = t
}
// TrendColor colors a rise (sign > 0), fall or flat.
func TrendColor(c *ui.Context, sign int) ui.Color {
k := Tokens(c)
up, down := k.Success, k.Danger
if *ui.Local(c.Root(), trendKey{}, func() Trend { return GreenUp }) == RedUp {
up, down = k.Danger, k.Success
}
switch {
case sign > 0:
return up
case sign < 0:
return down
}
return k.TextMuted
}
// TrendIcon is the arrow that says the direction without color.
func TrendIcon(sign int) *ui.SVG {
switch {
case sign > 0:
return icons.Must("arrow-up")
case sign < 0:
return icons.Must("arrow-down")
}
return icons.Must("minus")
}
// TrendWord names the direction for assistive technology.
func TrendWord(c *ui.Context, sign int) string {
switch {
case sign > 0:
return Msg(c, "price_text.up")
case sign < 0:
return Msg(c, "price_text.down")
}
return Msg(c, "price_text.flat")
}
func TrendSign(v float64) int {
switch {
case v > 0:
return 1
case v < 0:
return -1
}
return 0
}
// PriceDecimals resolves a Decimals option: zero means 2, negative panics.
func PriceDecimals(name string, d int) int {
if d < 0 {
panic("mujica: " + name + " with negative Decimals")
}
if d == 0 {
return 2
}
return d
}
// PriceUngrouped writes v with dec decimals and no separators.
func PriceUngrouped(v float64, dec int) string {
s := fmt.Sprintf("%.*f", dec, math.Abs(v))
if v < 0 && s != fmt.Sprintf("%.*f", dec, 0.0) {
return "−" + s
}
return s
}
const (
GreenUp Trend = iota
RedUp
)