Use fs for language, add lang_files option

The local app translations are loaded, and then if [files]/lang_files
is provided (a directory containing custom translations), any found
inside it are loaded over top. This makes customizing much easier.
This commit is contained in:
Harvey Tindall 2021-02-01 17:39:19 +00:00
parent fefe2d82a4
commit 0330540f87
Signed by: hrfee
GPG Key ID: BBC65952848FB1A2
7 changed files with 207 additions and 83 deletions

View File

@ -860,6 +860,14 @@
"type": "text",
"value": "",
"description": "Path to directory containing custom versions of web ui pages. See wiki for more info."
},
"lang_files": {
"name": "Custom language files directory",
"required": false,
"requires_restart": true,
"type": "text",
"value": "",
"description": "Useful if you want to customize the text in jfa-go. Should follow the same structure as the 'lang' directory, which you can see on GitHub."
}
}
}

3
go.mod
View File

@ -51,7 +51,8 @@ require (
golang.org/x/net v0.0.0-20210119194325-5f4716e94777 // indirect
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c // indirect
golang.org/x/text v0.3.5 // indirect
golang.org/x/tools v0.1.0 // indirect
golang.org/x/tools v0.1.1-0.20210129181147-0cef57b5b584 // indirect
golang.org/x/tools/gopls v0.0.0-20210201165201-19db92ec3be1 // indirect
google.golang.org/protobuf v1.25.0 // indirect
gopkg.in/ini.v1 v1.62.0
)

42
go.sum
View File

