Added basic i18n

This commit is contained in:
2026-03-10 15:18:34 +08:00
parent 093a8745ac
commit 7d1de5f781
25 changed files with 660 additions and 105 deletions

View File

@@ -1,6 +1,7 @@
package bus
import (
"fmt"
i18n "github.com/tgckpg/golifehk/i18n"
query "github.com/tgckpg/golifehk/query"
)
@@ -53,10 +54,11 @@ func (this *BusStop) Reload() {
}
func (this BusStop) Register(registers map[string]struct{}) bool {
if _, ok := registers[this.StationId]; ok {
key := fmt.Sprintf("%s,%s", this.StationId, this.ReferenceId)
if _, ok := registers[key]; ok {
return false
}
registers[this.StationId] = struct{}{}
registers[key] = struct{}{}
return true
}

View File

@@ -6,6 +6,7 @@ import (
"strconv"
"strings"
i18n "github.com/tgckpg/golifehk/i18n"
query "github.com/tgckpg/golifehk/query"
utils "github.com/tgckpg/golifehk/utils"
)
@@ -20,6 +21,9 @@ type QueryResult struct {
isConsumed bool
dataType string
tableData [][]query.TableCell
FallbackNearest int
NearestRange float64
}
func writeShortRoute(lang *string, sb *strings.Builder, b *BusStop) {
@@ -52,6 +56,11 @@ func (this *QueryResult) Message() (string, error) {
return "", this.Error
}
langPack, err := i18n.LoadKeys(this.Lang)
if err != nil {
return "", err
}
sb := strings.Builder{}
if this.Schedules == nil {
@@ -72,33 +81,83 @@ func (this *QueryResult) Message() (string, error) {
if loc != nil {
this.dataType = "Table"
sb.WriteString("K巴 100m")
table := [][]query.TableCell{}
// Group by Station Name first
bGroups := map[string]*[]*BusStop{}
for _, entry := range *q.Results {
busStop := any(entry).(*BusStop)
sb_i := strings.Builder{}
sb_i.WriteString(fmt.Sprintf("%.2fm", busStop.Dist(loc.Lat(), loc.Lon())))
sb_i.WriteString(" ")
utils.WriteMDv2Text(&sb_i, busStop.RouteId)
d := busStop.Direction
if d == "O" {
sb_i.WriteString("↑")
} else if d == "I" {
sb_i.WriteString("↓")
} else {
sb_i.WriteString("\\?")
bName := (*busStop.Name)[this.Lang]
bGroup, ok := bGroups[bName]
if !ok {
bGroup = &[]*BusStop{}
bGroups[bName] = bGroup
}
sb_i.WriteString(" ")
utils.WriteMDv2Text(&sb_i, (*busStop.Name)[this.Lang])
*bGroup = append(*bGroup, busStop)
}
for bName, bGroup := range bGroups {
row := []query.TableCell{
query.TableCell{
query.TableCell{Name: bName, Value: bName},
}
gRow := row
var minDist float64
var maxDist float64
for colIndex, busStop := range *bGroup {
if colIndex%6 == 0 {
table = append(table, row)
row = []query.TableCell{}
}
sb_i := strings.Builder{}
sb_i.WriteString(busStop.RouteId)
d := busStop.Direction
if d == "O" {
sb_i.WriteString("↑")
} else if d == "I" {
sb_i.WriteString("↓")
} else {
sb_i.WriteString("\\?")
}
cell := query.TableCell{
Name: sb_i.String(),
Value: fmt.Sprintf("%s %s", busStop.RouteId, (*busStop.Name)[this.Lang]),
},
Value: fmt.Sprintf("%s %s", busStop.RouteId, bName),
}
// Data are already sorted by shortest dist
// So the first one must be min dist
if minDist == 0 {
minDist = busStop.Dist(loc.Lat(), loc.Lon())
}
if colIndex+1 == len(*bGroup) {
maxDist = busStop.Dist(loc.Lat(), loc.Lon())
}
row = append(row, cell)
}
if minDist == maxDist {
gRow[0].Name = fmt.Sprintf("%s (%s)", bName, i18n.FormatDistance(langPack, minDist))
} else {
gRow[0].Name = fmt.Sprintf(
"%s (%s~%s)",
bName, i18n.FormatDistance(langPack, minDist),
bName, i18n.FormatDistance(langPack, maxDist),
)
}
rangeText := i18n.FormatDistance(langPack, this.NearestRange)
if maxDist < this.NearestRange {
utils.WriteMDv2Text(&sb, i18n.DS_MTR_NEAREST_STOPS.Text(langPack, rangeText))
} else if this.NearestRange < minDist {
utils.WriteMDv2Text(&sb, i18n.DS_MTR_NO_NEAREST_STOPS.Text(langPack, rangeText, this.FallbackNearest))
}
table = append(table, row)
@@ -235,7 +294,7 @@ func (this *QueryResult) Message() (string, error) {
sb.WriteString("\n")
}
} else {
utils.WriteMDv2Text(&sb, "Schedules are empty...perhaps Out of Service Time?")
utils.WriteMDv2Text(&sb, i18n.DS_MTR_NO_SCHEDULES.Text(langPack))
}
}

View File

@@ -7,6 +7,7 @@ import (
"net/http"
"path/filepath"
"strconv"
"strings"
query "github.com/tgckpg/golifehk/query"
"github.com/tgckpg/golifehk/utils"
@@ -52,9 +53,9 @@ func readBusStopData(r io.Reader) (*map[string]*BusStop, error) {
v, _ := strconv.ParseFloat(value, 64)
entry.Longitude = v
case "STATION_NAME_CHI":
entry.Name_zh = value
entry.Name_zh = strings.TrimSpace(value)
case "STATION_NAME_ENG":
entry.Name_en = value
entry.Name_en = strings.TrimSpace(value)
case "REFERENCE_ID":
entry.ReferenceId = value
default:

View File

@@ -13,7 +13,12 @@ func Query(q query.QueryMessage) query.IQueryResult {
var qBusStops *query.QueryObject
var err error
qr := QueryResult{Lang: lang}
qr := QueryResult{
Lang: lang,
FallbackNearest: 3,
NearestRange: 50,
}
busStops, err := getBusStops()
if err != nil {
qr.Error = err
@@ -23,16 +28,16 @@ func Query(q query.QueryMessage) query.IQueryResult {
if q.Text != "" {
qBusStops, err = query.MatchKeys(strings.ToUpper(q.Text), busStops)
} else if q.Location != nil {
qBusStops, err = query.MatchNearest(*q.Location, busStops, 100, 3)
qBusStops, err = query.MatchNearest(*q.Location, busStops, qr.NearestRange, qr.FallbackNearest)
}
qBusStops.Message = &q
if err != nil {
qr.Error = err
goto qrReturn
}
qBusStops.Message = &q
qr.Query = qBusStops
if 0 < len(*qBusStops.Results) && 1 < len(*qBusStops.SearchTerms) {
schedules, err := getSchedule(lang, qBusStops.Key)

View File

@@ -1,33 +1,55 @@
package bus
import (
"fmt"
"strings"
"fmt"
query "github.com/tgckpg/golifehk/query"
"strings"
"testing"
)
func TestQuery( t *testing.T ) {
qo := Query( "zh-Hant", "K73" )
mesg, err := qo.Message()
if err != nil {
t.Errorf( "Unexpected Error: %s", err )
}
func TestQuery(t *testing.T) {
qo := Query(query.QueryMessage{Lang: "zh-Hant", Text: "K73"})
mesg, err := qo.Message()
if err != nil {
t.Errorf("Unexpected Error: %s", err)
}
if !strings.Contains( mesg, "K73\\-O" ) {
t.Errorf( "Expected Route Listing, got \"%s\" instead", mesg )
}
if !strings.Contains(mesg, "K73↓") {
t.Errorf("Expected Route Listing, got \"%s\" instead", mesg)
}
qo = Query( "zh-Hant", "K76 池" )
mesg, err = qo.Message()
if err == nil {
t.Errorf( "Expecting error, got \"%s\" instead", mesg )
}
qo = Query(query.QueryMessage{Lang: "zh-Hant", Text: "K76 池"})
mesg, err = qo.Message()
if err == nil {
t.Errorf("Expecting error, got \"%s\" instead", mesg)
}
qo = Query( "zh-Hant", "K73 池" )
mesg, err = qo.Message()
if err != nil {
t.Errorf( "Unexpected Error: %s", err )
}
qo = Query(query.QueryMessage{Lang: "zh-Hant", Text: "K73 池"})
mesg, err = qo.Message()
if err != nil {
t.Errorf("Unexpected Error: %s", err)
}
fmt.Println( mesg )
qo = Query(query.QueryMessage{
Lang: "zh-Hant", Text: "",
// Yuen Long Plaza
Location: &query.GeoLocation{22.444894482044997, 114.02393826485495},
// Nathan Rd
// Location: &query.GeoLocation{22.308944848482525, 114.17116565400259},
// GO PARK
// Location: &query.GeoLocation{22.427238734660868, 114.26595846515744},
// 288 Sa Po Kong
// Location: &query.GeoLocation{22.386886035837605, 113.92123399401174},
})
mesg, err = qo.Message()
if err != nil {
t.Errorf("Unexpected Error: %s", err)
}
for _, row := range qo.GetTableData() {
for _, cell := range row {
fmt.Printf("| %s |", cell.Name)
}
fmt.Print("\n")
}
}