Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
* Auto-collapse items after resize if the final size is less than `minSize` for that item;
* Prevent toggle buttons on `WorkspaceLayoutRow` children from being partially hidden when corresponding item is collapsed.
- Export `TranslationProvider` and `DefaultTranslation` to be able to use `useTranslation()` outside the workspace component:
* Export default (fallback) bundle for `en` language: `DefaultTranslationBundle`.
* Remove deprecated `Translation.formatIri()` method (use `DataLocaleProvider.formatIri()` instead).
- Extend `CommandBatch.discard()` to accept `revert` option to be able to revert the batch without storing it first.
- Always display ungroup buttons on `StandardGroup` when the element is single-selected.
Expand Down
3 changes: 2 additions & 1 deletion examples/i18n.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ function I18nExample() {
'toolbar_action': {
'layout.label': 'Layout the graph',
},
}
},
Reactodia.DefaultTranslationBundle,
],
}),
defaultLayout,
Expand Down
35 changes: 15 additions & 20 deletions src/diagram/locale.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,52 +8,47 @@ import {

import * as Rdf from '../data/rdf/rdfModel';

/**
* Default (fallback) translation bundle `en` language.
*
* @category Constants
*/
export const DefaultTranslationBundle: TranslationBundle = DefaultBundle;

/**
* Default built-in implementation for i18n strings interpolation and other
* methods from {@link Translation} interface.
*
* @category Core
*/
export class DefaultTranslation implements Translation {
export class DefaultTranslation<K extends string = TranslationKey> implements Translation<K> {
protected readonly bundles: ReadonlyArray<Partial<TranslationBundle>>;

private readonly _selectLabel: LabelLanguageSelector;

constructor(options?: {
/**
* Additional translation bundles for UI text strings in the workspace
* Translation bundles for UI text strings in the workspace
* in order from higher to lower priority.
*
* @default []
* @see {@link useDefaultTranslation}
* @see {@link DefaultTranslationBundle}
*/
bundles?: ReadonlyArray<Partial<TranslationBundle>>;
/**
* If set, disables translation fallback which (with default `en` language).
*
* @default true
* @see {@link translations}
*/
useDefaultBundle?: boolean;
/**
* Overrides how a single label gets selected from multiple of them based on target language.
*/
selectLabel?: LabelLanguageSelector;
}) {
const {
bundles = [],
useDefaultBundle = true,
selectLabel = defaultSelectLabel,
} = options ?? {};
const translationBundles: Partial<TranslationBundle>[] = [...bundles];
if (useDefaultBundle) {
translationBundles.push(DefaultTranslationBundle);
}
this.bundles = translationBundles;
this.bundles = bundles;
this._selectLabel = selectLabel;
}

private getString(key: TranslationKey): string | undefined {
private getString(key: K): string | undefined {
const dotIndex = key.indexOf('.');
if (!(dotIndex > 0 && dotIndex < key.length)) {
throw new Error(`Reactodia: Invalid translation key: ${key}`);
Expand All @@ -69,12 +64,12 @@ export class DefaultTranslation implements Translation {
return undefined;
}

text(key: TranslationKey, placeholders?: Record<string, string | number | boolean>): string {
text(key: K, placeholders?: Record<string, string | number | boolean>): string {
return this.textOptional(key, placeholders) ?? key;
}

textOptional(
key: TranslationKey,
key: K,
placeholders?: Record<string, string | number | boolean>
): string | undefined {
const template = this.getString(key);
Expand All @@ -84,7 +79,7 @@ export class DefaultTranslation implements Translation {
return formatPlaceholders(template, placeholders);
}

template(key: TranslationKey, parts: Record<string, React.ReactNode>): React.ReactNode {
template(key: K, parts: Record<string, React.ReactNode>): React.ReactNode {
const template = this.getString(key) ?? key;
return templatePlaceholders(template, parts);
}
Expand Down
2 changes: 1 addition & 1 deletion src/workspace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ export {
LinkVertices, type LinkVerticesProps,
} from './diagram/linkLayer';
export { DefaultLinkRouter, type DefaultLinkRouterOptions } from './diagram/linkRouter';
export { DefaultTranslation } from './diagram/locale';
export { DefaultTranslation, DefaultTranslationBundle } from './diagram/locale';
export { type DiagramModel, type DiagramModelEvents, type GraphStructure } from './diagram/model';
export { CanvasPlaceAt, type CanvasPlaceAtLayer } from './diagram/placeLayer';
export {
Expand Down
9 changes: 6 additions & 3 deletions src/workspace/workspaceProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { CommandHistory, InMemoryHistory } from '../diagram/history';
import {
CalculatedLayout, LayoutFunction, LayoutTypeProvider, calculateLayout, applyLayout,
} from '../diagram/layout';
import { DefaultTranslation } from '../diagram/locale';
import { DefaultTranslation, DefaultTranslationBundle } from '../diagram/locale';
import { RenameLinkToLinkStateProvider, SharedCanvasState } from '../diagram/sharedCanvasState';

import { AnnotationElement, AnnotationLink } from '../editor/annotationCells';
Expand Down Expand Up @@ -52,7 +52,8 @@ export interface CreateWorkspaceParams {
/**
* Overrides default i18n (translation) implementation.
*
* By default, {@link DefaultTranslation} instance is used.
* By default, {@link DefaultTranslation} instance with a single
* {@link DefaultTranslationBundle} is used.
*/
translation?: Translation;
/**
Expand Down Expand Up @@ -224,7 +225,9 @@ class RefCountedWorkspaceContext implements WorkspaceContext {

constructor(params: CreateWorkspaceParams) {
const {
translation = new DefaultTranslation(),
translation = new DefaultTranslation({
bundles: [DefaultTranslationBundle],
}),
history = new InMemoryHistory(),
dialogSettingsProvider = new DefaultDialogSettingsProvider(),
metadataProvider,
Expand Down
9 changes: 6 additions & 3 deletions src/workspace/workspaceWrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { TypeStyleResolver, RenameLinkProvider } from '../diagram/customization'
import { Element } from '../diagram/elements';
import { CommandHistory, InMemoryHistory } from '../diagram/history';
import { LayoutFunction } from '../diagram/layout';
import { DefaultTranslation } from '../diagram/locale';
import { DefaultTranslation, DefaultTranslationBundle } from '../diagram/locale';

import { EntityElement } from '../editor/dataElements';
import {
Expand Down Expand Up @@ -151,10 +151,13 @@ export class Workspace extends React.Component<WorkspaceProps> {
onWorkspaceEvent,
} = this.props;

let bundles = translations;
if (useDefaultTranslation) {
bundles = [...translations, DefaultTranslationBundle];
}
this._workspace = createWorkspace({
translation: this.context ?? new DefaultTranslation({
bundles: translations,
useDefaultBundle: useDefaultTranslation,
bundles,
selectLabel: selectLabelLanguage,
}),
history,
Expand Down
Loading