@ -21,6 +21,7 @@ github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/creack/pty v1.1.9 h1:uDmaGzcdjhF4i/plgjmEsriH11Y0o7RKapEf/LDaM3w=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v0.0.0-20161028175848-04cdfd42973b/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@ -158,14 +159,22 @@ github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/renameio v0.1.0 h1:GOZbcHa3HfsPKPlmyPyN2KEohoMXOhdMbHrvbpl2QaA=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/safehtml v0.0.2 h1:ZOt2VXg4x24bW0m2jtzAOkhoXV0iM8vNKc0paByCZqM=
github.com/google/safehtml v0.0.2/go.mod h1:L4KWwDsUJdECRAEpZoBn3O64bQaywRscowZjJAzjHnU=
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/hrfee/jfa-go/jfapi v0.0.0-20210109010027-4aae65518089 h1:WRk+JAywI8V4u+PBQpdvXBX73yCZxgnLwyIiX7xL+Xc=
github.com/hrfee/jfa-go/jfapi v0.0.0-20210109010027-4aae65518089/go.mod h1:Al1Rd1JGtpS+3KnK8t7+J0CZVDbT86QJrXHR6kZijds=
github.com/jba/templatecheck v0.5.0 h1:sZwNjXG3xNApuwKmgUWEo2JuxmG0sgNaELl0zwRQ9x8=
github.com/jba/templatecheck v0.5.0/go.mod h1:/1k7EajoSErFI9GLHAsiIJEaNLt3ALKNw2TV7z2SYv4=
github.com/jordan-wright/email v0.0.0-20200602115436-fd8a7622303e h1:OGunVjqY7y4U4laftpEHv+mvZBlr7UGimJXKEGQtg48=
github.com/jordan-wright/email v0.0.0-20200602115436-fd8a7622303e/go.mod h1:Fy2gCFfZhay8jplf/Csj6cyH/oshQTkLQYZbKkcV+SY=
github.com/jordan-wright/email v4.0.1-0.20200917010138-e1c00e156980+incompatible h1:CL0ooBNfbNyJTJATno+m0h+zM5bW6v7fKlboKUGP/dI=
@ -179,6 +188,8 @@ github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGn
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68=
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/kisielk/gotool v1.0.0 h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/knz/strtime v0.0.0-20200318182718-be999391ffa9 h1:GQE1iatYDRrIidq4Zf/9ZzKWyrTk2sXOYc1JADbkAjQ=
github.com/knz/strtime v0.0.0-20200318182718-be999391ffa9/go.mod h1:4ZxfWkxwtc7dBeifERVVWRy9F9rTU9p0yCDgeCtlius=
github.com/knz/strtime v0.0.0-20200924090105-187c67f2bf5e h1:ViPE0JEOvtw5I0EGUiFSr2VNKGNU+3oBT+oHbDXHbxk=
@ -248,21 +259,31 @@ github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4 h1:gQz4mCbXsO+nc9n1hCxHcGA3Zx3Eo+UHZoInFGUIXNM=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.5.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/rogpeppe/go-internal v1.6.2 h1:aIihoIOHCiLZHxyoNQ+ABL4NKhFTgKLBdMLyEAh98m0=
github.com/rogpeppe/go-internal v1.6.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sanity-io/litter v1.3.0 h1:5ZO+weUsqdSWMUng5JnpkW/Oz8iTXiIdeumhQr1sSjs=
github.com/sanity-io/litter v1.3.0/go.mod h1:5Z71SvaYy5kcGtyglXOC9rrUi3c1E8CamFWjQsazTh0=
github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
github.com/stretchr/testify v0.0.0-20161117074351-18a02ba4a312/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
@ -313,6 +334,7 @@ github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6Kllzaw
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasttemplate v1.0.1 h1:tY9CJiPnMXf1ERmG2EyK7gNUd+c6RKGD0IfU8WdUSz8=
github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1 h1:ruQGxdhGHe7FWOJPT0mKs5+pD2Xs1Bm/kdGlHO04FmM=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
@ -332,8 +354,11 @@ golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTk
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3 h1:XQyxROzUlZH+WIQwySDgnISgOivlhjIEwaQaJEJrrN0=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.0 h1:8pl+sMODzuvGJkmj2W4kZihvVb5mKm8pB/X44PIQHv8=
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@ -347,6 +372,7 @@ golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 h1:k7pJ2yAPLPgbskkFdhRCsA77k2fySZ1zf2zCjvQCiIM=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200923182212-328152dc79b1 h1:Iu68XRPd67wN4aRGGWwwq6bZo/25jR6uu52l/j2KkUE=
@ -373,6 +399,7 @@ golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 h1:SQFwaSi55rU7vdNs9Yr0Z324VNlrF+0wMqRXT4St8ck=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@ -429,6 +456,7 @@ golang.org/x/tools v0.0.0-20190611222205-d73e1c7e250b/go.mod h1:/rFqwRUd4F7ZHNgw
golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59 h1:QjA/9ArTfVTLfEhClDCG7SGrZkZixxWpwNCDiwJfh88=
golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200410194907-79a7a3126eef/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200820010801-b793a1359eac/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200923182640-463111b69878 h1:VUw1+Jf6KJPf82mbTQMia6HCnNMv2BbAipkEZ4KTcqQ=
golang.org/x/tools v0.0.0-20200923182640-463111b69878/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
@ -450,10 +478,15 @@ golang.org/x/tools v0.0.0-20201114224030-61ea331ec02b h1:Ych5r0Z6MLML1fgf5hTg9p5
golang.org/x/tools v0.0.0-20201114224030-61ea331ec02b/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201120155355-20be4ac4bd6e h1:t96dS3DO8DGjawSLJL/HIdz8CycAd2v07XxqB3UPTi0=
golang.org/x/tools v0.0.0-20201120155355-20be4ac4bd6e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210101214203-2dba1e4ea05c/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210104081019-d8d6ddbec6ee h1:5xKxdl/RhlelmSPaxyVeq5PYSmJ4H14yeQT58qP1F6o=
golang.org/x/tools v0.0.0-20210104081019-d8d6ddbec6ee/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.0 h1:po9/4sTYwZU9lPhi1tOrb4hCv3qrhiQ77LZfGa2OjwY=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/tools v0.1.1-0.20210129181147-0cef57b5b584 h1:JAI5SUo/oOtQXK4jvtjJMlwF5opt8qBUpxGa86SJ6zU=
golang.org/x/tools v0.1.1-0.20210129181147-0cef57b5b584/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/tools/gopls v0.0.0-20210201165201-19db92ec3be1 h1:YRvjnCA/wBOOkQAEKC5ts16/1IJ+NEO9eevhfDF5ues=
golang.org/x/tools/gopls v0.0.0-20210201165201-19db92ec3be1/go.mod h1:DWl5nefYvX46i2mLQVu6Ud0ycJQ3HNPbQKzUHT3VUek=
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=
@ -483,8 +516,11 @@ google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0 h1:0vLT13EuvQ0hNvakwLuFZ/jYrLp5F3kcWHXdRggjCE8=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM=
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
gopkg.in/go-playground/validator.v8 v8.18.2 h1:lFB4DoMU6B626w8ny76MV7VX6W2VHct2GVOI3xgiMrQ=
@ -515,3 +551,9 @@ gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc h1:/hemPrYIhOhy8zYrNj+069zDB68us2sMGsfkFJO0iZs=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2020.1.6 h1:W18jzjh8mfPez+AwGLxmOImucz/IFjpNlrKVnaj2YVc=
honnef.co/go/tools v0.0.1-2020.1.6/go.mod h1:pyyisuGw24ruLjrr1ddx39WE0y9OooInRzEYLhQB2YY=
mvdan.cc/gofumpt v0.1.0 h1:hsVv+Y9UsZ/mFZTxJZuHVI6shSQCtzZ11h1JEFPAZLw=
mvdan.cc/gofumpt v0.1.0/go.mod h1:yXG1r1WqZVKWbVRtBWKWX9+CxGYfA51nSomhM0woR48=
mvdan.cc/xurls/v2 v2.2.0 h1:NSZPykBXJFCetGZykLAxaL6SIpvbVy/UFEniIfHAa8A=
mvdan.cc/xurls/v2 v2.2.0/go.mod h1:EV1RMtya9D6G5DMYPGD8zTQzaHet6Jh8gFlRgGRJeO8=

