core-plugin-api: additional translation ref refactor

Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
Patrik Oldsberg
2023-09-12 11:19:52 +02:00
parent a75247a722
commit 2fcadae9df
2 changed files with 92 additions and 50 deletions
@@ -17,39 +17,57 @@ import {
createTranslationRef,
toInternalTranslationRef,
} from './TranslationRef';
import { toInternalTranslationResource } from './TranslationResource';
describe('TranslationRefImpl', () => {
it('should create a TranslationRef instance using the factory function', () => {
const config = {
id: 'testId',
const ref = createTranslationRef({
id: 'test',
messages: { key: 'value' },
};
});
const translationRef = toInternalTranslationRef(
createTranslationRef(config),
);
const internalRef = toInternalTranslationRef(ref);
expect(translationRef.id).toBe('testId');
expect(translationRef.getDefaultMessages()).toEqual({ key: 'value' });
expect(internalRef.$$type).toBe('@backstage/TranslationRef');
expect(internalRef.version).toBe('v1');
expect(internalRef.id).toBe('test');
expect(internalRef.getDefaultMessages()).toEqual({ key: 'value' });
});
it('should get lazy resources', async () => {
const config = {
id: 'testId',
it('should be created with lazy translations', async () => {
const ref = createTranslationRef({
id: 'test',
messages: { key: 'value' },
lazyResources: {
en: () => Promise.resolve({ messages: { key: 'value' } }),
translations: {
de: () => Promise.resolve({ default: { key: 'other-value' } }),
},
};
});
const translationRef = toInternalTranslationRef(
createTranslationRef(config),
const internalRef = toInternalTranslationRef(ref);
expect(internalRef.$$type).toBe('@backstage/TranslationRef');
expect(internalRef.version).toBe('v1');
expect(internalRef.id).toBe('test');
expect(internalRef.getDefaultMessages()).toEqual({ key: 'value' });
const internalResource = toInternalTranslationResource(
internalRef.getDefaultResource()!,
);
const lazyResources = translationRef.getLazyResources();
const messages = await lazyResources?.en();
expect(messages).toEqual({ messages: { key: 'value' } });
expect(internalResource).toEqual({
$$type: '@backstage/TranslationResource',
version: 'v1',
id: 'test',
resources: [
{
language: 'de',
loader: expect.any(Function),
},
],
});
await expect(internalResource.resources[0].loader()).resolves.toEqual({
messages: {
key: 'other-value',
},
});
});
});
@@ -14,10 +14,15 @@
* limitations under the License.
*/
import {
createTranslationResource,
TranslationResource,
} from './TranslationResource';
/** @alpha */
export interface TranslationRef<
TMessages extends { [key in string]: string } = { [key in string]: string },
TId extends string = string,
TMessages extends { [key in string]: string } = { [key in string]: string },
> {
$$type: '@backstage/TranslationRef';
@@ -31,47 +36,54 @@ type AnyMessages = { [key in string]: string };
/** @internal */
export interface InternalTranslationRef<
TMessages extends { [key in string]: string } = { [key in string]: string },
TId extends string = string,
> extends TranslationRef<TMessages, TId> {
TMessages extends { [key in string]: string } = { [key in string]: string },
> extends TranslationRef<TId, TMessages> {
version: 'v1';
getDefaultMessages(): AnyMessages;
getResources(): Record<string, AnyMessages> | undefined;
getLazyResources():
| Record<string, () => Promise<{ messages: AnyMessages }>>
| undefined;
getDefaultResource(): TranslationResource | undefined;
}
export type NoInfer<T> = T extends infer S ? S : never;
/** @alpha */
export interface TranslationRefOptions<
TId extends string,
TMessages extends { [key in string]: string },
TId extends string = string,
TTranslations extends {
[language in string]: () => Promise<{
default: { [key in keyof TMessages]: string | null };
}>;
},
> {
id: TId;
messages: TMessages;
lazyResources?: Record<string, () => Promise<{ messages: TMessages }>>;
resources?: Record<string, TMessages>;
translations?: TTranslations;
}
/** @internal */
class TranslationRefImpl<
TId extends string,
TMessages extends { [key in string]: string },
TId extends string = string,
> implements InternalTranslationRef<TMessages, TId>
> implements InternalTranslationRef<TId, TMessages>
{
constructor(
private readonly options: TranslationRefOptions<TMessages, TId>,
) {}
#id: TId;
#messages: TMessages;
#resources: TranslationResource | undefined;
constructor(options: TranslationRefOptions<TId, TMessages, any>) {
this.#id = options.id;
this.#messages = options.messages;
}
$$type = '@backstage/TranslationRef' as const;
version = 'v1' as const;
get id(): TId {
return this.options.id;
return this.#id;
}
get T(): never {
@@ -79,17 +91,15 @@ class TranslationRefImpl<
}
getDefaultMessages(): AnyMessages {
return this.options.messages;
return this.#messages;
}
getLazyResources():
| Record<string, () => Promise<{ messages: AnyMessages }>>
| undefined {
return this.options.lazyResources;
setDefaultResource(resources: TranslationResource): void {
this.#resources = resources;
}
getResources(): Record<string, AnyMessages> | undefined {
return this.options.resources;
getDefaultResource(): TranslationResource | undefined {
return this.#resources;
}
toString() {
@@ -99,12 +109,26 @@ class TranslationRefImpl<
/** @alpha */
export function createTranslationRef<
TId extends string,
TMessages extends { [key in string]: string },
TId extends string = string,
TTranslations extends {
[language in string]: () => Promise<{
default: { [key in keyof TMessages]: string | null };
}>;
},
>(
config: TranslationRefOptions<TMessages, TId>,
): TranslationRef<TMessages, TId> {
return new TranslationRefImpl(config);
config: TranslationRefOptions<TId, TMessages, TTranslations>,
): TranslationRef<TId, TMessages> {
const ref = new TranslationRefImpl(config);
if (config.translations) {
ref.setDefaultResource(
createTranslationResource({
ref,
translations: config.translations as any,
}),
);
}
return ref;
}
/** @internal */