frontend-plugin-api: add createTranslationExtension
Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/frontend-app-api': patch
|
||||
---
|
||||
|
||||
Add support for translation extensions.
|
||||
@@ -18,6 +18,7 @@ import {
|
||||
coreExtensionData,
|
||||
createExtension,
|
||||
createExtensionInput,
|
||||
createTranslationExtension,
|
||||
} from '@backstage/frontend-plugin-api';
|
||||
|
||||
export const Core = createExtension({
|
||||
@@ -33,6 +34,9 @@ export const Core = createExtension({
|
||||
components: createExtensionInput({
|
||||
component: coreExtensionData.component,
|
||||
}),
|
||||
translations: createExtensionInput({
|
||||
translation: createTranslationExtension.translationDataRef,
|
||||
}),
|
||||
root: createExtensionInput(
|
||||
{
|
||||
element: coreExtensionData.reactElement,
|
||||
|
||||
@@ -23,6 +23,7 @@ import {
|
||||
ComponentRef,
|
||||
componentsApiRef,
|
||||
coreExtensionData,
|
||||
createTranslationExtension,
|
||||
ExtensionDataRef,
|
||||
ExtensionOverrides,
|
||||
RouteRef,
|
||||
@@ -415,6 +416,16 @@ function createApiHolder(
|
||||
?.map(e => e.instance?.getData(coreExtensionData.theme))
|
||||
.filter((x): x is AppTheme => !!x) ?? [];
|
||||
|
||||
const translationResources =
|
||||
tree.root.edges.attachments
|
||||
.get('translations')
|
||||
?.map(e =>
|
||||
e.instance?.getData(createTranslationExtension.translationDataRef),
|
||||
)
|
||||
.filter(
|
||||
(x): x is typeof createTranslationExtension.translationDataRef.T => !!x,
|
||||
) ?? [];
|
||||
|
||||
for (const factory of [...defaultApis, ...pluginApis]) {
|
||||
factoryRegistry.register('default', factory);
|
||||
}
|
||||
@@ -471,15 +482,6 @@ function createApiHolder(
|
||||
factory: () => AppLanguageSelector.createWithStorage(),
|
||||
});
|
||||
|
||||
factoryRegistry.register('default', {
|
||||
api: translationApiRef,
|
||||
deps: { languageApi: appLanguageApiRef },
|
||||
factory: ({ languageApi }) =>
|
||||
I18nextTranslationApi.create({
|
||||
languageApi,
|
||||
}),
|
||||
});
|
||||
|
||||
factoryRegistry.register('static', {
|
||||
api: configApiRef,
|
||||
deps: {},
|
||||
@@ -492,12 +494,13 @@ function createApiHolder(
|
||||
factory: () => AppLanguageSelector.createWithStorage(),
|
||||
});
|
||||
|
||||
factoryRegistry.register('default', {
|
||||
factoryRegistry.register('static', {
|
||||
api: translationApiRef,
|
||||
deps: { languageApi: appLanguageApiRef },
|
||||
factory: ({ languageApi }) =>
|
||||
I18nextTranslationApi.create({
|
||||
languageApi,
|
||||
resources: translationResources,
|
||||
}),
|
||||
});
|
||||
|
||||
|
||||
@@ -74,6 +74,8 @@ import { SignInPageProps } from '@backstage/core-plugin-api';
|
||||
import { StorageApi } from '@backstage/core-plugin-api';
|
||||
import { storageApiRef } from '@backstage/core-plugin-api';
|
||||
import { StorageValueSnapshot } from '@backstage/core-plugin-api';
|
||||
import { TranslationMessages } from '@backstage/core-plugin-api/alpha';
|
||||
import { TranslationResource } from '@backstage/core-plugin-api/alpha';
|
||||
import { TypesToApiRefs } from '@backstage/core-plugin-api';
|
||||
import { useApi } from '@backstage/core-plugin-api';
|
||||
import { useApiHolder } from '@backstage/core-plugin-api';
|
||||
@@ -628,6 +630,28 @@ export function createThemeExtension(
|
||||
theme: AppTheme,
|
||||
): ExtensionDefinition<never>;
|
||||
|
||||
// @public (undocumented)
|
||||
export function createTranslationExtension(options: {
|
||||
name?: string;
|
||||
resource: TranslationResource | TranslationMessages;
|
||||
}): ExtensionDefinition<never>;
|
||||
|
||||
// @public (undocumented)
|
||||
export namespace createTranslationExtension {
|
||||
const // (undocumented)
|
||||
translationDataRef: ConfigurableExtensionDataRef<
|
||||
| TranslationResource<string>
|
||||
| TranslationMessages<
|
||||
string,
|
||||
{
|
||||
[x: string]: string;
|
||||
},
|
||||
boolean
|
||||
>,
|
||||
{}
|
||||
>;
|
||||
}
|
||||
|
||||
export { DiscoveryApi };
|
||||
|
||||
export { discoveryApiRef };
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright 2023 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {
|
||||
createTranslationRef,
|
||||
createTranslationMessages,
|
||||
createTranslationResource,
|
||||
} from '@backstage/core-plugin-api/alpha';
|
||||
import { createTranslationExtension } from './createTranslationExtension';
|
||||
|
||||
const translationRef = createTranslationRef({
|
||||
id: 'test',
|
||||
messages: {
|
||||
a: 'a',
|
||||
b: 'b',
|
||||
},
|
||||
});
|
||||
|
||||
describe('createTranslationExtension', () => {
|
||||
it('creates a translation message extension', () => {
|
||||
const messages = createTranslationMessages({
|
||||
ref: translationRef,
|
||||
messages: {
|
||||
a: 'A',
|
||||
},
|
||||
});
|
||||
const extension = createTranslationExtension({ resource: messages });
|
||||
|
||||
expect(extension).toEqual({
|
||||
$$type: '@backstage/ExtensionDefinition',
|
||||
kind: 'translation',
|
||||
namespace: 'test',
|
||||
attachTo: { id: 'core', input: 'translations' },
|
||||
disabled: false,
|
||||
inputs: {},
|
||||
output: {
|
||||
resource: createTranslationExtension.translationDataRef,
|
||||
},
|
||||
factory: expect.any(Function),
|
||||
});
|
||||
|
||||
expect(extension.factory({} as any)).toEqual({
|
||||
resource: messages,
|
||||
});
|
||||
});
|
||||
|
||||
it('creates a translation resource extension', () => {
|
||||
const resource = createTranslationResource({
|
||||
ref: translationRef,
|
||||
translations: {
|
||||
sv: () =>
|
||||
Promise.resolve({
|
||||
default: createTranslationMessages({
|
||||
ref: translationRef,
|
||||
messages: {
|
||||
a: 'Ä',
|
||||
b: 'Ö',
|
||||
},
|
||||
}),
|
||||
}),
|
||||
},
|
||||
});
|
||||
const extension = createTranslationExtension({ resource });
|
||||
|
||||
expect(extension).toEqual({
|
||||
$$type: '@backstage/ExtensionDefinition',
|
||||
kind: 'translation',
|
||||
namespace: 'test',
|
||||
attachTo: { id: 'core', input: 'translations' },
|
||||
disabled: false,
|
||||
inputs: {},
|
||||
output: {
|
||||
resource: createTranslationExtension.translationDataRef,
|
||||
},
|
||||
factory: expect.any(Function),
|
||||
});
|
||||
|
||||
expect(extension.factory({} as any)).toEqual({ resource });
|
||||
});
|
||||
|
||||
it('creates a translation resource extension with a name', () => {
|
||||
expect(
|
||||
createTranslationExtension({
|
||||
name: 'sv',
|
||||
resource: createTranslationResource({
|
||||
ref: translationRef,
|
||||
translations: {
|
||||
sv: () =>
|
||||
Promise.resolve({
|
||||
default: createTranslationMessages({
|
||||
ref: translationRef,
|
||||
messages: {
|
||||
a: 'Ä',
|
||||
b: 'Ö',
|
||||
},
|
||||
}),
|
||||
}),
|
||||
},
|
||||
}),
|
||||
}),
|
||||
).toEqual({
|
||||
$$type: '@backstage/ExtensionDefinition',
|
||||
kind: 'translation',
|
||||
namespace: 'test',
|
||||
name: 'sv',
|
||||
attachTo: { id: 'core', input: 'translations' },
|
||||
disabled: false,
|
||||
inputs: {},
|
||||
output: {
|
||||
resource: createTranslationExtension.translationDataRef,
|
||||
},
|
||||
factory: expect.any(Function),
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2023 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { createExtension, createExtensionDataRef } from '../wiring';
|
||||
import {
|
||||
TranslationResource,
|
||||
TranslationMessages,
|
||||
} from '@backstage/core-plugin-api/alpha';
|
||||
|
||||
/** @public */
|
||||
export function createTranslationExtension(options: {
|
||||
name?: string;
|
||||
resource: TranslationResource | TranslationMessages;
|
||||
}) {
|
||||
return createExtension({
|
||||
kind: 'translation',
|
||||
namespace: options.resource.id,
|
||||
name: options.name,
|
||||
attachTo: { id: 'core', input: 'translations' },
|
||||
output: {
|
||||
resource: createTranslationExtension.translationDataRef,
|
||||
},
|
||||
factory: () => ({ resource: options.resource }),
|
||||
});
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export namespace createTranslationExtension {
|
||||
export const translationDataRef = createExtensionDataRef<
|
||||
TranslationResource | TranslationMessages
|
||||
>('core.translationResource');
|
||||
}
|
||||
@@ -20,3 +20,4 @@ export { createNavItemExtension } from './createNavItemExtension';
|
||||
export { createSignInPageExtension } from './createSignInPageExtension';
|
||||
export { createThemeExtension } from './createThemeExtension';
|
||||
export { createComponentExtension } from './createComponentExtension';
|
||||
export { createTranslationExtension } from './createTranslationExtension';
|
||||
|
||||
Reference in New Issue
Block a user