소스 검색

WebClient: add language switcher, complete localization support

Signed-off-by: Nicola Murino <[email protected]>
Nicola Murino 1 년 전
부모
커밋
c76a18168b

+ 10 - 7
go.mod

@@ -32,8 +32,8 @@ require (
 	github.com/go-sql-driver/mysql v1.7.1
 	github.com/golang/mock v1.6.0
 	github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
-	github.com/google/uuid v1.4.0
-	github.com/hashicorp/go-hclog v1.6.1
+	github.com/google/uuid v1.5.0
+	github.com/hashicorp/go-hclog v1.6.2
 	github.com/hashicorp/go-plugin v1.6.0
 	github.com/hashicorp/go-retryablehttp v0.7.5
 	github.com/jackc/pgx/v5 v5.5.1
@@ -74,7 +74,7 @@ require (
 	golang.org/x/sys v0.15.0
 	golang.org/x/term v0.15.0
 	golang.org/x/time v0.5.0
-	google.golang.org/api v0.153.0
+	google.golang.org/api v0.154.0
 	gopkg.in/natefinch/lumberjack.v2 v2.2.1
 )
 
@@ -106,6 +106,7 @@ require (
 	github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
 	github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect
 	github.com/fatih/color v1.16.0 // indirect
+	github.com/felixge/httpsnoop v1.0.4 // indirect
 	github.com/fsnotify/fsnotify v1.7.0 // indirect
 	github.com/go-jose/go-jose/v3 v3.0.1 // indirect
 	github.com/go-logr/logr v1.3.0 // indirect
@@ -158,6 +159,8 @@ require (
 	github.com/tklauser/numcpus v0.7.0 // indirect
 	github.com/yusufpapurcu/wmi v1.2.3 // indirect
 	go.opencensus.io v0.24.0 // indirect
+	go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1 // indirect
+	go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1 // indirect
 	go.opentelemetry.io/otel v1.21.0 // indirect
 	go.opentelemetry.io/otel/metric v1.21.0 // indirect
 	go.opentelemetry.io/otel/trace v1.21.0 // indirect
@@ -166,12 +169,12 @@ require (
 	golang.org/x/mod v0.14.0 // indirect
 	golang.org/x/sync v0.5.0 // indirect
 	golang.org/x/text v0.14.0 // indirect
-	golang.org/x/tools v0.16.0 // indirect
+	golang.org/x/tools v0.16.1 // indirect
 	golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect
 	google.golang.org/appengine v1.6.8 // indirect
-	google.golang.org/genproto v0.0.0-20231211222908-989df2bf70f3 // indirect
-	google.golang.org/genproto/googleapis/api v0.0.0-20231211222908-989df2bf70f3 // indirect
-	google.golang.org/genproto/googleapis/rpc v0.0.0-20231211222908-989df2bf70f3 // indirect
+	google.golang.org/genproto v0.0.0-20231212172506-995d672761c0 // indirect
+	google.golang.org/genproto/googleapis/api v0.0.0-20231212172506-995d672761c0 // indirect
+	google.golang.org/genproto/googleapis/rpc v0.0.0-20231212172506-995d672761c0 // indirect
 	google.golang.org/grpc v1.60.0 // indirect
 	google.golang.org/protobuf v1.31.0 // indirect
 	gopkg.in/ini.v1 v1.67.0 // indirect

+ 24 - 14
go.sum

@@ -91,6 +91,8 @@ github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj
 github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
 github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
 github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
+github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4 h1:/inchEIKaYC1Akx+H+gqO04wryn5h75LSazbRlnya1k=
+github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
 github.com/cockroachdb/cockroach-go/v2 v2.3.5 h1:Khtm8K6fTTz/ZCWPzU9Ne3aOW9VyAnj4qIPCJgKtwK0=
 github.com/cockroachdb/cockroach-go/v2 v2.3.5/go.mod h1:1wNJ45eSXW9AnOc3skntW9ZUZz6gxrQK3cOj3rK+BC8=
 github.com/coreos/go-oidc/v3 v3.9.0 h1:0J/ogVOd4y8P0f0xUh8l9t07xRP/d8tccvjHl2dcsSo=
@@ -124,11 +126,15 @@ github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymF
 github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
 github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
 github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
+github.com/envoyproxy/protoc-gen-validate v1.0.2 h1:QkIBuU5k+x7/QXPvPPnWXWlCdaBFApVqftFV6k087DA=
+github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7QWXpgx6x8QiMKdmN72jogE=
 github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
 github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
 github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
 github.com/fclairamb/go-log v0.4.1 h1:rLtdSG9x2pK41AIAnE8WYpl05xBJfw1ZyYxZaXFcBsM=
 github.com/fclairamb/go-log v0.4.1/go.mod h1:sw1KvnkZ4wKCYkvy4SL3qVZcJSWFP8Ure4pM3z+KNn4=
+github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
+github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
 github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
 github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
 github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
@@ -203,8 +209,8 @@ github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaU
 github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
 github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4=
-github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU=
+github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 github.com/google/wire v0.5.0 h1:I7ELFeVBr3yfPIcc8+MWvrjk+3VjbcSzoXm3JVa+jD8=
 github.com/google/wire v0.5.0/go.mod h1:ngWDr9Qvq3yZA10YrxfyGELY/AFWGVpy9c1LTRi1EoU=
 github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs=
@@ -214,8 +220,8 @@ github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qK
 github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
 github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
 github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
-github.com/hashicorp/go-hclog v1.6.1 h1:pa92nu9bPoAqI7p+uPDCIWGAibUdlCi6TYWJEQQkLf8=
-github.com/hashicorp/go-hclog v1.6.1/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
+github.com/hashicorp/go-hclog v1.6.2 h1:NOtoftovWkDheyUM/8JW3QMiXyxJK3uHRK7wV04nD2I=
+github.com/hashicorp/go-hclog v1.6.2/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
 github.com/hashicorp/go-plugin v1.6.0 h1:wgd4KxHJTVGGqWBq4QPB1i5BZNEx9BR8+OFmHDmTk8A=
 github.com/hashicorp/go-plugin v1.6.0/go.mod h1:lBS5MtSSBZk0SHc66KACcjjlU6WzEVP/8pwz68aMkCI=
 github.com/hashicorp/go-retryablehttp v0.7.5 h1:bJj+Pj19UZMIweq/iie+1u5YCdGrnxCT9yvm0e+Nd5M=
@@ -407,6 +413,10 @@ go.etcd.io/bbolt v1.3.8 h1:xs88BrvEv273UsB79e0hcVrlUWmS0a8upikMFhSyAtA=
 go.etcd.io/bbolt v1.3.8/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw=
 go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
 go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
+go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1 h1:SpGay3w+nEwMpfVnbqOLH5gY52/foP8RE8UzTZ1pdSE=
+go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1/go.mod h1:4UoMYEZOC0yN/sPGH76KPkkU7zgiEWYWL9vwmbnTJPE=
+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1 h1:aFJWCqJMNjENlcleuuOkGAPH82y0yULBScfXcIEdS24=
+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1/go.mod h1:sEGXWArGqc3tVa+ekntsN65DmVbVeW+7lTKTjZF3/Fo=
 go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc=
 go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo=
 go.opentelemetry.io/otel/metric v1.21.0 h1:tlYWfeo+Bocx5kLEloTjbcDwBuELRrIFxwdQ36PlJu4=
@@ -507,16 +517,16 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn
 golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
 golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
 golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
-golang.org/x/tools v0.16.0 h1:GO788SKMRunPIBCXiQyo2AaexLstOrVhuAL5YwsckQM=
-golang.org/x/tools v0.16.0/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0=
+golang.org/x/tools v0.16.1 h1:TLyB3WofjdOEepBHAU20JdNC1Zbg87elYofWYAY5oZA=
+golang.org/x/tools v0.16.1/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU=
 golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90=
-google.golang.org/api v0.153.0 h1:N1AwGhielyKFaUqH07/ZSIQR3uNPcV7NVw0vj+j4iR4=
-google.golang.org/api v0.153.0/go.mod h1:3qNJX5eOmhiWYc67jRA/3GsDw97UFb5ivv7Y2PrriAY=
+google.golang.org/api v0.154.0 h1:X7QkVKZBskztmpPKWQXgjJRPA2dJYrL6r+sYPRLj050=
+google.golang.org/api v0.154.0/go.mod h1:qhSMkM85hgqiokIYsrRyKxrjfBeIhgl4Z2JmeRkYylc=
 google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
 google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
 google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
@@ -524,12 +534,12 @@ google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJ
 google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
 google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
 google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
-google.golang.org/genproto v0.0.0-20231211222908-989df2bf70f3 h1:1hfbdAfFbkmpg41000wDVqr7jUpK/Yo+LPnIxxGzmkg=
-google.golang.org/genproto v0.0.0-20231211222908-989df2bf70f3/go.mod h1:5RBcpGRxr25RbDzY5w+dmaqpSEvl8Gwl1x2CICf60ic=
-google.golang.org/genproto/googleapis/api v0.0.0-20231211222908-989df2bf70f3 h1:EWIeHfGuUf00zrVZGEgYFxok7plSAXBGcH7NNdMAWvA=
-google.golang.org/genproto/googleapis/api v0.0.0-20231211222908-989df2bf70f3/go.mod h1:k2dtGpRrbsSyKcNPKKI5sstZkrNCZwpU/ns96JoHbGg=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20231211222908-989df2bf70f3 h1:kzJAXnzZoFbe5bhZd4zjUuHos/I31yH4thfMb/13oVY=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20231211222908-989df2bf70f3/go.mod h1:eJVxU6o+4G1PSczBr85xmyvSNYAKvAYgkub40YGomFM=
+google.golang.org/genproto v0.0.0-20231212172506-995d672761c0 h1:YJ5pD9rF8o9Qtta0Cmy9rdBwkSjrTCT6XTiUQVOtIos=
+google.golang.org/genproto v0.0.0-20231212172506-995d672761c0/go.mod h1:l/k7rMz0vFTBPy+tFSGvXEd3z+BcoG1k7EHbqm+YBsY=
+google.golang.org/genproto/googleapis/api v0.0.0-20231212172506-995d672761c0 h1:s1w3X6gQxwrLEpxnLd/qXTVLgQE2yXwaOaoa6IlY/+o=
+google.golang.org/genproto/googleapis/api v0.0.0-20231212172506-995d672761c0/go.mod h1:CAny0tYF+0/9rmDB9fahA9YLzX3+AEVl1qXbv5hhj6c=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20231212172506-995d672761c0 h1:/jFB8jK5R3Sq3i/lmeZO0cATSzFfZaJq1J2Euan3XKU=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20231212172506-995d672761c0/go.mod h1:FUoWkonphQm3RhTS+kOEhF8h0iDpm4tdXolVCeZ9KKA=
 google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
 google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
 google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=

+ 71 - 0
static/assets/plugins/custom/flatpickr/l10n/it.js

@@ -0,0 +1,71 @@
+(function (global, factory) {
+  typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
+  typeof define === 'function' && define.amd ? define(['exports'], factory) :
+  (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.it = {}));
+}(this, (function (exports) { 'use strict';
+
+  var fp = typeof window !== "undefined" && window.flatpickr !== undefined
+      ? window.flatpickr
+      : {
+          l10ns: {},
+      };
+  var Italian = {
+      weekdays: {
+          shorthand: ["Dom", "Lun", "Mar", "Mer", "Gio", "Ven", "Sab"],
+          longhand: [
+              "Domenica",
+              "Lunedì",
+              "Martedì",
+              "Mercoledì",
+              "Giovedì",
+              "Venerdì",
+              "Sabato",
+          ],
+      },
+      months: {
+          shorthand: [
+              "Gen",
+              "Feb",
+              "Mar",
+              "Apr",
+              "Mag",
+              "Giu",
+              "Lug",
+              "Ago",
+              "Set",
+              "Ott",
+              "Nov",
+              "Dic",
+          ],
+          longhand: [
+              "Gennaio",
+              "Febbraio",
+              "Marzo",
+              "Aprile",
+              "Maggio",
+              "Giugno",
+              "Luglio",
+              "Agosto",
+              "Settembre",
+              "Ottobre",
+              "Novembre",
+              "Dicembre",
+          ],
+      },
+      firstDayOfWeek: 1,
+      ordinal: function () { return "°"; },
+      rangeSeparator: " al ",
+      weekAbbreviation: "Se",
+      scrollTitle: "Scrolla per aumentare",
+      toggleTitle: "Clicca per cambiare",
+      time_24hr: true,
+  };
+  fp.l10ns.it = Italian;
+  var it = fp.l10ns;
+
+  exports.Italian = Italian;
+  exports.default = it;
+
+  Object.defineProperty(exports, '__esModule', { value: true });
+
+})));

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 0 - 0
static/assets/plugins/global/plugins.bundle.css


파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 0 - 0
static/assets/plugins/global/plugins.bundle.js


+ 23 - 0
templates/common/base.html

@@ -125,6 +125,11 @@ explicit grant from the SFTPGo Team ([email protected]).
         }
     }
 
+    const lngs = {
+        en: { nativeName: 'English' },
+        it: { nativeName: 'Italiano' }
+    };
+
     const renderI18n = () => {
         $('body').localize();
         let select2elements = [].slice.call(document.querySelectorAll('[data-control="i18n-select2"]'));
@@ -188,6 +193,24 @@ explicit grant from the SFTPGo Team ([email protected]).
                     console.error(err);
                 } else {
                     jqueryI18next.init(i18next, $, { useOptionsAttr: true });
+
+                    var languageSwitcher = $('#languageSwitcher');
+                    if (languageSwitcher){
+                        Object.keys(lngs).map((lng) => {
+                            const opt = new Option(lngs[lng].nativeName, lng);
+                            if (lng === i18next.resolvedLanguage) {
+                                opt.setAttribute("selected", "selected");
+                            }
+                            languageSwitcher.append(opt);
+                        });
+                        languageSwitcher.on('change', function(){
+                            const chosenLng = $(this).find("option:selected").attr('value');
+                            i18next.changeLanguage(chosenLng, () => {
+                                renderI18n();
+                            });
+                        });
+                    }
+
                     renderI18n();
                     $('title').text('{{.Branding.Name}} - '+$.t('{{.Title}}'));
                     $.event.trigger({

+ 1 - 1
templates/webclient/files.html

@@ -25,7 +25,7 @@ explicit grant from the SFTPGo Team ([email protected]).
                     <span class="path1"></span>
                     <span class="path2"></span>
                 </i>
-                <input data-i18n="[placeholder]general.search" type="text" data-kt-filemanager-table-filter="search" class="form-control form-control-solid w-250px ps-15" placeholder="Search Files & Folders" />
+                <input name="search" data-i18n="[placeholder]general.search" type="text" data-kt-filemanager-table-filter="search" class="form-control rounded-1 w-250px ps-15" placeholder="Search Files & Folders" />
             </div>
         </div>
         <div class="card-toolbar">

+ 12 - 8
templates/webclient/login.html

@@ -32,7 +32,7 @@ explicit grant from the SFTPGo Team ([email protected]).
 							{{- template "errmsg" .Error}}
 							{{- if not .FormDisabled}}
 							<div class="fv-row mb-10">
-								<input data-i18n="[placeholder]login.username" class="form-control form-control-lg form-control-solid" type="text" name="username" placeholder="Username" spellcheck="false" required />
+								<input data-i18n="[placeholder]login.username" class="form-control form-control-lg form-control-solid" type="text" name="username" placeholder="Username" autocomplete="on" spellcheck="false" required />
 							</div>
 							<div class="fv-row mb-10">
 								<input data-i18n="[placeholder]login.password" class="form-control form-control-lg form-control-solid" type="password" name="password" placeholder="Password" autocomplete="current-password" spellcheck="false" required />
@@ -58,23 +58,27 @@ explicit grant from the SFTPGo Team ([email protected]).
 								{{- if not .FormDisabled}}
 								<div data-i18n="general.or" class="text-center text-muted text-uppercase fw-bold mb-5">or</div>
 								{{- end}}
-								<a href="{{.OpenIDLoginURL}}" class="btn btn-flex flex-center btn-light btn-lg w-100 mb-5">
+								<a href="{{.OpenIDLoginURL}}" class="btn btn-flex btn-outline flex-center btn-active-color-primary bg-state-light btn-lg w-100 mb-5">
 									<img alt="Logo" src="{{.StaticURL}}/img/openid-logo.png" class="h-20px me-3" />
 									<span data-i18n="login.signin_openid">Sign in with OpenID</span>
 								</a>
 								{{- end}}
 							</div>
 						</form>
-						{{- if or .AltLoginURL (and .Branding.DisclaimerName .Branding.DisclaimerPath) }}
-						<div class="d-flex flex-center flex-column-auto pt-10 mt-5">
-							<div class="d-flex align-items-center fw-semibold fs-6">
+						<div class=" d-flex flex-stack pt-5 mt-5">
+							<div class="me-10">
+								<select id="languageSwitcher" name="language" class="form-select form-select-solid form-select-sm" data-control="i18n-select2" data-hide-search="true">
+								</select>
+							</div>
+							<div class="d-flex fw-semibold text-primary">
 								{{- if .AltLoginURL}}
-								<a href="{{.AltLoginURL}}" class="text-muted text-hover-primary px-2">{{.AltLoginName}}</a>
+								<a href="{{.AltLoginURL}}" class="px-2">{{.AltLoginName}}</a>
 								{{- end}}
 								{{- if and .Branding.DisclaimerName .Branding.DisclaimerPath}}
-								<a href="{{.StaticURL}}{{.Branding.DisclaimerPath}}" target="_blank" class="text-muted text-hover-primary px-2">{{.Branding.DisclaimerName}}</a>
+								<a href="{{.StaticURL}}{{.Branding.DisclaimerPath}}" target="_blank" class="px-2">
+									<span data-i18n="custom.disclaimer_webclient">{{.Branding.DisclaimerName}}</span>
+								</a>
 								{{- end}}
 							</div>
 						</div>
-						{{- end}}
 {{- end}}

+ 2 - 2
templates/webclient/mfa.html

@@ -59,7 +59,7 @@ explicit grant from the SFTPGo Team ([email protected]).
         {{- template "errmsg" ""}}
 
         <div class="form-group row mt-10">
-            <label data-i18n="general.configuration" class="col-md-3 col-form-label">Configuration</label>
+            <label for="id_config" data-i18n="general.configuration" class="col-md-3 col-form-label">Configuration</label>
             <div class="col-md-9">
                 <select id="id_config" name="config_name" class="form-select" data-control="i18n-select2" data-hide-search="true">
                     <option data-i18n="general.none" value="">None</option>
@@ -71,7 +71,7 @@ explicit grant from the SFTPGo Team ([email protected]).
         </div>
 
         <div class="form-group row mt-10">
-            <label data-i18n="2fa.require_for" class="col-md-3 col-form-label required">
+            <label for="id_protocols" data-i18n="2fa.require_for" class="col-md-3 col-form-label required">
                 Require 2FA for
             </label>
             <div class="col-md-9">

+ 15 - 13
templates/webclient/share.html

@@ -24,17 +24,17 @@ explicit grant from the SFTPGo Team ([email protected]).
         {{- template "errmsg" .Error}}
         <form id="share_form" action="{{.CurrentURL}}" method="POST" autocomplete="off">
             <div class="form-group row">
-                <label data-i18n="general.name" class="col-md-3 col-form-label">Name</label>
+                <label for="name" data-i18n="general.name" class="col-md-3 col-form-label">Name</label>
                 <div class="col-md-9">
-                    <input type="text" class="form-control" placeholder="" name="name" value="{{.Share.Name}}"
+                    <input id="name" type="text" class="form-control" placeholder="" name="name" value="{{.Share.Name}}"
                         maxlength="255" autocomplete="nope" required {{if not .IsAdd}}readonly{{end}} />
                 </div>
             </div>
 
             <div class="form-group row mt-10">
-                <label data-i18n="share.scope" class="col-md-3 col-form-label">Scope</label>
+                <label for="scope" data-i18n="share.scope" class="col-md-3 col-form-label">Scope</label>
                 <div class="col-md-9">
-                    <select name="scope" class="form-select" data-control="i18n-select2" data-hide-search="true">
+                    <select id="scope" name="scope" class="form-select" data-control="i18n-select2" data-hide-search="true">
                         <option data-i18n="share.scope_read" value="1" {{if eq .Share.Scope 1 }}selected{{end}}>Read</option>
                         <option data-i18n="share.scope_write" value="2" {{if eq .Share.Scope 2 }}selected{{end}}>Write</option>
                         <option data-i18n="share.scope_read_write" value="3" {{if eq .Share.Scope 3 }}selected{{end}}>Read/Write</option>
@@ -112,9 +112,9 @@ explicit grant from the SFTPGo Team ([email protected]).
             </div>
 
             <div class="form-group row mt-10">
-                <label data-i18n="login.password" class="col-md-3 col-form-label">Password</label>
+                <label for="password" data-i18n="login.password" class="col-md-3 col-form-label">Password</label>
                 <div class="col-md-9">
-                    <input type="password" class="form-control" name="password" autocomplete="new-password"
+                    <input id="password" type="password" class="form-control" name="password" autocomplete="new-password"
                         placeholder="" spellcheck="false" value="{{.Share.Password}}" />
                     <div data-i18n="share.password_help" class="form-text">
                         If set the share will be password-protected
@@ -123,7 +123,7 @@ explicit grant from the SFTPGo Team ([email protected]).
             </div>
 
             <div class="form-group row mt-10">
-                <label data-i18n="share.expiration" class="col-md-3 col-form-label">Expiration</label>
+                <label for="id_expiration" data-i18n="share.expiration" class="col-md-3 col-form-label">Expiration</label>
                 <div class="col-md-9 d-flex">
                     <input data-i18n="[placeholder]share.expiration_help" id="id_expiration" class="form-control" placeholder="Pick an expiration date" />
                     <button class="btn btn-icon btn-light-danger ms-2 d-none" id="id_expiration_clear">
@@ -136,9 +136,9 @@ explicit grant from the SFTPGo Team ([email protected]).
             </div>
 
             <div class="form-group row mt-10">
-                <label data-i18n="share.max_tokens" class="col-md-3 col-form-label">Max tokens</label>
+                <label for="max_tokens" data-i18n="share.max_tokens" class="col-md-3 col-form-label">Max tokens</label>
                 <div class="col-md-9">
-                    <input type="number" min="0" class="form-control" name="max_tokens" value="{{.Share.MaxTokens}}" />
+                    <input id="max_tokens" type="number" min="0" class="form-control" name="max_tokens" value="{{.Share.MaxTokens}}" />
                     <div data-i18n="share.max_tokens_help" class="form-text">
                         Maximum number of times this share can be accessed. 0 means no limit
                     </div>
@@ -146,9 +146,9 @@ explicit grant from the SFTPGo Team ([email protected]).
             </div>
 
             <div class="form-group row mt-10">
-                <label data-i18n="general.allowed_ip_mask" class="col-md-3 col-form-label">Allowed IP/Mask</label>
+                <label for="allowed_ip" data-i18n="general.allowed_ip_mask" class="col-md-3 col-form-label">Allowed IP/Mask</label>
                 <div class="col-md-9">
-                    <textarea class="form-control" name="allowed_ip" rows="3"
+                    <textarea id="allowed_ip" class="form-control" name="allowed_ip" rows="3"
                         placeholder="">{{.Share.GetAllowedFromAsString}}</textarea>
                     <div data-i18n="general.allowed_ip_mask_help" class="form-text">
                         Comma separated IP/Mask in CIDR format, for example "192.168.1.0/24,10.8.0.100/32"
@@ -157,9 +157,9 @@ explicit grant from the SFTPGo Team ([email protected]).
             </div>
 
             <div class="form-group row mt-10">
-                <label data-i18n="general.description" class="col-md-3 col-form-label">Description</label>
+                <label for="description" data-i18n="general.description" class="col-md-3 col-form-label">Description</label>
                 <div class="col-md-9">
-                    <textarea class="form-control" name="description" rows="3"
+                    <textarea id="description" class="form-control" name="description" rows="3"
                         placeholder="">{{.Share.Description}}</textarea>
                 </div>
             </div>
@@ -184,6 +184,7 @@ explicit grant from the SFTPGo Team ([email protected]).
 
 {{- define "extra_js"}}
 <script {{- if .CSPNonce}} nonce="{{.CSPNonce}}"{{- end}} src="{{.StaticURL}}/assets/plugins/custom/formrepeater/formrepeater.bundle.js"></script>
+<script {{- if .CSPNonce}} nonce="{{.CSPNonce}}"{{- end}} src="{{.StaticURL}}/assets/plugins/custom/flatpickr/l10n/it.js"></script>
 <script type="text/javascript" {{- if .CSPNonce}} nonce="{{.CSPNonce}}"{{- end}}>
     $(document).on("i18nshow", function(){
             initRepeater('#paths');
@@ -202,6 +203,7 @@ explicit grant from the SFTPGo Team ([email protected]).
                 },
                 defaultHour: 23,
                 defaultMinute: 59,
+                locale: i18next.language,
                 onChange: function(selectedDates, dateStr, instance) {
                     if (selectedDates.length > 0){
                         $('#id_expiration_clear').removeClass("d-none");

+ 6 - 0
templates/webclient/sharelogin.html

@@ -44,4 +44,10 @@ explicit grant from the SFTPGo Team ([email protected]).
         </button>
     </div>
 </form>
+<div class=" d-flex flex-stack pt-5 mt-5">
+    <div class="me-10">
+        <select id="languageSwitcher" name="language" class="form-select form-select-solid form-select-sm" data-control="i18n-select2" data-hide-search="true">
+        </select>
+    </div>
+</div>
 {{- end}}

+ 2 - 2
templates/webclient/shares.html

@@ -39,8 +39,8 @@ explicit grant from the SFTPGo Team ([email protected]).
                         <span class="path1"></span>
                         <span class="path2"></span>
                     </i>
-                    <input data-i18n="[placeholder]general.search" type="text" data-share-table-filter="search"
-                        class="form-control form-control-solid w-200px ps-15" placeholder="Search" />
+                    <input name="search" data-i18n="[placeholder]general.search" type="text" data-share-table-filter="search"
+                        class="form-control rounded-1 w-200px ps-15" placeholder="Search" />
                 </div>
 
                 <div class="d-flex justify-content-end" data-share-table-toolbar="base">

이 변경점에서 너무 많은 파일들이 변경되어 몇몇 파일들은 표시되지 않았습니다.