Add github.com/jeandeaual/go-locale for locale-detection across platform

pull/206/head
Simon Roberts 3 years ago
parent 11bf5e23df
commit 1cf12fd173
No known key found for this signature in database
GPG Key ID: 0F30F99E6B771FD4

@ -11,6 +11,7 @@ require (
github.com/gen2brain/beeep v0.0.0-20210529141713-5586760f0cc1
github.com/gliderlabs/ssh v0.3.3
github.com/goodsign/monday v1.0.0
github.com/jeandeaual/go-locale v0.0.0-20210323163322-5cf4ff553a8d
github.com/maruel/panicparse v1.6.1
github.com/mattn/go-runewidth v0.0.13
github.com/miguelmota/go-coinmarketcap v0.1.8

@ -37,13 +37,16 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
fyne.io/fyne v1.4.2/go.mod h1:xL4c3WmpE/Tvz5CEm5vqsaizU/EeOCm9DYlL2GtTSiM=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/toml v0.4.1 h1:GaI7EiDXDRfa8VshkTj7Fym7ha+y8/XxIgD2okUIjLw=
github.com/BurntSushi/toml v0.4.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
github.com/Kodeworks/golang-image-ico v0.0.0-20141118225523-73f0f4cfade9/go.mod h1:7uhhqiBaR4CpN0k9rMjOtjpcfGd6DG2m04zQxKnWQ0I=
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d h1:licZJFw2RwpHMqeKTCYkitsPqHNxTmd4SNR5r94FGM8=
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d/go.mod h1:asat636LX7Bqt5lYEZ27JNDcqxfjdBQuJ/MM4CN/Lzo=
github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c=
github.com/anaskhan96/soup v1.0.1 h1:3p9zOr7o2weHqDakRA1uR0SZNr6VhH5qPkm6p3gvS6o=
github.com/anaskhan96/soup v1.0.1/go.mod h1:pT5vs4HXDwA5y4KQCsKvnkpQd3D+joP7IqpiGskfWW0=
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
@ -84,6 +87,8 @@ github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5Kwzbycv
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fyne-io/mobile v0.1.2-0.20201127155338-06aeb98410cc/go.mod h1:/kOrWrZB6sasLbEy2JIvr4arEzQTXBTZGb3Y96yWbHY=
github.com/fyne-io/mobile v0.1.2/go.mod h1:/kOrWrZB6sasLbEy2JIvr4arEzQTXBTZGb3Y96yWbHY=
github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg=
github.com/gdamore/tcell v1.3.0/go.mod h1:Hjvr+Ofd+gLglo7RYKxxnzCBmev3BzsS67MebKS4zMM=
github.com/gen2brain/beeep v0.0.0-20210529141713-5586760f0cc1 h1:Xh9mvwEmhbdXlRSsgn+N0zj/NqnKvpeqL08oKDHln2s=
@ -91,15 +96,18 @@ github.com/gen2brain/beeep v0.0.0-20210529141713-5586760f0cc1/go.mod h1:ElSskYZe
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/gliderlabs/ssh v0.3.3 h1:mBQ8NiOgDkINJrZtoizkC3nDNYgSaWtxyem6S2XHBtA=
github.com/gliderlabs/ssh v0.3.3/go.mod h1:ZSS+CUoKHDrqVakTfTWUlKSr9MtMFkC4UvtQKD7O914=
github.com/go-gl/gl v0.0.0-20190320180904-bf2b1f2f34d7/go.mod h1:482civXOzJJCPzJ4ZOX/pwvXBWSnzD4OKMdH4ClKGbk=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200625191551-73d3c3675aa3/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-toast/toast v0.0.0-20190211030409-01e6764cf0a4 h1:qZNfIGkIANxGv/OqtnntR4DfOY2+BgwR60cAcu/i3SE=
github.com/go-toast/toast v0.0.0-20190211030409-01e6764cf0a4/go.mod h1:kW3HQ4UdaAyrUCSSDR4xUzBKW6O2iA4uHhk7AtyYp10=
github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/godbus/dbus/v5 v5.0.4 h1:9349emZab16e7zQvpmsbtjc18ykshndd8y2PG3sgJbA=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/goki/freetype v0.0.0-20181231101311-fa8a33aabaff/go.mod h1:wfqRWLHRBsRgkp5dmbG56SA0DmVtwrF5N3oPdI8t+Aw=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
@ -194,6 +202,10 @@ github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/jackmordaunt/icns v0.0.0-20181231085925-4f16af745526/go.mod h1:UQkeMHVoNcyXYq9otUupF7/h/2tmHlhrS2zw7ZVvUqc=
github.com/jeandeaual/go-locale v0.0.0-20210323163322-5cf4ff553a8d h1:VPBM6qn7uSBJroH61nL9yqtfK0xDWcmI5JHl11a2CJ0=
github.com/jeandeaual/go-locale v0.0.0-20210323163322-5cf4ff553a8d/go.mod h1:S0Hh9Ro1RbEQKfJA5XcnmGjcSQF+ZdSVikXVNQJMTAo=
github.com/josephspurrier/goversioninfo v0.0.0-20200309025242-14b0ab84c6ca/go.mod h1:eJTEwMjXb7kZ633hO3Ln9mBUCOjX2+FlTljvpl9SYdE=
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
@ -206,6 +218,7 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/lucasb-eyer/go-colorful v1.0.2/go.mod h1:0MS4r+7BZKSJ5mw4/S5MPN+qHFF1fYclkSPilDOKW0s=
github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/lucor/goinfo v0.0.0-20200401173949-526b5363a13a/go.mod h1:ORP3/rB5IsulLEBwQZCJyyV6niqmI7P4EWSmkug+1Ng=
github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
github.com/maruel/panicparse v1.6.1 h1:803MjBzGcUgE1vYgg3UMNq3G1oyYeKkMu3t6hBS97x0=
github.com/maruel/panicparse v1.6.1/go.mod h1:uoxI4w9gJL6XahaYPMq/z9uadrdr1SyHuQwV2q80Mm0=
@ -245,6 +258,9 @@ github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RR
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
github.com/nicksnyder/go-i18n/v2 v2.1.1/go.mod h1:d++QJC9ZVf7pa48qrsRWhMJ5pSHIPmS3OLqK1niyLxs=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d h1:VhgPp6v9qf9Agr/56bj7Y/xa04UccTW04VP0Qed4vnQ=
github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d/go.mod h1:YUTz3bUH2ZwIWBy3CJBeOBEugqcmXREj14T+iG/4k4U=
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
@ -253,7 +269,9 @@ github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FI
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
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=
@ -275,14 +293,18 @@ github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cobra v1.2.1 h1:+KmjbUw1hriSNMF55oPrkZcb27aECyrj8V2ytv7kWDw=
github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk=
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns=
github.com/srwiley/oksvg v0.0.0-20200311192757-870daf9aa564/go.mod h1:afMbS0qvv1m5tfENCwnOdZGOF8RGR/FsZ7bvBxQGZG4=
github.com/srwiley/rasterx v0.0.0-20200120212402-85cb7272f5e9/go.mod h1:mvWM0+15UqyrFKqdRjY6LuAVJR0HOVhJlEgZ5JWtSWU=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
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=
@ -337,6 +359,7 @@ golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EH
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@ -451,12 +474,14 @@ golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200720211630-cb9d2d5c5666/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200724161237-0e2f3a69832c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201223074533-0d417f636930/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -497,6 +522,7 @@ golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBn
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190808195139-e713427fea3f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
@ -518,6 +544,7 @@ golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapK
golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
golang.org/x/tools v0.0.0-20200328031815-3db5fc6bac03/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
@ -643,11 +670,13 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
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-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=

@ -0,0 +1 @@
* text eol=lf

@ -0,0 +1,44 @@
### Go ###
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib
# Test binary, built with `go test -c`
*.test
# Output of the go coverage tool
*.out
# Fyne Cross build folder
fyne-cross/
### Linux ###
*~
### Vim ###
# Swap
[._]*.s[a-v][a-z]
[._]*.sw[a-p]
[._]s[a-rt-v][a-z]
[._]ss[a-gi-z]
[._]sw[a-p]
# Session
Session.vim
# Auto-generated tag files
tags
# Persistent undo
[._]*.un~
### VisualStudioCode ###
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
.history

@ -0,0 +1,40 @@
run:
timeout: 5m
linters:
disable-all: true
enable:
# Default
- deadcode
- errcheck
- gosimple
- govet
- ineffassign
- staticcheck
- structcheck
- typecheck
- unused
- varcheck
# Manually enabled
- dupl
- gocyclo
- gofmt
- golint
- goprintffuncname
- lll
- misspell
- nakedret
- prealloc
- unconvert
- whitespace
linter-settings:
gocyclo:
# Minimal code complexity to report, 30 by default
min-complexity: 15
govet:
# Report about shadowed variables
check-shadowing: true
issues:
exclude-use-default: false
exclude:
# govet: Common false positives
- (possible misuse of unsafe.Pointer|should have signature)

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2020 Alexis Jeandeau
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

@ -0,0 +1,135 @@
# go-locale
[![PkgGoDev](https://pkg.go.dev/badge/github.com/jeandeaual/go-locale)](https://pkg.go.dev/github.com/jeandeaual/go-locale)
[![Go Report Card](https://goreportcard.com/badge/github.com/jeandeaual/go-locale)](https://goreportcard.com/report/github.com/jeandeaual/go-locale)
[![Coverage Status](https://coveralls.io/repos/github/jeandeaual/go-locale/badge.svg?branch=master)](https://coveralls.io/github/jeandeaual/go-locale?branch=master)
[![test](https://github.com/jeandeaual/go-locale/workflows/test/badge.svg)](https://github.com/jeandeaual/go-locale/actions?query=workflow%3Atest)
Go library used to retrieve the current locale(s) of the operating system.
## OS Support
* Windows\
Using [`GetUserDefaultLocaleName`](https://docs.microsoft.com/en-us/windows/win32/api/winnls/nf-winnls-getuserdefaultlocalename) and [`GetSystemDefaultLocaleName`](https://docs.microsoft.com/en-us/windows/win32/api/winnls/nf-winnls-getsystemdefaultlocalename).
* macOS\
Using `defaults read -g AppleLocale` and `defaults read -g AppleLanguages` (since environment variables like `LANG` are not usually set on macOS).
* Unix-like systems (Linux, BSD, etc.)\
Using the `LANGUAGE`, `LC_ALL`, `LC_MESSAGES` and `LANG` environment variables.
* WASM (JavaScript)\
Using [`navigator.language`](https://developer.mozilla.org/en-US/docs/Web/API/NavigatorLanguage/language) and [`navigator.languages`](https://developer.mozilla.org/en-US/docs/Web/API/NavigatorLanguage/languages).
* iOS\
Using [`[NSLocale preferredLanguages]`](https://developer.apple.com/documentation/foundation/nslocale/1415614-preferredlanguages).
* Android\
Using [`getResources().getConfiguration().getLocales`](https://developer.android.com/reference/android/content/res/Configuration#getLocales()) for Android N or later, or [`getResources().getConfiguration().locale`](https://developer.android.com/reference/android/content/res/Configuration#locale) otherwise.
Note: for Android, you'll first need to call `SetRunOnJVM`, depending on which mobile framework you're using:
* For [Fyne](https://fyne.io/):
```go
import (
"github.com/fyne-io/mobile/app"
"github.com/jeandeaual/go-locale"
)
func init() {
locale.SetRunOnJVM(app.RunOnJVM)
}
```
* For [gomobile](https://github.com/golang/go/wiki/Mobile):
```go
import (
"golang.org/x/mobile/app"
"github.com/jeandeaual/go-locale"
)
func init() {
locale.SetRunOnJVM(app.RunOnJVM)
}
```
## Usage
## GetLocales
`GetLocales` returns the user's preferred locales, by order of preference, as a slice of [IETF BCP 47 language tag](https://tools.ietf.org/rfc/bcp/bcp47.txt) (e.g. `[]string{"en-US", "fr-FR", "ja-JP"}`).
This works if the user set multiple languages on macOS and other Unix systems.
Otherwise, it returns a slice with a single locale.
```go
userLocales, err := locale.GetLocales()
if err == nil {
fmt.Println("Locales:", userLocales)
}
```
This can be used with [golang.org/x/text](https://godoc.org/golang.org/x/text) or [go-i18n](https://github.com/nicksnyder/go-i18n) to set the localizer's language preferences:
```go
import (
"github.com/jeandeaual/go-locale"
"golang.org/x/text/message"
)
func main() {
userLocales, _ := locale.GetLocales()
p := message.NewPrinter(message.MatchLanguage(userLocales...))
...
}
```
```go
import (
"github.com/jeandeaual/go-locale"
"github.com/nicksnyder/go-i18n/v2/i18n"
"golang.org/x/text/language"
)
func main() {
userLocales, _ := locale.GetLocales()
bundle := i18n.NewBundle(language.English)
localizer := i18n.NewLocalizer(bundle, userLocales...)
...
}
```
For a complete example, see [here](examples/getlocale-gui/main.go).
## GetLocale
`GetLocale` returns the current locale as defined in [IETF BCP 47](https://tools.ietf.org/rfc/bcp/bcp47.txt) (e.g. `"en-US"`).
```go
userLocale, err := locale.GetLocale()
if err == nil {
fmt.Println("Locale:", userLocale)
}
```
## GetLanguage
`GetLanguage` returns the current language as an [ISO 639](http://en.wikipedia.org/wiki/ISO_639) language code (e.g. `"en"`).
```go
userLanguage, err := locale.GetLanguage()
if err == nil {
fmt.Println("Language:", userLocale)
}
```
## GetRegion
`GetRegion` returns the current language as an [ISO 3166](http://en.wikipedia.org/wiki/ISO_3166-1) country code (e.g. `"US"`).
```go
userRegion, err := locale.GetRegion()
if err == nil {
fmt.Println("Region:", userRegion)
}
```
## Aknowledgements
Inspired by [jibber_jabber](https://github.com/cloudfoundry-attic/jibber_jabber).

@ -0,0 +1,243 @@
// +build android
#include <android/log.h>
#include <jni.h>
#include <stdlib.h>
#include <string.h>
#define LOG_FATAL(...) __android_log_print(ANDROID_LOG_FATAL, "GoLog", __VA_ARGS__)
static const char *jstringToCharCopy(JNIEnv *env, const jstring string)
{
const char *chars = (*env)->GetStringUTFChars(env, string, NULL);
const char *copy = strdup(chars);
(*env)->ReleaseStringUTFChars(env, string, chars);
return copy;
}
static jclass findClass(JNIEnv *env, const char *class_name)
{
jclass clazz = (*env)->FindClass(env, class_name);
if (clazz == NULL)
{
(*env)->ExceptionClear(env);
LOG_FATAL("cannot find %s", class_name);
return NULL;
}
return clazz;
}
static jmethodID findMethod(JNIEnv *env, jclass clazz, const char *name, const char *sig)
{
jmethodID m = (*env)->GetMethodID(env, clazz, name, sig);
if (m == 0)
{
(*env)->ExceptionClear(env);
LOG_FATAL("cannot find method %s %s", name, sig);
return 0;
}
return m;
}
static jfieldID findField(JNIEnv *env, jclass clazz, const char *name, const char *sig)
{
jfieldID f = (*env)->GetFieldID(env, clazz, name, sig);
if (f == 0)
{
(*env)->ExceptionClear(env);
LOG_FATAL("cannot find method %s %s", name, sig);
return 0;
}
return f;
}
static jfieldID getStaticFieldID(JNIEnv *env, jclass clazz, const char *name, const char *sig)
{
jfieldID f = (*env)->GetStaticFieldID(env, clazz, name, sig);
if (f == 0)
{
(*env)->ExceptionClear(env);
LOG_FATAL("cannot find static field %s %s", name, sig);
return 0;
}
return f;
}
static const char *toLanguageTag(JNIEnv *env, jobject locale)
{
const jclass java_util_Locale = findClass(env, "java/util/Locale");
const jstring localeStr =
(*env)->CallObjectMethod(
env,
locale,
(*env)->GetMethodID(env, java_util_Locale, "toLanguageTag", "()Ljava/lang/String;"));
return jstringToCharCopy(env, localeStr);
}
static const char *toLanguageTags(JNIEnv *env, jobject locales, jclass android_os_LocaleList)
{
const jstring localeStr =
(*env)->CallObjectMethod(
env,
locales,
(*env)->GetMethodID(env, android_os_LocaleList, "toLanguageTags", "()Ljava/lang/String;"));
return jstringToCharCopy(env, localeStr);
}
static int getAPIVersion(JNIEnv *env)
{
// VERSION is a nested class within android.os.Build (hence "$" rather than "/")
const jclass versionClass = findClass(env, "android/os/Build$VERSION");
const jfieldID sdkIntFieldID = getStaticFieldID(env, versionClass, "SDK_INT", "I");
int sdkInt = (*env)->GetStaticIntField(env, versionClass, sdkIntFieldID);
return sdkInt;
}
static const jobject getConfiguration(JNIEnv *env, jobject context)
{
const jclass android_content_ContextWrapper = findClass(env, "android/content/ContextWrapper");
const jclass android_content_res_Resources = findClass(env, "android/content/res/Resources");
const jobject resources =
(*env)->CallObjectMethod(
env,
context,
findMethod(env, android_content_ContextWrapper, "getResources", "()Landroid/content/res/Resources;"));
const jobject configuration =
(*env)->CallObjectMethod(
env,
resources,
findMethod(env, android_content_res_Resources, "getConfiguration", "()Landroid/content/res/Configuration;"));
return configuration;
}
static const jobject getLocaleObject(JNIEnv *env, jobject context)
{
const jobject configuration = getConfiguration(env, context);
const jclass android_content_res_Configuration = findClass(env, "android/content/res/Configuration");
int version = getAPIVersion(env);
// Android N or later
// See https://developer.android.com/reference/android/content/res/Configuration#locale
if (version >= 24) {
const jclass android_os_LocaleList = findClass(env, "android/os/LocaleList");
const jobject locales =
(*env)->CallObjectMethod(
env,
configuration,
findMethod(env, android_content_res_Configuration, "getLocales", "()Landroid/os/LocaleList;"));
return (*env)->CallObjectMethod(
env,
locales,
findMethod(env, android_os_LocaleList, "get", "(I)Ljava/util/Locale;"),
0);
} else {
return (*env)->GetObjectField(
env,
configuration,
findField(env, android_content_res_Configuration, "locale", "Ljava/util/Locale;"));
}
}
// Basically the same as `getResources().getConfiguration().getLocales()` for Android N and later,
// or `getResources().getConfiguration().locale` for earlier Android version.
const char *getLocales(uintptr_t java_vm, uintptr_t jni_env, uintptr_t ctx)
{
JavaVM *vm = (JavaVM *)java_vm;
JNIEnv *env = (JNIEnv *)jni_env;
jobject context = (jobject)ctx;
const jobject configuration = getConfiguration(env, context);
const jclass android_content_res_Configuration = findClass(env, "android/content/res/Configuration");
int version = getAPIVersion(env);
// Android N or later
// See https://developer.android.com/reference/android/content/res/Configuration#locale
if (version >= 24) {
const jclass android_os_LocaleList = findClass(env, "android/os/LocaleList");
const jobject locales =
(*env)->CallObjectMethod(
env,
configuration,
findMethod(env, android_content_res_Configuration, "getLocales", "()Landroid/os/LocaleList;"));
return toLanguageTags(env, locales, android_os_LocaleList);
} else {
const jobject locale =
(*env)->GetObjectField(
env,
configuration,
findField(env, android_content_res_Configuration, "locale", "Ljava/util/Locale;"));
return toLanguageTag(env, locale);
}
}
// Basically the same as `getResources().getConfiguration().getLocales().get(0).toString()` for Android N and later,
// or `getResources().getConfiguration().locale` for earlier Android version.
const char *getLocale(uintptr_t java_vm, uintptr_t jni_env, uintptr_t ctx)
{
JavaVM *vm = (JavaVM *)java_vm;
JNIEnv *env = (JNIEnv *)jni_env;
jobject context = (jobject)ctx;
const jobject locale = getLocaleObject(env, context);
return toLanguageTag(env, locale);
}
const char *getLanguage(uintptr_t java_vm, uintptr_t jni_env, uintptr_t ctx)
{
JavaVM *vm = (JavaVM *)java_vm;
JNIEnv *env = (JNIEnv *)jni_env;
jobject context = (jobject)ctx;
const jobject locale = getLocaleObject(env, context);
const jclass java_util_Locale = findClass(env, "java/util/Locale");
const jstring language =
(*env)->CallObjectMethod(
env,
locale,
(*env)->GetMethodID(env, java_util_Locale, "getLanguage", "()Ljava/lang/String;"));
return jstringToCharCopy(env, language);
}
const char *getRegion(uintptr_t java_vm, uintptr_t jni_env, uintptr_t ctx)
{
JavaVM *vm = (JavaVM *)java_vm;
JNIEnv *env = (JNIEnv *)jni_env;
jobject context = (jobject)ctx;
const jobject locale = getLocaleObject(env, context);
const jclass java_util_Locale = findClass(env, "java/util/Locale");
const jstring country =
(*env)->CallObjectMethod(
env,
locale,
(*env)->GetMethodID(env, java_util_Locale, "getCountry", "()Ljava/lang/String;"));
return jstringToCharCopy(env, country);
}

@ -0,0 +1,115 @@
// +build android
package locale
/*
#cgo LDFLAGS: -landroid -llog
#include <stdlib.h>
const char *getLocales(uintptr_t java_vm, uintptr_t jni_env, uintptr_t ctx);
const char *getLocale(uintptr_t java_vm, uintptr_t jni_env, uintptr_t ctx);
const char *getLanguage(uintptr_t java_vm, uintptr_t jni_env, uintptr_t ctx);
const char *getRegion(uintptr_t java_vm, uintptr_t jni_env, uintptr_t ctx);
*/
import "C"
import (
"errors"
"strings"
"unsafe"
)
var (
errRunOnJVMNotSet error = errors.New("you first need to call SetRunOnJVM")
runOnJVM func(fn func(vm, env, ctx uintptr) error) error
)
// SetRunOnJVM sets the RunOnJVM function that will be called by this library.
// This can either be "golang.org/x/mobile/app".RunOnJVM or "github.com/fyne-io/mobile/app".RunOnJVM,
// depending on the mobile framework you're using (both can't be imported at the same time).
//
// RunOnJVM runs fn on a new goroutine locked to an OS thread with a JNIEnv.
//
// RunOnJVM blocks until the call to fn is complete. Any Java
// exception or failure to attach to the JVM is returned as an error.
//
// The function fn takes vm, the current JavaVM*,
// env, the current JNIEnv*, and
// ctx, a jobject representing the global android.context.Context.
func SetRunOnJVM(fn func(fn func(vm, env, ctx uintptr) error) error) {
runOnJVM = fn
}
// GetLocale retrieves the IETF BCP 47 language tag set on the system.
func GetLocale() (string, error) {
if runOnJVM == nil {
return "", errRunOnJVMNotSet
}
locale := ""
err := runOnJVM(func(vm, env, ctx uintptr) error {
chars := C.getLocale(C.uintptr_t(vm), C.uintptr_t(env), C.uintptr_t(ctx))
locale = C.GoString(chars)
C.free(unsafe.Pointer(chars))
return nil
})
return locale, err
}
// GetLocales retrieves the IETF BCP 47 language tags set on the system.
func GetLocales() ([]string, error) {
if runOnJVM == nil {
return nil, errRunOnJVMNotSet
}
locales := ""
err := runOnJVM(func(vm, env, ctx uintptr) error {
chars := C.getLocales(C.uintptr_t(vm), C.uintptr_t(env), C.uintptr_t(ctx))
locales = C.GoString(chars)
C.free(unsafe.Pointer(chars))
return nil
})
return strings.Split(locales, ","), err
}
// GetLanguage retrieves the IETF BCP 47 language tag set on the system and
// returns the language part of the tag.
func GetLanguage() (string, error) {
if runOnJVM == nil {
return "", errRunOnJVMNotSet
}
language := ""
err := runOnJVM(func(vm, env, ctx uintptr) error {
chars := C.getLanguage(C.uintptr_t(vm), C.uintptr_t(env), C.uintptr_t(ctx))
language = C.GoString(chars)
C.free(unsafe.Pointer(chars))
return nil
})
return language, err
}
// GetRegion retrieves the IETF BCP 47 language tag set on the system and
// returns the region part of the tag.
func GetRegion() (string, error) {
if runOnJVM == nil {
return "", errRunOnJVMNotSet
}
region := ""
err := runOnJVM(func(vm, env, ctx uintptr) error {
chars := C.getRegion(C.uintptr_t(vm), C.uintptr_t(env), C.uintptr_t(ctx))
region = C.GoString(chars)
C.free(unsafe.Pointer(chars))
return nil
})
return region, err
}

@ -0,0 +1,95 @@
// +build darwin,!ios
package locale
import (
"fmt"
"os/exec"
"regexp"
"strings"
"syscall"
)
func execCommand(cmd string, args ...string) (status int, out []byte, err error) {
status = -1
command := exec.Command(cmd, args...)
// Execute the command and get the standard and error outputs
out, err = command.CombinedOutput()
if err != nil {
return
}
// Check the status code
if w, ok := command.ProcessState.Sys().(syscall.WaitStatus); ok {
status = w.ExitStatus()
}
return
}
// GetLocale retrieves the IETF BCP 47 language tag set on the system.
func GetLocale() (string, error) {
_, output, err := execCommand("defaults", "read", "-g", "AppleLocale")
if err != nil {
return "", fmt.Errorf("cannot determine locale: %v (output: %s)", err, output)
}
return strings.TrimRight(strings.Replace(string(output), "_", "-", 1), "\n"), nil
}
// appleLanguagesRegex is used to parse the output of "defaults read -g AppleLanguages"
// e.g.:
// (
// "en-US",
// "fr-FR",
// "ja-JP"
// )
var appleLanguagesRegex = regexp.MustCompile(`"([a-z]{2}-[A-Z]{2})"`)
// GetLocales retrieves the IETF BCP 47 language tags set on the system.
func GetLocales() ([]string, error) {
_, output, err := execCommand("defaults", "read", "-g", "AppleLanguages")
if err != nil {
return nil, fmt.Errorf("cannot determine locale: %v (output: %s)", err, output)
}
matches := appleLanguagesRegex.FindAllStringSubmatch(string(output), -1)
if len(matches) == 0 {
return nil, fmt.Errorf("invalid output from \"defaults read -g AppleLanguages\": %s", output)
}
locales := make([]string, 0, len(matches))
for _, match := range matches {
locales = append(locales, match[1])
}
return locales, nil
}
// GetLanguage retrieves the IETF BCP 47 language tag set on the system and
// returns the language part of the tag.
func GetLanguage() (string, error) {
language := ""
locale, err := GetLocale()
if err == nil {
language, _ = splitLocale(locale)
}
return language, err
}
// GetRegion retrieves the IETF BCP 47 language tag set on the system and
// returns the region part of the tag.
func GetRegion() (string, error) {
region := ""
locale, err := GetLocale()
if err == nil {
_, region = splitLocale(locale)
}
return region, err
}

@ -0,0 +1,51 @@
// +build ios
package locale
/*
#cgo CFLAGS: -x objective-c
#cgo LDFLAGS: -framework Foundation -framework UIKit
const char *getLocale();
const char *getLocales();
*/
import "C"
import (
"strings"
)
// GetLocale retrieves the IETF BCP 47 language tag set on the system.
func GetLocale() (string, error) {
return C.GoString(C.getLocale()), nil
}
// GetLocales retrieves the IETF BCP 47 language tags set on the system.
func GetLocales() ([]string, error) {
return strings.Split(C.GoString(C.getLocales()), ","), nil
}
// GetLanguage retrieves the IETF BCP 47 language tag set on the system and
// returns the language part of the tag.
func GetLanguage() (string, error) {
language := ""
locale, err := GetLocale()
if err == nil {
language, _ = splitLocale(locale)
}
return language, err
}
// GetRegion retrieves the IETF BCP 47 language tag set on the system and
// returns the region part of the tag.
func GetRegion() (string, error) {
region := ""
locale, err := GetLocale()
if err == nil {
_, region = splitLocale(locale)
}
return region, err
}

@ -0,0 +1,17 @@
// +build ios
#import <UIKit/UIKit.h>
const char *getLocale()
{
NSString *locale = [[NSLocale preferredLanguages] firstObject];
return [locale UTF8String];
}
const char *getLocales()
{
NSString *locales = [[NSLocale preferredLanguages] componentsJoinedByString:@","];
return [locales UTF8String];
}

@ -0,0 +1,75 @@
// +build js,wasm
package locale
import (
"errors"
"syscall/js"
)
func getNavigatorObject() js.Value {
return js.Global().Get("navigator")
}
// GetLocale retrieves the IETF BCP 47 language tag set on the system.
func GetLocale() (string, error) {
navigator := getNavigatorObject()
if navigator.IsUndefined() {
return "", errors.New("couldn't get window.navigator")
}
language := navigator.Get("language")
if language.IsUndefined() {
return "", errors.New("couldn't get window.navigator.language")
}
return language.String(), nil
}
// GetLocales retrieves the IETF BCP 47 language tags set on the system.
func GetLocales() ([]string, error) {
navigator := getNavigatorObject()
if navigator.IsUndefined() {
return nil, errors.New("couldn't get window.navigator")
}
languages := navigator.Get("languages")
if languages.IsUndefined() {
return nil, errors.New("couldn't get window.navigator.languages")
}
locales := make([]string, 0, languages.Length())
// Convert the Javascript object to a string slice
for i := 0; i < languages.Length(); i++ {
locales = append(locales, languages.Index(i).String())
}
return locales, nil
}
// GetLanguage retrieves the IETF BCP 47 language tag set on the system and
// returns the language part of the tag.
func GetLanguage() (string, error) {
language := ""
locale, err := GetLocale()
if err == nil {
language, _ = splitLocale(locale)
}
return language, err
}
// GetRegion retrieves the IETF BCP 47 language tag set on the system and
// returns the region part of the tag.
func GetRegion() (string, error) {
region := ""
locale, err := GetLocale()
if err == nil {
_, region = splitLocale(locale)
}
return region, err
}

@ -0,0 +1,116 @@
// +build !windows,!darwin,!js,!android
package locale
import (
"os"
"strings"
)
func splitLocales(locales string) []string {
// If the user set different locales, they might be set in $LANGUAGE,
// separated by a colon
return strings.Split(locales, ":")
}
func getLangFromEnv() string {
locale := ""
// Check the following environment variables for the language information
// See https://www.gnu.org/software/gettext/manual/html_node/Locale-Environment-Variables.html
for _, env := range [...]string{"LC_ALL", "LC_MESSAGES", "LANG"} {
locale = os.Getenv(env)
if len(locale) > 0 {
break
}
}
if locale == "C" || locale == "POSIX" {
return locale
}
// Check LANGUAGE if localization is enabled (not set to "C")
// See https://www.gnu.org/software/gettext/manual/html_node/The-LANGUAGE-variable.html#The-LANGUAGE-variable
languages := os.Getenv("LANGUAGE")
if len(languages) > 0 {
return languages
}
return locale
}
func getUnixLocales() []string {
locale := getLangFromEnv()
if locale == "C" || locale == "POSIX" || len(locale) == 0 {
return nil
}
return splitLocales(locale)
}
// GetLocale retrieves the IETF BCP 47 language tag set on the system.
func GetLocale() (string, error) {
unixLocales := getUnixLocales()
if unixLocales == nil {
return "", nil
}
language, region := splitLocale(unixLocales[0])
locale := language
if len(region) > 0 {
locale = strings.Join([]string{language, region}, "-")
}
return locale, nil
}
// GetLocales retrieves the IETF BCP 47 language tags set on the system.
func GetLocales() ([]string, error) {
unixLocales := getUnixLocales()
if unixLocales == nil {
return nil, nil
}
locales := make([]string, 0, len(unixLocales))
for _, unixLocale := range unixLocales {
language, region := splitLocale(unixLocale)
locale := language
if len(region) > 0 {
locale = strings.Join([]string{language, region}, "-")
}
locales = append(locales, locale)
}
return locales, nil
}
// GetLanguage retrieves the IETF BCP 47 language tag set on the system and
// returns the language part of the tag.
func GetLanguage() (string, error) {
language := ""
unixLocales := getUnixLocales()
if unixLocales == nil {
return "", nil
}
language, _ = splitLocale(unixLocales[0])
return language, nil
}
// GetRegion retrieves the IETF BCP 47 language tag set on the system and
// returns the region part of the tag.
func GetRegion() (string, error) {
region := ""
unixLocales := getUnixLocales()
if unixLocales == nil {
return "", nil
}
_, region = splitLocale(unixLocales[0])
return region, nil
}

@ -0,0 +1,101 @@
// +build windows
package locale
import (
"fmt"
"unsafe"
"golang.org/x/sys/windows"
)
// LocaleNameMaxLength is the maximum length of a locale name on Windows.
// See https://docs.microsoft.com/en-us/windows/win32/intl/locale-name-constants.
const LocaleNameMaxLength uint32 = 85
func getWindowsLocaleFromProc(syscall string) (string, error) {
dll, err := windows.LoadDLL("kernel32")
if err != nil {
return "", fmt.Errorf("could not find the kernel32 DLL: %v", err)
}
proc, err := dll.FindProc(syscall)
if err != nil {
return "", fmt.Errorf("could not find the %s proc in kernel32: %v", syscall, err)
}
buffer := make([]uint16, LocaleNameMaxLength)
// See https://docs.microsoft.com/en-us/windows/win32/api/winnls/nf-winnls-getuserdefaultlocalename
// and https://docs.microsoft.com/en-us/windows/win32/api/winnls/nf-winnls-getsystemdefaultlocalename
// GetUserDefaultLocaleName and GetSystemDefaultLocaleName both take a buffer and a buffer size,
// and return the length of the locale name (0 if not found).
ret, _, err := proc.Call(uintptr(unsafe.Pointer(&buffer[0])), uintptr(LocaleNameMaxLength))
if ret == 0 {
return "", fmt.Errorf("locale not found when calling %s: %v", syscall, err)
}
return windows.UTF16ToString(buffer), nil
}
func getWindowsLocale() (string, error) {
var (
locale string
err error
)
for _, proc := range [...]string{"GetUserDefaultLocaleName", "GetSystemDefaultLocaleName"} {
locale, err = getWindowsLocaleFromProc(proc)
if err == nil {
return locale, err
}
}
return locale, err
}
// GetLocale retrieves the IETF BCP 47 language tag set on the system.
func GetLocale() (string, error) {
locale, err := getWindowsLocale()
if err != nil {
return "", fmt.Errorf("cannot determine locale: %v", err)
}
return locale, err
}
// GetLocales retrieves the IETF BCP 47 language tags set on the system.
func GetLocales() ([]string, error) {
locale, err := GetLocale()
if err != nil {
return nil, err
}
return []string{locale}, nil
}
// GetLanguage retrieves the IETF BCP 47 language tag set on the system and
// returns the language part of the tag.
func GetLanguage() (string, error) {
language := ""
locale, err := GetLocale()
if err == nil {
language, _ = splitLocale(locale)
}
return language, err
}
// GetRegion retrieves the IETF BCP 47 language tag set on the system and
// returns the region part of the tag.
func GetRegion() (string, error) {
region := ""
locale, err := GetLocale()
if err == nil {
_, region = splitLocale(locale)
}
return region, err
}

@ -0,0 +1,27 @@
// +build !android
package locale
import (
"strings"
)
// SetRunOnJVM is a noop, this function is only valid on Android
func SetRunOnJVM(fn func(fn func(vm, env, ctx uintptr) error) error) {}
func splitLocale(locale string) (string, string) {
// Remove the encoding, if present
formattedLocale := strings.Split(locale, ".")[0]
// Normalize by replacing the hyphens with underscores
formattedLocale = strings.Replace(formattedLocale, "-", "_", -1)
// Split at the underscore
split := strings.Split(formattedLocale, "_")
language := split[0]
territory := ""
if len(split) > 1 {
territory = split[1]
}
return language, territory
}

@ -53,6 +53,9 @@ github.com/gopherjs/gopherwasm/js
# github.com/inconshreveable/mousetrap v1.0.0
## explicit
github.com/inconshreveable/mousetrap
# github.com/jeandeaual/go-locale v0.0.0-20210323163322-5cf4ff553a8d
## explicit; go 1.12
github.com/jeandeaual/go-locale
# github.com/maruel/panicparse v1.6.1
## explicit; go 1.11
github.com/maruel/panicparse/stack

Loading…
Cancel
Save