18
main.go
View File

@ -61,6 +61,7 @@ type appContext struct {
dataPath string
systemFS fs.FS
localFS fs.FS
langFS fs.FS
webFS httpFS
cssClass string
jellyfinLogin bool
@ -202,6 +203,7 @@ func start(asDaemon, firstCall bool) {
app.configPath = filepath.Join(app.dataPath, "config.ini")
executable, _ := os.Executable()
app.localFS = os.DirFS(filepath.Join(filepath.Dir(executable), "data"))
app.langFS = os.DirFS(filepath.Join(filepath.Dir(executable), "data", "lang"))
app.systemFS = os.DirFS("/")
wfs := os.DirFS(filepath.Join(filepath.Dir(executable), "data", "web"))
app.webFS = httpFS{
@ -340,11 +342,17 @@ func start(asDaemon, firstCall bool) {
}()
}
app.storage.lang.CommonPath = filepath.Join("lang", "common")
app.storage.lang.FormPath = filepath.Join("lang", "form")
app.storage.lang.AdminPath = filepath.Join("lang", "admin")
app.storage.lang.EmailPath = filepath.Join("lang", "email")
err := app.storage.loadLang()
app.storage.lang.CommonPath = "common"
app.storage.lang.FormPath = "form"
app.storage.lang.AdminPath = "admin"
app.storage.lang.EmailPath = "email"
externalLang := app.config.Section("files").Key("lang_files").MustString("")
var err error
if externalLang == "" {
err = app.storage.loadLang(app.langFS)
} else {
err = app.storage.loadLang(app.langFS, os.DirFS(externalLang))
}
if err != nil {
app.info.Fatalf("Failed to load language files: %+v\n", err)
}

View File

@ -2,7 +2,7 @@ package main
import (
"encoding/json"
"os"
"io/fs"
"path/filepath"
"strings"
@ -70,13 +70,14 @@ func (app *appContext) TestJF(gc *gin.Context) {
gc.JSON(200, map[string]bool{"success": true})
}
func (st *Storage) loadLangSetup() error {
// The first filesystem passed should be the localFS, to ensure the local lang files are loaded first.
func (st *Storage) loadLangSetup(filesystems ...fs.FS) error {
st.lang.Setup = map[string]setupLang{}
var english setupLang
load := func(fname string) error {
load := func(filesystem fs.FS, fname string) error {
index := strings.TrimSuffix(fname, filepath.Ext(fname))
lang := setupLang{}
f, err := os.ReadFile(filepath.Join(st.lang.SetupPath, fname))
f, err := fs.ReadFile(filesystem, filepath.Join(st.lang.SetupPath, fname))
if err != nil {
return err
}
@ -107,20 +108,29 @@ func (st *Storage) loadLangSetup() error {
st.lang.Setup[index] = lang
return nil
}
err := load("en-us.json")
if err != nil {
engFound := false
var err error
for _, filesystem := range filesystems {
err = load(filesystem, "en-us.json")
if err == nil {
engFound = true
}
}
if !engFound {
return err
}
english = st.lang.Setup["en-us"]
files, err := os.ReadDir(st.lang.SetupPath)
if err != nil {
return err
}
for _, f := range files {
if f.Name() != "en-us.json" {
err = load(f.Name())
if err != nil {
return err
for _, filesystem := range filesystems {
files, err := fs.ReadDir(filesystem, st.lang.SetupPath)
if err != nil {
return err
}
for _, f := range files {
if f.Name() != "en-us.json" {
err = load(filesystem, f.Name())
if err != nil {
return err
}
}
}
}

View File

@ -6,8 +6,10 @@ import (
"strings"
)
// Since the gin-static middleware uses a version of http.Filesystem with an extra Exists() func, we extend it here.
type httpFS struct {
hfs http.FileSystem
hfs http.FileSystem // Created by converting fs.FS using http.FS()
fs fs.FS
}

View File

@ -2,6 +2,7 @@ package main
import (
"encoding/json"
"io/fs"
"log"
"os"
"path/filepath"
@ -62,20 +63,20 @@ type Lang struct {
Setup setupLangs
}
func (st *Storage) loadLang() (err error) {
err = st.loadLangCommon()
func (st *Storage) loadLang(filesystems ...fs.FS) (err error) {
err = st.loadLangCommon(filesystems...)
if err != nil {
return
}
err = st.loadLangAdmin()
err = st.loadLangAdmin(filesystems...)
if err != nil {
return
}
err = st.loadLangForm()
err = st.loadLangForm(filesystems...)
if err != nil {
return
}
err = st.loadLangEmail()
err = st.loadLangEmail(filesystems...)
return
}
@ -120,13 +121,13 @@ func patchQuantityStrings(english, other *map[string]quantityString) {
}
}
func (st *Storage) loadLangCommon() error {
func (st *Storage) loadLangCommon(filesystems ...fs.FS) error {
st.lang.Common = map[string]commonLang{}
var english commonLang
load := func(fname string) error {
load := func(filesystem fs.FS, fname string) error {
index := strings.TrimSuffix(fname, filepath.Ext(fname))
lang := commonLang{}
f, err := os.ReadFile(filepath.Join(st.lang.CommonPath, fname))
f, err := fs.ReadFile(filesystem, filepath.Join(st.lang.CommonPath, fname))
if err != nil {
return err
}
@ -143,33 +144,46 @@ func (st *Storage) loadLangCommon() error {
st.lang.Common[index] = lang
return nil
}
err := load("en-us.json")
if err != nil {
engFound := false
var err error
for _, filesystem := range filesystems {
err = load(filesystem, "en-us.json")
if err == nil {
engFound = true
}
}
if !engFound {
return err
}
english = st.lang.Common["en-us"]
files, err := os.ReadDir(st.lang.CommonPath)
if err != nil {
return err
}
for _, f := range files {
if f.Name() != "en-us.json" {
err = load(f.Name())
if err != nil {
return err
commonLoaded := false
for _, filesystem := range filesystems {
files, err := fs.ReadDir(filesystem, st.lang.CommonPath)
if err != nil {
continue
}
for _, f := range files {
if f.Name() != "en-us.json" {
err = load(filesystem, f.Name())
if err == nil {
commonLoaded = true
}
}
}
}
if !commonLoaded {
return err
}
return nil
}
func (st *Storage) loadLangAdmin() error {
func (st *Storage) loadLangAdmin(filesystems ...fs.FS) error {
st.lang.Admin = map[string]adminLang{}
var english adminLang
load := func(fname string) error {
load := func(filesystem fs.FS, fname string) error {
index := strings.TrimSuffix(fname, filepath.Ext(fname))
lang := adminLang{}
f, err := os.ReadFile(filepath.Join(st.lang.AdminPath, fname))
f, err := fs.ReadFile(filesystem, filepath.Join(st.lang.AdminPath, fname))
if err != nil {
return err
}
@ -194,33 +208,46 @@ func (st *Storage) loadLangAdmin() error {
st.lang.Admin[index] = lang
return nil
}
err := load("en-us.json")
if err != nil {
engFound := false
var err error
for _, filesystem := range filesystems {
err = load(filesystem, "en-us.json")
if err == nil {
engFound = true
}
}
if !engFound {
return err
}
english = st.lang.Admin["en-us"]
files, err := os.ReadDir(st.lang.AdminPath)
if err != nil {
return err
}
for _, f := range files {
if f.Name() != "en-us.json" {
err = load(f.Name())
if err != nil {
return err
adminLoaded := false
for _, filesystem := range filesystems {
files, err := fs.ReadDir(filesystem, st.lang.AdminPath)
if err != nil {
continue
}
for _, f := range files {
if f.Name() != "en-us.json" {
err = load(filesystem, f.Name())
if err == nil {
adminLoaded = true
}
}
}
}
if !adminLoaded {
return err
}
return nil
}
func (st *Storage) loadLangForm() error {
func (st *Storage) loadLangForm(filesystems ...fs.FS) error {
st.lang.Form = map[string]formLang{}
var english formLang
load := func(fname string) error {
load := func(filesystem fs.FS, fname string) error {
index := strings.TrimSuffix(fname, filepath.Ext(fname))
lang := formLang{}
f, err := os.ReadFile(filepath.Join(st.lang.FormPath, fname))
f, err := fs.ReadFile(filesystem, filepath.Join(st.lang.FormPath, fname))
if err != nil {
return err
}
@ -250,33 +277,46 @@ func (st *Storage) loadLangForm() error {
st.lang.Form[index] = lang
return nil
}
err := load("en-us.json")
if err != nil {
engFound := false
var err error
for _, filesystem := range filesystems {
err = load(filesystem, "en-us.json")
if err == nil {
engFound = true
}
}
if !engFound {
return err
}
english = st.lang.Form["en-us"]
files, err := os.ReadDir(st.lang.FormPath)
if err != nil {
return err
}
for _, f := range files {
if f.Name() != "en-us.json" {
err = load(f.Name())
if err != nil {
return err
formLoaded := false
for _, filesystem := range filesystems {
files, err := fs.ReadDir(filesystem, st.lang.FormPath)
if err != nil {
continue
}
for _, f := range files {
if f.Name() != "en-us.json" {
err = load(filesystem, f.Name())
if err == nil {
formLoaded = true
}
}
}
}
if !formLoaded {
return err
}
return nil
}
func (st *Storage) loadLangEmail() error {
func (st *Storage) loadLangEmail(filesystems ...fs.FS) error {
st.lang.Email = map[string]emailLang{}
var english emailLang
load := func(fname string) error {
load := func(filesystem fs.FS, fname string) error {
index := strings.TrimSuffix(fname, filepath.Ext(fname))
lang := emailLang{}
f, err := os.ReadFile(filepath.Join(st.lang.EmailPath, fname))
f, err := fs.ReadFile(filesystem, filepath.Join(st.lang.EmailPath, fname))
if err != nil {
return err
}
@ -299,23 +339,36 @@ func (st *Storage) loadLangEmail() error {
st.lang.Email[index] = lang
return nil
}
err := load("en-us.json")
if err != nil {
engFound := false
var err error
for _, filesystem := range filesystems {
err = load(filesystem, "en-us.json")
if err == nil {
engFound = true
}
}
if !engFound {
return err
}
english = st.lang.Email["en-us"]
files, err := os.ReadDir(st.lang.EmailPath)
if err != nil {
return err
}
for _, f := range files {
if f.Name() != "en-us.json" {
err = load(f.Name())
if err != nil {
return err
emailLoaded := false
for _, filesystem := range filesystems {
files, err := fs.ReadDir(filesystem, st.lang.EmailPath)
if err != nil {
continue
}
for _, f := range files {
if f.Name() != "en-us.json" {
err = load(filesystem, f.Name())
if err == nil {
emailLoaded = true
}
}
}
}
if !emailLoaded {
return err
}
return nil
}