i18n: wires up translations for plugins (#102853)

* i18n: consolidate i18n types & runtime services

* Chore: updates after PR feedback

* Chore: updates after feedback

* Chore: updates after feedback

* Chore: adds feature toggle

* Chore: adds locale to backend

* Chore: adds locales to i18n instance

* Chore: fix missing path in CODEOWNERS

* Chore: fix go lint issues

* Chore: fix missing path in CODEOWNERS

* Chore: updates after PR feedback

* Trigger build

* Chore: updates after PR feedback

* Chore: use resolved language for lookup

* Chore: updates after PR feedback

* Update pkg/plugins/plugins.go

Co-authored-by: Will Browne <wbrowne@users.noreply.github.com>

* Chore: updates after PR feedback

* Chore: updates after PR feedback

---------

Co-authored-by: Will Browne <wbrowne@users.noreply.github.com>
This commit is contained in:
Hugo Häggmark
2025-03-31 06:38:38 +02:00
committed by GitHub
co-authored by Will Browne
parent 7ea0fab606
commit 18ae5d7f0c
29 changed files with 759 additions and 46 deletions
@@ -1977,7 +1977,7 @@ func TestGetDashboardUIDByID(t *testing.T) {
func TestUnstructuredToLegacyDashboard(t *testing.T) {
k8sCliMock := new(client.MockK8sHandler)
k8sCliMock.On("GetUsersFromMeta", mock.Anything, mock.Anything).Return(map[string]*user.User{"user:useruid": &user.User{ID: 10, UID: "useruid"}}, nil)
k8sCliMock.On("GetUsersFromMeta", mock.Anything, mock.Anything).Return(map[string]*user.User{"user:useruid": {ID: 10, UID: "useruid"}}, nil)
dr := &DashboardServiceImpl{
k8sclient: k8sCliMock,
}
@@ -73,7 +73,7 @@ func TestDashboardVersionService(t *testing.T) {
obj, err := utils.MetaAccessor(dash)
require.NoError(t, err)
obj.SetUpdatedTimestamp(&updatedTimestamp)
mockCli.On("GetUsersFromMeta", mock.Anything, []string{"user:1", ""}).Return(map[string]*user.User{"user:1": &user.User{ID: 1}}, nil)
mockCli.On("GetUsersFromMeta", mock.Anything, []string{"user:1", ""}).Return(map[string]*user.User{"user:1": {ID: 1}}, nil)
mockCli.On("List", mock.Anything, int64(1), mock.Anything).Return(&unstructured.UnstructuredList{
Items: []unstructured.Unstructured{*dash}}, nil).Once()
res, err := dashboardVersionService.Get(context.Background(), &dashver.GetDashboardVersionQuery{
+7
View File
@@ -1818,6 +1818,13 @@ var (
HideFromDocs: true,
Expression: "true", // enabled by default
},
{
Name: "localizationForPlugins",
Description: "Enables localization for plugins",
Stage: FeatureStageExperimental,
Owner: grafanaPluginsPlatformSquad,
FrontendOnly: false,
},
}
)
+1
View File
@@ -239,3 +239,4 @@ alertingMigrationUI,experimental,@grafana/alerting-squad,false,false,true
unifiedStorageHistoryPruner,experimental,@grafana/search-and-storage,false,false,false
unifiedStorageGrpcConnectionPool,experimental,@grafana/search-and-storage,false,false,false
alertingRuleRecoverDeleted,GA,@grafana/alerting-squad,false,false,true
localizationForPlugins,experimental,@grafana/plugins-platform-backend,false,false,false
1 Name Stage Owner requiresDevMode RequiresRestart FrontendOnly
239 unifiedStorageHistoryPruner experimental @grafana/search-and-storage false false false
240 unifiedStorageGrpcConnectionPool experimental @grafana/search-and-storage false false false
241 alertingRuleRecoverDeleted GA @grafana/alerting-squad false false true
242 localizationForPlugins experimental @grafana/plugins-platform-backend false false false
+4
View File
@@ -966,4 +966,8 @@ const (
// FlagAlertingRuleRecoverDeleted
// Enables the UI functionality to recover and view deleted alert rules
FlagAlertingRuleRecoverDeleted = "alertingRuleRecoverDeleted"
// FlagLocalizationForPlugins
// Enables localization for plugins
FlagLocalizationForPlugins = "localizationForPlugins"
)
+12
View File
@@ -2469,6 +2469,18 @@
"frontend": true
}
},
{
"metadata": {
"name": "localizationForPlugins",
"resourceVersion": "1742561476144",
"creationTimestamp": "2025-03-21T12:51:16Z"
},
"spec": {
"description": "Enables localization for plugins",
"stage": "experimental",
"codeowner": "@grafana/plugins-platform-backend"
}
},
{
"metadata": {
"name": "logQLScope",
@@ -44,7 +44,7 @@ func ProvideDiscoveryStage(cfg *config.PluginManagementCfg, pf finder.Finder, pr
func ProvideBootstrapStage(cfg *config.PluginManagementCfg, sc plugins.SignatureCalculator, a *assetpath.Service) *bootstrap.Bootstrap {
return bootstrap.New(cfg, bootstrap.Opts{
ConstructFunc: bootstrap.DefaultConstructFunc(sc, a),
ConstructFunc: bootstrap.DefaultConstructFunc(cfg, sc, a),
DecorateFuncs: bootstrap.DefaultDecorateFuncs(cfg),
})
}
@@ -34,6 +34,7 @@ func ProvidePluginManagementConfig(cfg *setting.Cfg, settingProvider setting.Pro
SkipHostEnvVarsEnabled: features.IsEnabledGlobally(featuremgmt.FlagPluginsSkipHostEnvVars),
SriChecksEnabled: features.IsEnabledGlobally(featuremgmt.FlagPluginsSriChecks),
PluginsCDNSyncLoaderEnabled: features.IsEnabledGlobally(featuremgmt.FlagPluginsCDNSyncLoader),
LocalizationForPlugins: features.IsEnabledGlobally(featuremgmt.FlagLocalizationForPlugins),
},
cfg.AngularSupportEnabled,
cfg.GrafanaComAPIURL,
@@ -35,6 +35,8 @@ type Plugin struct {
Angular plugins.AngularMeta
ExternalService *auth.ExternalService
Translations map[string]string
}
func (p Plugin) SupportsStreaming() bool {
@@ -76,6 +78,7 @@ func ToGrafanaDTO(p *plugins.Plugin) Plugin {
BaseURL: p.BaseURL,
ExternalService: p.ExternalService,
Angular: p.Angular,
Translations: p.Translations,
}
if p.Parent != nil {
@@ -0,0 +1,22 @@
package pluginstore
import (
"testing"
"github.com/grafana/grafana/pkg/plugins"
"github.com/stretchr/testify/require"
)
func TestToGrafanaDTO(t *testing.T) {
plugin := &plugins.Plugin{
Translations: map[string]string{
"en-US": "public/plugins/test-app/locales/en-US/test-app.json",
"pt-BR": "public/plugins/test-app/locales/pt-BR/test-app.json",
},
}
t.Run("Translations", func(t *testing.T) {
dto := ToGrafanaDTO(plugin)
require.Equal(t, plugin.Translations, dto.Translations)
})
}