core-plugin-api: move TranslationResource from app-api + refactor
Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
@@ -14,4 +14,3 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
export * from './apis/implementations/AppTranslationApi';
|
||||
export * from './app/TranslationResource';
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* 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 {
|
||||
createTranslationResource,
|
||||
toInternalTranslationResource,
|
||||
} from './TranslationResource';
|
||||
import { countingTranslationRef } from './__fixtures__/refs';
|
||||
|
||||
describe('createTranslationResource', () => {
|
||||
it('should create a simple resource', async () => {
|
||||
const resource = createTranslationResource({
|
||||
ref: countingTranslationRef,
|
||||
translations: {
|
||||
sv: () =>
|
||||
Promise.resolve({
|
||||
default: {
|
||||
one: 'ett',
|
||||
two: 'två',
|
||||
three: 'tre',
|
||||
},
|
||||
}),
|
||||
},
|
||||
});
|
||||
expect(toInternalTranslationResource(resource)).toEqual({
|
||||
$$type: '@backstage/TranslationResource',
|
||||
version: 'v1',
|
||||
id: 'counting',
|
||||
resources: [
|
||||
{
|
||||
language: 'sv',
|
||||
loader: expect.any(Function),
|
||||
},
|
||||
],
|
||||
});
|
||||
await expect(
|
||||
toInternalTranslationResource(resource).resources[0].loader(),
|
||||
).resolves.toEqual({
|
||||
messages: {
|
||||
one: 'ett',
|
||||
two: 'två',
|
||||
three: 'tre',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should create a resource with lazy loaded messages', async () => {
|
||||
const resource = createTranslationResource({
|
||||
ref: countingTranslationRef,
|
||||
translations: {
|
||||
de: () => import('./__fixtures__/counting-de'),
|
||||
sv: () => import('./__fixtures__/counting-sv.json'),
|
||||
// @ts-expect-error
|
||||
deBad: () => import('./__fixtures__/fruits-de.json'),
|
||||
// @ts-expect-error
|
||||
svBad: () => import('./__fixtures__/fruits-sv'),
|
||||
},
|
||||
});
|
||||
expect(toInternalTranslationResource(resource)).toEqual({
|
||||
$$type: '@backstage/TranslationResource',
|
||||
version: 'v1',
|
||||
id: 'counting',
|
||||
resources: [
|
||||
{
|
||||
language: 'de',
|
||||
loader: expect.any(Function),
|
||||
},
|
||||
{
|
||||
language: 'sv',
|
||||
loader: expect.any(Function),
|
||||
},
|
||||
{
|
||||
language: 'deBad',
|
||||
loader: expect.any(Function),
|
||||
},
|
||||
{
|
||||
language: 'svBad',
|
||||
loader: expect.any(Function),
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
await expect(
|
||||
toInternalTranslationResource(resource).resources[0].loader(),
|
||||
).resolves.toEqual({
|
||||
messages: {
|
||||
one: 'eins',
|
||||
two: 'zwei',
|
||||
three: 'polizei',
|
||||
},
|
||||
});
|
||||
|
||||
await expect(
|
||||
toInternalTranslationResource(resource).resources[1].loader(),
|
||||
).resolves.toEqual({
|
||||
messages: {
|
||||
one: 'ett',
|
||||
two: 'två',
|
||||
three: 'tre',
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* 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 {
|
||||
TranslationMessages,
|
||||
TranslationRef,
|
||||
} from '@backstage/core-plugin-api/alpha';
|
||||
|
||||
/** @alpha */
|
||||
export interface TranslationResource<TId extends string = string> {
|
||||
$$type: '@backstage/TranslationResource';
|
||||
id: TId;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export interface InternalTranslationResource<TId extends string = string>
|
||||
extends TranslationResource<TId> {
|
||||
version: 'v1';
|
||||
resources: Array<{
|
||||
language: string;
|
||||
loader(): Promise<{ messages: TranslationMessages<TId> }>;
|
||||
}>;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function toInternalTranslationResource<TId extends string>(
|
||||
resource: TranslationResource<TId>,
|
||||
): InternalTranslationResource<TId> {
|
||||
const r = resource as InternalTranslationResource<TId>;
|
||||
if (r.$$type !== '@backstage/TranslationResource') {
|
||||
throw new Error(`Invalid translation resource, bad type '${r.$$type}'`);
|
||||
}
|
||||
if (r.version !== 'v1') {
|
||||
throw new Error(`Invalid translation resource, bad version '${r.version}'`);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/** @alpha */
|
||||
export interface TranslationResourceOptions<
|
||||
TId extends string,
|
||||
TMessages extends { [key in string]: string },
|
||||
TTranslations extends {
|
||||
[language in string]: () => Promise<{
|
||||
default:
|
||||
| TranslationMessages<TId>
|
||||
| { [key in keyof TMessages]: string | null };
|
||||
}>;
|
||||
},
|
||||
> {
|
||||
ref: TranslationRef<TId, TMessages>;
|
||||
|
||||
translations: TTranslations;
|
||||
}
|
||||
|
||||
/** @alpha */
|
||||
export function createTranslationResource<
|
||||
TId extends string,
|
||||
TMessages extends { [key in string]: string },
|
||||
TTranslations extends {
|
||||
[language in string]: () => Promise<{
|
||||
default:
|
||||
| TranslationMessages<TId>
|
||||
| { [key in keyof TMessages]: string | null };
|
||||
}>;
|
||||
},
|
||||
>(
|
||||
options: TranslationResourceOptions<TId, TMessages, TTranslations>,
|
||||
): TranslationResource<TId> {
|
||||
return {
|
||||
$$type: '@backstage/TranslationResource',
|
||||
version: 'v1',
|
||||
id: options.ref.id,
|
||||
resources: Object.entries(options.translations).map(
|
||||
([language, loader]) => ({
|
||||
language,
|
||||
loader: () =>
|
||||
loader().then(m => {
|
||||
const value = m.default;
|
||||
return {
|
||||
messages:
|
||||
value?.$$type === '@backstage/TranslationMessages'
|
||||
? value.messages
|
||||
: value,
|
||||
};
|
||||
}),
|
||||
}),
|
||||
),
|
||||
} as InternalTranslationResource<TId>;
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* 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 { createTranslationMessages } from '../TranslationMessages';
|
||||
import { countingTranslationRef } from './refs';
|
||||
|
||||
export default createTranslationMessages({
|
||||
ref: countingTranslationRef,
|
||||
messages: {
|
||||
one: 'eins',
|
||||
two: 'zwei',
|
||||
three: 'polizei',
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"one": "ett",
|
||||
"two": "två",
|
||||
"three": "tre"
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"apple": "apfel",
|
||||
"orange": "apfelsine"
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* 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 { createTranslationMessages } from '../TranslationMessages';
|
||||
import { fruitsTranslationRef } from './refs';
|
||||
|
||||
export default createTranslationMessages({
|
||||
ref: fruitsTranslationRef,
|
||||
messages: {
|
||||
apple: 'äpple',
|
||||
orange: 'apelsin',
|
||||
},
|
||||
});
|
||||
+19
-16
@@ -14,21 +14,24 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { TranslationRef } from '@backstage/core-plugin-api/alpha';
|
||||
import { createTranslationRef } from '../TranslationRef';
|
||||
|
||||
/** @alpha */
|
||||
export type TranslationMessages<T> = T extends TranslationRef<infer R>
|
||||
? Partial<R>
|
||||
: never;
|
||||
export const countingTranslationRef = createTranslationRef({
|
||||
id: 'counting',
|
||||
messages: {
|
||||
one: 'one',
|
||||
two: 'two',
|
||||
three: 'three',
|
||||
},
|
||||
});
|
||||
|
||||
/** @alpha */
|
||||
export function createTranslationResource<T extends TranslationRef>(options: {
|
||||
ref: T;
|
||||
messages?: Record<string, TranslationMessages<T>>;
|
||||
lazyMessages: Record<
|
||||
string,
|
||||
() => Promise<{ messages: TranslationMessages<T> }>
|
||||
>;
|
||||
}) {
|
||||
return options;
|
||||
}
|
||||
export const fruitsTranslationRef = createTranslationRef({
|
||||
id: 'fruits',
|
||||
messages: {
|
||||
apple: 'apple',
|
||||
orange: 'orange',
|
||||
},
|
||||
translations: {
|
||||
de: () => import('./fruits-de.json'),
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user