Skip to content

Commit 02d8525

Browse files
committed
Places: Add config option to specify location details locale #465 #883
Signed-off-by: Michael Mayer <michael@photoprism.app>
1 parent 4b1cc5d commit 02d8525

30 files changed

+203
-83
lines changed

NOTICE

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ The following 3rd-party software packages may be used by or distributed with
99
PhotoPrism. Any information relevant to third-party vendors listed below are
1010
collected using common, reasonable means.
1111

12-
Date generated: 2025-07-02
12+
Date generated: 2025-07-03
1313

1414
================================================================================
1515

@@ -2343,8 +2343,8 @@ SOFTWARE.
23432343
--------------------------------------------------------------------------------
23442344

23452345
Package: github.com/golang/geo
2346-
Version: v0.0.0-20250627182359-f4b81656db99
2347-
License: Apache-2.0 (https://github.com/golang/geo/blob/f4b81656db99/LICENSE)
2346+
Version: v0.0.0-20250702194635-55051eb0594d
2347+
License: Apache-2.0 (https://github.com/golang/geo/blob/55051eb0594d/LICENSE)
23482348

23492349

23502350
Apache License
@@ -6414,8 +6414,8 @@ License: Apache-2.0 (https://github.com/zitadel/logging/blob/v0.6.2/LICENSE)
64146414
--------------------------------------------------------------------------------
64156415

64166416
Package: github.com/zitadel/oidc/v3/pkg
6417-
Version: v3.39.0
6418-
License: Apache-2.0 (https://github.com/zitadel/oidc/blob/v3.39.0/LICENSE)
6417+
Version: v3.39.1
6418+
License: Apache-2.0 (https://github.com/zitadel/oidc/blob/v3.39.1/LICENSE)
64196419

64206420
Apache License
64216421
Version 2.0, January 2004

go.mod

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ require (
1414
github.com/esimov/pigo v1.4.6
1515
github.com/gin-contrib/gzip v1.2.3
1616
github.com/gin-gonic/gin v1.10.1
17-
github.com/golang/geo v0.0.0-20250630213057-fac2d31592dd
17+
github.com/golang/geo v0.0.0-20250702194635-55051eb0594d
1818
github.com/google/open-location-code/go v0.0.0-20250620134813-83986da0156b
1919
github.com/gorilla/websocket v1.5.3
2020
github.com/gosimple/slug v1.15.0
@@ -86,7 +86,7 @@ require (
8686
github.com/ugjka/go-tz/v2 v2.2.6
8787
github.com/urfave/cli/v2 v2.27.7
8888
github.com/wamuir/graft v0.10.0
89-
github.com/zitadel/oidc/v3 v3.39.0
89+
github.com/zitadel/oidc/v3 v3.39.1
9090
golang.org/x/mod v0.25.0
9191
golang.org/x/sys v0.33.0
9292
)

go.sum

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -133,8 +133,8 @@ github.com/gin-gonic/gin v1.10.1 h1:T0ujvqyCSqRopADpgPgiTT63DUQVSfojyME59Ei63pQ=
133133
github.com/gin-gonic/gin v1.10.1/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
134134
github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667 h1:BP4M0CvQ4S3TGls2FvczZtj5Re/2ZzkV9VwqPHH/3Bo=
135135
github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
136-
github.com/go-chi/chi/v5 v5.2.1 h1:KOIHODQj58PmL80G2Eak4WdvUzjSJSm0vG72crDCqb8=
137-
github.com/go-chi/chi/v5 v5.2.1/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops=
136+
github.com/go-chi/chi/v5 v5.2.2 h1:CMwsvRVTbXVytCk1Wd72Zy1LAsAh9GxMmSNWLHCG618=
137+
github.com/go-chi/chi/v5 v5.2.2/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops=
138138
github.com/go-co-op/gocron/v2 v2.16.2 h1:r08P663ikXiulLT9XaabkLypL/W9MoCIbqgQoAutyX4=
139139
github.com/go-co-op/gocron/v2 v2.16.2/go.mod h1:4YTLGCCAH75A5RlQ6q+h+VacO7CgjkgP0EJ+BEOXRSI=
140140
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
@@ -184,8 +184,8 @@ github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGw
184184
github.com/golang/geo v0.0.0-20190916061304-5b978397cfec/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI=
185185
github.com/golang/geo v0.0.0-20200319012246-673a6f80352d/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI=
186186
github.com/golang/geo v0.0.0-20210211234256-740aa86cb551/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI=
187-
github.com/golang/geo v0.0.0-20250630213057-fac2d31592dd h1:4BU/Fy2KwDucgY0al91L0wJI05rb1Y4hQKucQkybjT8=
188-
github.com/golang/geo v0.0.0-20250630213057-fac2d31592dd/go.mod h1:Vaw7L5b+xa3Rj4/pRtrQkymn3lSBRB/NAEdbF9YEVLA=
187+
github.com/golang/geo v0.0.0-20250702194635-55051eb0594d h1:AzT7tYHcPLcUlo6224yQJvhL1A9GjT5g1cYbyDSYt/w=
188+
github.com/golang/geo v0.0.0-20250702194635-55051eb0594d/go.mod h1:Vaw7L5b+xa3Rj4/pRtrQkymn3lSBRB/NAEdbF9YEVLA=
189189
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
190190
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
191191
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
@@ -419,8 +419,8 @@ github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBi
419419
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
420420
github.com/zitadel/logging v0.6.2 h1:MW2kDDR0ieQynPZ0KIZPrh9ote2WkxfBif5QoARDQcU=
421421
github.com/zitadel/logging v0.6.2/go.mod h1:z6VWLWUkJpnNVDSLzrPSQSQyttysKZ6bCRongw0ROK4=
422-
github.com/zitadel/oidc/v3 v3.39.0 h1:WK3eNqmgshiYo1oEqONfXXbPbve+Qzgjl8KhKDFUvxc=
423-
github.com/zitadel/oidc/v3 v3.39.0/go.mod h1:JwdgdU/WxkmBtWuE8/pEjAbDTWXxJGqBix/gUoeEig4=
422+
github.com/zitadel/oidc/v3 v3.39.1 h1:6QwGwI3yxh4somT7fwRCeT1KOn/HOGv0PA0dFciwJjE=
423+
github.com/zitadel/oidc/v3 v3.39.1/go.mod h1:aH8brOrzoliAybVdfq2xIdGvbtl0j/VsKRNa7WE72gI=
424424
github.com/zitadel/schema v1.3.1 h1:QT3kwiRIRXXLVAs6gCK/u044WmUVh6IlbLXUsn6yRQU=
425425
github.com/zitadel/schema v1.3.1/go.mod h1:071u7D2LQacy1HAN+YnMd/mx1qVE2isb0Mjeqg46xnU=
426426
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=

internal/api/api_request.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,5 @@ func ClientIP(c *gin.Context) (ip string) {
1313

1414
// UserAgent returns the user agent from the request context or an empty string if it is unknown.
1515
func UserAgent(c *gin.Context) string {
16-
return header.UserAgent(c)
16+
return header.ClientUserAgent(c)
1717
}

internal/api/places_reverse.go

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"github.com/photoprism/photoprism/internal/auth/acl"
99
"github.com/photoprism/photoprism/internal/photoprism/get"
1010
"github.com/photoprism/photoprism/internal/service/hub/places"
11+
"github.com/photoprism/photoprism/pkg/clean"
1112
"github.com/photoprism/photoprism/pkg/txt"
1213
)
1314

@@ -19,12 +20,13 @@ import (
1920
// @Id GetPlacesReverse
2021
// @Tags Places
2122
// @Produce json
22-
// @Param lat query string true "Latitude"
23-
// @Param lng query string true "Longitude"
24-
// @Success 200 {object} places.Location
25-
// @Failure 400 {object} gin.H "Missing latitude or longitude"
26-
// @Failure 401 {object} i18n.Response
27-
// @Failure 500 {object} gin.H "Geocoding service error"
23+
// @Param lat query string true "Latitude"
24+
// @Param lng query string true "Longitude"
25+
// @Param locale query string false "Locale"
26+
// @Success 200 {object} places.Location
27+
// @Failure 400 {object} gin.H "Missing latitude or longitude"
28+
// @Failure 401 {object} i18n.Response
29+
// @Failure 500 {object} gin.H "Geocoding service error"
2830
// @Router /api/v1/places/reverse [get]
2931
func GetPlacesReverse(router *gin.RouterGroup) {
3032
handler := func(c *gin.Context) {
@@ -44,7 +46,7 @@ func GetPlacesReverse(router *gin.RouterGroup) {
4446
return
4547
}
4648

47-
// Get latitude and longitude from query parameters.
49+
// Get latitude, longitude, and locale from query parameters.
4850
var lat, lng string
4951

5052
if lat = txt.Numeric(c.Query("lat")); lat == "" {
@@ -61,14 +63,19 @@ func GetPlacesReverse(router *gin.RouterGroup) {
6163
return
6264
}
6365

64-
result, err := places.LatLng(txt.Float64(lat), txt.Float64(lng))
66+
locale := clean.WebLocale(c.Query("locale"), conf.PlacesLocale())
6567

68+
// Perform service request.
69+
result, err := places.LatLng(txt.Float64(lat), txt.Float64(lng), locale)
70+
71+
// Return error if request was not successful.
6672
if err != nil {
6773
log.Errorf("places: failed to resolve location at lat %s, lng %s", lat, lng)
6874
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"error": err})
6975
return
7076
}
7177

78+
// Return location details.
7279
c.JSON(http.StatusOK, result)
7380
}
7481

internal/api/places_search.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ func GetPlacesSearch(router *gin.RouterGroup) {
4848

4949
// Get the search string, locale, and result count limit from the query parameters.
5050
query := clean.SearchString(c.Query("q"))
51-
locale := clean.WebLocale(c.Query("locale"), conf.DefaultLocale())
51+
locale := clean.WebLocale(c.Query("locale"), conf.PlacesLocale())
5252
count := txt.IntVal(c.Query("count"), 1, 50, 10)
5353

5454
if query == "" {

internal/api/swagger.json

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3873,6 +3873,12 @@
38733873
"name": "lng",
38743874
"in": "query",
38753875
"required": true
3876+
},
3877+
{
3878+
"type": "string",
3879+
"description": "Locale",
3880+
"name": "locale",
3881+
"in": "query"
38763882
}
38773883
],
38783884
"responses": {
@@ -5665,6 +5671,9 @@
56655671
"OriginalsLimit": {
56665672
"type": "integer"
56675673
},
5674+
"PlacesLocale": {
5675+
"type": "string"
5676+
},
56685677
"PngSize": {
56695678
"type": "integer"
56705679
},
@@ -7534,6 +7543,9 @@
75347543
"lng": {
75357544
"type": "number"
75367545
},
7546+
"locale": {
7547+
"type": "string"
7548+
},
75377549
"name": {
75387550
"type": "string"
75397551
},
@@ -7580,7 +7592,7 @@
75807592
"places.SearchResult": {
75817593
"type": "object",
75827594
"properties": {
7583-
"boundingbox": {
7595+
"bbox": {
75847596
"type": "array",
75857597
"items": {
75867598
"type": "number"

internal/config/config.go

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,7 @@ func (c *Config) Propagate() {
306306

307307
// Set geocoding parameters.
308308
places.UserAgent = c.UserAgent()
309+
places.DefaultLocale = c.PlacesLocale()
309310
entity.GeoApi = c.GeoApi()
310311

311312
// Set session cache duration.
@@ -698,15 +699,6 @@ func (c *Config) AutoImport() time.Duration {
698699
return time.Duration(c.options.AutoImport) * time.Second
699700
}
700701

701-
// GeoApi returns the preferred geocoding api (places, or none).
702-
func (c *Config) GeoApi() string {
703-
if c.options.DisablePlaces {
704-
return ""
705-
}
706-
707-
return "places"
708-
}
709-
710702
// OriginalsLimit returns the maximum size of originals in MB.
711703
func (c *Config) OriginalsLimit() int {
712704
if c.options.OriginalsLimit <= 0 || c.options.OriginalsLimit > 100000 {

internal/config/config_places.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package config
2+
3+
import (
4+
"github.com/photoprism/photoprism/internal/service/hub/places"
5+
"github.com/photoprism/photoprism/pkg/clean"
6+
)
7+
8+
// GeoApi returns the preferred geocoding api (places, or none).
9+
func (c *Config) GeoApi() string {
10+
if c.options.DisablePlaces {
11+
return ""
12+
}
13+
14+
return "places"
15+
}
16+
17+
// PlacesLocale returns the locale name used for geocoding.
18+
func (c *Config) PlacesLocale() string {
19+
return clean.WebLocale(c.options.PlacesLocale, places.LocalLocale)
20+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package config
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/assert"
7+
)
8+
9+
func TestConfig_GeoApi(t *testing.T) {
10+
c := NewConfig(CliTestContext())
11+
12+
assert.Equal(t, "places", c.GeoApi())
13+
c.options.DisablePlaces = true
14+
assert.Equal(t, "", c.GeoApi())
15+
}
16+
17+
func TestConfig_PlacesLocale(t *testing.T) {
18+
c := NewConfig(CliTestContext())
19+
20+
c.options.PlacesLocale = ""
21+
assert.Equal(t, "local", c.PlacesLocale())
22+
c.options.PlacesLocale = "local"
23+
assert.Equal(t, "local", c.PlacesLocale())
24+
c.options.PlacesLocale = "EN"
25+
assert.Equal(t, "en", c.PlacesLocale())
26+
c.options.PlacesLocale = "EN_US"
27+
assert.Equal(t, "en-US", c.PlacesLocale())
28+
c.options.PlacesLocale = ""
29+
assert.Equal(t, "local", c.PlacesLocale())
30+
}

0 commit comments

Comments
 (0)