Added basic i18n
This commit is contained in:
@@ -2,10 +2,12 @@ package kmb
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
i18n "github.com/tgckpg/golifehk/i18n"
|
||||
query "github.com/tgckpg/golifehk/query"
|
||||
utils "github.com/tgckpg/golifehk/utils"
|
||||
)
|
||||
@@ -19,6 +21,9 @@ type QueryResult struct {
|
||||
isConsumed bool
|
||||
dataType string
|
||||
tableData [][]query.TableCell
|
||||
|
||||
FallbackNearest int
|
||||
NearestRange float64
|
||||
}
|
||||
|
||||
func writeRouteHead(sb *strings.Builder, r *RouteStop) {
|
||||
@@ -64,6 +69,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 0 < len(*this.Query.Results) {
|
||||
@@ -72,23 +82,38 @@ func (this *QueryResult) Message() (string, error) {
|
||||
if this.Query.Key == "" {
|
||||
loc := this.Query.Message.Location
|
||||
if loc != nil {
|
||||
sb.WriteString("九巴 100m")
|
||||
|
||||
this.dataType = "Table"
|
||||
|
||||
table := [][]query.TableCell{}
|
||||
minDist := math.MaxFloat64
|
||||
maxDist := -1.0
|
||||
|
||||
for _, item := range *this.Query.Results {
|
||||
b := any(item).(*BusStop)
|
||||
|
||||
row := []query.TableCell{}
|
||||
|
||||
bDist := b.Dist(loc.Lat(), loc.Lon())
|
||||
if bDist < minDist {
|
||||
minDist = bDist
|
||||
}
|
||||
|
||||
if maxDist < bDist {
|
||||
maxDist = bDist
|
||||
}
|
||||
|
||||
cell := query.TableCell{
|
||||
Name: fmt.Sprintf("%.2fm %s", b.Dist(loc.Lat(), loc.Lon()), (*b.Name)[this.Lang]),
|
||||
Name: fmt.Sprintf("%s (%s)", (*b.Name)[this.Lang], i18n.FormatDistance(langPack, bDist)),
|
||||
Value: fmt.Sprintf("%s", b.BusStopId),
|
||||
}
|
||||
row = append(row, cell)
|
||||
|
||||
for _, r := range *b.Routes {
|
||||
for colIndex, r := range *b.Routes {
|
||||
if colIndex%6 == 0 {
|
||||
table = append(table, row)
|
||||
row = []query.TableCell{}
|
||||
}
|
||||
sb_i := strings.Builder{}
|
||||
writeRouteHead(&sb_i, r)
|
||||
cell := query.TableCell{
|
||||
@@ -102,6 +127,13 @@ func (this *QueryResult) Message() (string, error) {
|
||||
}
|
||||
this.tableData = table
|
||||
|
||||
rangeText := i18n.FormatDistance(langPack, this.NearestRange)
|
||||
if maxDist < this.NearestRange {
|
||||
utils.WriteMDv2Text(&sb, i18n.DS_KMB_NEAREST_STOPS.Text(langPack, rangeText))
|
||||
} else if this.NearestRange < minDist {
|
||||
utils.WriteMDv2Text(&sb, i18n.DS_KMB_NO_NEAREST_STOPS.Text(langPack, rangeText, this.FallbackNearest))
|
||||
}
|
||||
|
||||
} else {
|
||||
busStops := map[string]*BusStop{}
|
||||
for _, item := range *this.Query.Results {
|
||||
@@ -149,16 +181,13 @@ func (this *QueryResult) Message() (string, error) {
|
||||
_m := schedule.ETA.Sub(now).Minutes()
|
||||
|
||||
sb.WriteString(" \\* ")
|
||||
txt := "%.0f min(s)"
|
||||
|
||||
if this.Lang == "zh-Hant" {
|
||||
txt = "%.0f 分鐘"
|
||||
}
|
||||
|
||||
utils.WriteMDv2Text(&sb, fmt.Sprintf(txt, _m))
|
||||
eta := i18n.UNITS_MINUTE.Text(langPack, _m)
|
||||
|
||||
if _m < 0 {
|
||||
sb.WriteString(" 走左了?")
|
||||
utils.WriteMDv2Text(&sb, i18n.DS_KMB_ETA_DEPARTED.Text(langPack, eta))
|
||||
} else {
|
||||
utils.WriteMDv2Text(&sb, eta)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,11 @@ func Query(q query.QueryMessage) query.IQueryResult {
|
||||
var err error
|
||||
var routeStops *[]query.ISearchable
|
||||
|
||||
qr := QueryResult{Lang: lang}
|
||||
qr := QueryResult{
|
||||
Lang: lang,
|
||||
FallbackNearest: 3,
|
||||
NearestRange: 50,
|
||||
}
|
||||
|
||||
busStops, err := readBusStopsData()
|
||||
if err != nil {
|
||||
@@ -37,7 +41,7 @@ func Query(q query.QueryMessage) query.IQueryResult {
|
||||
bList = append(bList, b)
|
||||
}
|
||||
|
||||
qo, err = query.MatchNearest(*q.Location, &bList, 100, 3)
|
||||
qo, err = query.MatchNearest(*q.Location, &bList, qr.NearestRange, qr.FallbackNearest)
|
||||
}
|
||||
|
||||
qo.Message = &q
|
||||
|
||||
@@ -1,36 +1,54 @@
|
||||
package kmb
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"fmt"
|
||||
query "github.com/tgckpg/golifehk/query"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestQuerySchedule( t *testing.T ) {
|
||||
qo := Query( "zh-Hant", "68X" )
|
||||
mesg, err := qo.Message()
|
||||
if err != nil {
|
||||
t.Errorf( "Unexpected Error: %s", err )
|
||||
}
|
||||
fmt.Println( mesg )
|
||||
func TestQuerySchedule(t *testing.T) {
|
||||
qo := Query(query.QueryMessage{Lang: "zh-Hant", Text: "68X"})
|
||||
mesg, err := qo.Message()
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected Error: %s", err)
|
||||
}
|
||||
|
||||
qo = Query( "zh-Hant", "K66 朗屏" )
|
||||
mesg, err = qo.Message()
|
||||
if err == nil {
|
||||
t.Errorf( "Expected Error: %s, got \"\" instead", mesg )
|
||||
}
|
||||
qo = Query(query.QueryMessage{Lang: "zh-Hant", Text: "K66 朗屏"})
|
||||
mesg, err = qo.Message()
|
||||
if err == nil {
|
||||
t.Errorf("Expected Error: %s, got \"\" instead", mesg)
|
||||
}
|
||||
|
||||
qo = Query( "zh-Hant", "大欖" )
|
||||
mesg, err = qo.Message()
|
||||
if err != nil {
|
||||
t.Errorf( "Unexpected Error: %s", err )
|
||||
}
|
||||
qo = Query(query.QueryMessage{Lang: "zh-Hant", Text: "大欖"})
|
||||
mesg, err = qo.Message()
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected Error: %s", err)
|
||||
}
|
||||
|
||||
fmt.Println( mesg )
|
||||
qo = Query(query.QueryMessage{Lang: "zh-Hant", Text: "261B 大欖"})
|
||||
mesg, err = qo.Message()
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected Error: %s", err)
|
||||
}
|
||||
|
||||
qo = Query( "zh-Hant", "261B 大欖" )
|
||||
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},
|
||||
})
|
||||
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")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,8 +5,9 @@ import (
|
||||
)
|
||||
|
||||
func TestRouteStops(t *testing.T) {
|
||||
_, err := getRouteStops()
|
||||
if err != nil {
|
||||
t.Error( err )
|
||||
}
|
||||
busStops, err := readBusStopsData()
|
||||
_, err = getRouteStops(busStops)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user