Skip to content

Commit 6d6a2a9

Browse files
authored
bdl requests to pass internationalized information (#3362)
1 parent bb20d36 commit 6d6a2a9

File tree

10 files changed

+206
-7
lines changed

10 files changed

+206
-7
lines changed

conf/core-services/i18n/i18n.yaml

+6
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ zh:
1414
Mem: ' 内存 '
1515
CPUQuotaIsLessThanRequest: '调整后的%s环境的 CPU 配额(%.3f 核)不得小于当前使用量(%.3f 核),请重新设置'
1616
MemQuotaIsLessThanRequest: '调整后的%s环境的内存配额(%.3f G)不得小于当前使用量(%.3f G),请重新设置'
17+
DeleteProjectErrorApplicationExist: '删除项目失败(项目中还存在应用)'
18+
FailedGetProject: "获取项目失败"
19+
FailedDeleteProject: "删除项目失败"
1720
en:
1821
AvailableIsLessThanQuota: The actual available resource on this workspace in the cluster is less than the quota. Please ask the Ops to allocate project resources reasonably
1922
NoResourceForTheWorkspace: No allocatable resources on this workspace in the cluster, please check the workspace labels for the nodes
@@ -30,3 +33,6 @@ en:
3033
Mem: ' Mem '
3134
CPUQuotaIsLessThanRequest: "The env %s's new CPU quota (%.3f Core) cannot be less than the actual request (%.3f Core), please reset it"
3235
MemQuotaIsLessThanRequest: "The env %s's new Mem quota (%.3f G) cannot be less than the actual request (%.3f G), please reset it"
36+
DeleteProjectErrorApplicationExist: 'failed to delete project(there exists applications)'
37+
FailedGetProject: "failed to get project"
38+
FailedDeleteProject: "failed to delete project"

go.mod

+1
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ require (
5252
github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32
5353
github.com/gin-gonic/gin v1.7.0
5454
github.com/go-echarts/go-echarts/v2 v2.2.4
55+
github.com/go-eden/routine v0.0.2
5556
github.com/go-openapi/loads v0.19.4
5657
github.com/go-openapi/spec v0.19.8
5758
github.com/go-openapi/strfmt v0.19.5

go.sum

+2-1
Original file line numberDiff line numberDiff line change
@@ -569,8 +569,9 @@ github.com/go-bindata/go-bindata/v3 v3.1.3/go.mod h1:1/zrpXsLD8YDIbhZRqXzm1Ghc7N
569569
github.com/go-chi/chi v4.0.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ=
570570
github.com/go-echarts/go-echarts/v2 v2.2.4 h1:SKJpdyNIyD65XjbUZjzg6SwccTNXEgmh+PlaO23g2H0=
571571
github.com/go-echarts/go-echarts/v2 v2.2.4/go.mod h1:6TOomEztzGDVDkOSCFBq3ed7xOYfbOqhaBzD0YV771A=
572-
github.com/go-eden/routine v0.0.1 h1:EFzGtHcxmv2gAcdoG7vMESe+26nuIl0/vTMtc030m/4=
573572
github.com/go-eden/routine v0.0.1/go.mod h1:R+sklWRKa0GPYXW5Opyr1nSb9KbwpEF9AXBARb7r1XI=
573+
github.com/go-eden/routine v0.0.2 h1:jcRSRZEKX0R1OqYqfbBRXxpaDxANUJn2m7liPe7KzQI=
574+
github.com/go-eden/routine v0.0.2/go.mod h1:R+sklWRKa0GPYXW5Opyr1nSb9KbwpEF9AXBARb7r1XI=
574575
github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w=
575576
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
576577
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=

modules/core-services/endpoints/project.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,7 @@ func (e *Endpoints) DeleteProject(ctx context.Context, r *http.Request, vars map
245245
orgIDStr := r.Header.Get(httputil.OrgHeader)
246246
orgID, err := strutil.Atoi64(orgIDStr)
247247
if err != nil {
248-
return apierrors.ErrUpdateProject.InvalidParameter(err).ToResp(), nil
248+
return apierrors.ErrDeleteProject.InvalidParameter(err).ToResp(), nil
249249
}
250250

251251
// 获取当前用户

modules/core-services/services/project/project.go

+5-3
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import (
3737
"github.com/erda-project/erda/modules/core-services/types"
3838
"github.com/erda-project/erda/pkg/crypto/uuid"
3939
"github.com/erda-project/erda/pkg/filehelper"
40+
local "github.com/erda-project/erda/pkg/i18n"
4041
"github.com/erda-project/erda/pkg/numeral"
4142
calcu "github.com/erda-project/erda/pkg/resourcecalculator"
4243
"github.com/erda-project/erda/pkg/ucauth"
@@ -637,14 +638,15 @@ func (p *Project) DeleteWithEvent(projectID int64) error {
637638

638639
// Delete 删除项目
639640
func (p *Project) Delete(projectID int64) (*model.Project, error) {
641+
langCodes, _ := i18n.ParseLanguageCode(local.GetGoroutineBindLang())
640642
// check if application exists
641643
if count, err := p.db.GetApplicationCountByProjectID(projectID); err != nil || count > 0 {
642-
return nil, errors.Errorf("failed to delete project(there exists applications)")
644+
return nil, errors.Errorf(p.trans.Text(langCodes, "DeleteProjectErrorApplicationExist"))
643645
}
644646

645647
project, err := p.db.GetProjectByID(projectID)
646648
if err != nil {
647-
return nil, errors.Errorf("failed to get project, (%v)", err)
649+
return nil, errors.Errorf(p.trans.Text(langCodes, "FailedGetProject")+"(%v)", err)
648650
}
649651

650652
// TODO We need to turn this check on after adding the delete portal to the UI
@@ -658,7 +660,7 @@ func (p *Project) Delete(projectID int64) (*model.Project, error) {
658660
// }
659661

660662
if err = p.db.DeleteProject(projectID); err != nil {
661-
return nil, errors.Errorf("failed to delete project, (%v)", err)
663+
return nil, errors.Errorf(p.trans.Text(langCodes, "FailedDeleteProject")+"(%v)", err)
662664
}
663665
_ = p.db.DeleteProjectQutoa(projectID)
664666
logrus.Infof("deleted project %d", projectID)

pkg/goroutine_context/context.go

+77
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
// Copyright (c) 2021 Terminus, Inc.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package goroutine_context
16+
17+
import (
18+
"context"
19+
"sync"
20+
21+
"github.com/go-eden/routine"
22+
)
23+
24+
const LocaleNameContextKey = "locale_name_context_key"
25+
26+
const bucketsSize = 128
27+
28+
type (
29+
contextBucket struct {
30+
lock sync.RWMutex
31+
data map[int64]context.Context
32+
}
33+
contextBuckets struct {
34+
buckets [bucketsSize]*contextBucket
35+
}
36+
)
37+
38+
var goroutineContext contextBuckets
39+
40+
func init() {
41+
for i := range goroutineContext.buckets {
42+
goroutineContext.buckets[i] = &contextBucket{
43+
data: make(map[int64]context.Context),
44+
}
45+
}
46+
}
47+
48+
// GetContext .
49+
func GetContext() context.Context {
50+
goid := routine.Goid()
51+
idx := goid % bucketsSize
52+
bucket := goroutineContext.buckets[idx]
53+
bucket.lock.RLock()
54+
ctx := bucket.data[goid]
55+
bucket.lock.RUnlock()
56+
return ctx
57+
}
58+
59+
// SetContext .
60+
func SetContext(ctx context.Context) {
61+
goid := routine.Goid()
62+
idx := goid % bucketsSize
63+
bucket := goroutineContext.buckets[idx]
64+
bucket.lock.Lock()
65+
defer bucket.lock.Unlock()
66+
bucket.data[goid] = ctx
67+
}
68+
69+
// ClearContext .
70+
func ClearContext() {
71+
goid := routine.Goid()
72+
idx := goid % bucketsSize
73+
bucket := goroutineContext.buckets[idx]
74+
bucket.lock.Lock()
75+
defer bucket.lock.Unlock()
76+
delete(bucket.data, goid)
77+
}

pkg/http/httpclient/request.go

+8
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import (
3232
"github.com/pkg/errors"
3333

3434
"github.com/erda-project/erda/pkg/http/customhttp"
35+
"github.com/erda-project/erda/pkg/i18n"
3536
"github.com/erda-project/erda/pkg/terminal/loading"
3637
)
3738

@@ -105,6 +106,13 @@ func (r *Request) Do() AfterDo {
105106
for k, v := range r.header {
106107
req.Header.Set(k, v)
107108
}
109+
110+
// get goroutine context il8n header to bdl request
111+
localeName := i18n.GetGoroutineBindLang()
112+
if localeName != "" {
113+
req.Header.Set(i18n.LangHeader, localeName)
114+
}
115+
108116
for _, v := range r.cookie {
109117
req.AddCookie(v)
110118
}

pkg/http/httpserver/server.go

+6
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import (
3232

3333
"github.com/erda-project/erda/apistructs"
3434
"github.com/erda-project/erda/pkg/crypto/uuid"
35+
"github.com/erda-project/erda/pkg/goroutine_context"
3536
"github.com/erda-project/erda/pkg/http/httpserver/ierror"
3637
"github.com/erda-project/erda/pkg/i18n"
3738
"github.com/erda-project/erda/pkg/strutil"
@@ -148,6 +149,11 @@ func (s *Server) internal(handler func(context.Context, *http.Request, map[strin
148149
locale = s.localeLoader.Locale(localeName)
149150
}
150151

152+
// set global context bind goroutine id
153+
i18n.SetGoroutineBindLang(localeName)
154+
// clear all global context
155+
defer goroutine_context.ClearContext()
156+
151157
// Manual decoding url var
152158
muxVars := mux.Vars(r)
153159
for k, v := range muxVars {

pkg/i18n/helper.go

+35-2
Original file line numberDiff line numberDiff line change
@@ -14,21 +14,54 @@
1414

1515
package i18n
1616

17-
import "net/http"
17+
import (
18+
"context"
19+
"net/http"
20+
21+
"github.com/erda-project/erda/pkg/goroutine_context"
22+
)
1823

1924
const ZH = "zh-CN"
2025
const EN = "en-US"
2126

27+
const LangHeader = "Lang"
28+
2229
// GetLocaleNameByRequest 从request获取语言名称
2330
func GetLocaleNameByRequest(request *http.Request) string {
2431
// 优先querystring 其次header
2532
lang := request.URL.Query().Get("lang")
2633
if lang != "" {
2734
return lang
2835
}
29-
lang = request.Header.Get("Lang")
36+
lang = request.Header.Get(LangHeader)
3037
if lang != "" {
3138
return lang
3239
}
3340
return ""
3441
}
42+
43+
func GetGoroutineBindLang() string {
44+
globalContext := goroutine_context.GetContext()
45+
if globalContext == nil {
46+
return ""
47+
}
48+
key := globalContext.Value(goroutine_context.LocaleNameContextKey)
49+
if key == nil {
50+
return ""
51+
}
52+
localeName, ok := key.(string)
53+
if !ok {
54+
return ""
55+
}
56+
57+
return localeName
58+
}
59+
60+
func SetGoroutineBindLang(localeName string) {
61+
ctx := goroutine_context.GetContext()
62+
if ctx == nil {
63+
ctx = context.Background()
64+
}
65+
66+
goroutine_context.SetContext(context.WithValue(ctx, goroutine_context.LocaleNameContextKey, localeName))
67+
}

pkg/i18n/helper_test.go

+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
// Copyright (c) 2021 Terminus, Inc.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package i18n
16+
17+
import "testing"
18+
19+
func TestSetGoroutineBindLang(t *testing.T) {
20+
type args struct {
21+
localeName string
22+
}
23+
tests := []struct {
24+
name string
25+
args args
26+
}{
27+
{
28+
name: "test",
29+
args: args{
30+
localeName: "test",
31+
},
32+
},
33+
}
34+
for _, tt := range tests {
35+
t.Run(tt.name, func(t *testing.T) {
36+
})
37+
}
38+
}
39+
40+
func TestGetGoroutineBindLang(t *testing.T) {
41+
tests := []struct {
42+
name string
43+
want string
44+
}{
45+
{
46+
name: "test",
47+
want: "test",
48+
},
49+
{
50+
name: "test",
51+
want: "",
52+
},
53+
}
54+
for _, tt := range tests {
55+
t.Run(tt.name, func(t *testing.T) {
56+
if tt.want != "" {
57+
SetGoroutineBindLang(tt.want)
58+
}
59+
60+
if got := GetGoroutineBindLang(); got != tt.want {
61+
t.Errorf("GetGoroutineBindLang() = %v, want %v", got, tt.want)
62+
}
63+
})
64+
}
65+
}

0 commit comments

Comments
 (0)