Skip to content

Commit

Permalink
feat: Set base language input to default value TG-368
Browse files Browse the repository at this point in the history
- When default value is provided and base translation for key is not stored, base language translation input in UI has the default value set
- Updated readmes to contain links to twitter
  • Loading branch information
JanCizmar committed Oct 26, 2021
1 parent 6c31124 commit 5f66114
Show file tree
Hide file tree
Showing 16 changed files with 157 additions and 34 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
![@tolgee/ui version](https://img.shields.io/npm/v/@tolgee/ui?label=%40tolgee%2Fui)
![types typescript](https://img.shields.io/badge/Types-Typescript-blue)
![licence](https://img.shields.io/github/license/tolgee/tolgee-js)
![twitter](https://img.shields.io/twitter/follow/Tolgee_i18n?style=social)
[![twitter](https://img.shields.io/twitter/follow/Tolgee_i18n?style=social)](https://twitter.com/Tolgee_i18n)
[![github stars](https://img.shields.io/github/stars/tolgee/tolgee-js?style=social)](https://github.com/tolgee/tolgee-js)

# Tolgee JS
Expand Down
36 changes: 36 additions & 0 deletions e2e/cypress/integration/react/base.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,40 @@ context('Base test', () => {
it('shows key as default when default not provided ', () => {
cy.contains('unknown key').should('be.visible');
});

it('opens key context menu when multiple keys are in one element', () => {
cy.get('.multiple-keys')
.should('be.visible')
.should('contain', 'First one')
.trigger('keydown', { key: 'Alt' })
.trigger('mouseover')
.click();

cy.get('#__tolgee_dev_tools')
.find('li')
.should('have.length', 3)
.should('contain', 'key')
.should('contain', 'key 2')
.should('contain', 'key 3');

cy.get('#__tolgee_dev_tools').find('li').contains('key 2').click();
cy.get('#__tolgee_dev_tools').should('contain', 'Quick translation');
cy.get('#__tolgee_dev_tools')
.find('textarea')
.should('contain', 'Second one');
});

it.only('opens dialog when element contains same key multiple times', () => {
cy.get('.same-key-multiple')
.should('be.visible')
.should('contain', 'First one')
.trigger('keydown', { key: 'Alt' })
.trigger('mouseover')
.click();

cy.get('#__tolgee_dev_tools').should('contain', 'Quick translation');
cy.get('#__tolgee_dev_tools')
.find('textarea')
.should('contain', 'First one');
});
});
2 changes: 1 addition & 1 deletion packages/core/README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
![test workflow](https://github.com/tolgee/tolgee-js/actions/workflows/test.yml/badge.svg)
![@tolgee/core version](https://img.shields.io/npm/v/@tolgee/core?label=%40tolgee%2Fcore)
![types typescript](https://img.shields.io/badge/Types-Typescript-blue)
![twitter](https://img.shields.io/twitter/follow/Tolgee_i18n?style=social)
[![twitter](https://img.shields.io/twitter/follow/Tolgee_i18n?style=social)](https://twitter.com/Tolgee_i18n)
[![github stars](https://img.shields.io/github/stars/tolgee/tolgee-js?style=social)](https://github.com/tolgee/tolgee-js)

# Tolgee core library
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/__testFixtures/createElement.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export const createElement = (
keys.push({
key: `key${sameKeys ? `` : ` ${keyNum++}`}`,
params: { a: 'aaa' },
defaultValue: 'default value',
});
}
node._tolgee = {
Expand Down
2 changes: 2 additions & 0 deletions packages/core/src/handlers/WrappedHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ export class WrappedHandler extends AbstractHandler {
elementWithMeta._tolgee.wrappedWithElementOnlyKey = element.getAttribute(
TOLGEE_WRAPPED_ONLY_DATA_ATTRIBUTE
);
elementWithMeta._tolgee.wrappedWithElementOnlyDefaultHtml =
element.innerHTML;
this.elementRegistrar.register(elementWithMeta);
});
}
Expand Down
1 change: 0 additions & 1 deletion packages/core/src/highlighter/MouseEventHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ export class MouseEventHandler {
private keysDown = new Set<ModifierKey>();
private mouseOn: Set<ElementWithMeta> = new Set();
private highlighted: ElementWithMeta;
private highlightedInitialBackgroundColor: string;
private mouseOnChanged = new EventEmitterImpl<ElementWithMeta>();
private keysChanged: EventEmitterImpl<boolean> =
new EventEmitterImpl<boolean>();
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/highlighter/TranslationHighlighter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ describe('TranslationHighlighter', () => {
await savedCallback(openEvent);

expect(rendererViewerMock).toBeCalledTimes(1);
expect(rendererViewerMock).toBeCalledWith('key');
expect(rendererViewerMock).toBeCalledWith('key', 'default value');
});

test('will open translation dialog when single key multiplied', async () => {
Expand All @@ -52,7 +52,7 @@ describe('TranslationHighlighter', () => {
await savedCallback(openEvent);

expect(rendererViewerMock).toBeCalledTimes(1);
expect(rendererViewerMock).toBeCalledWith('key');
expect(rendererViewerMock).toBeCalledWith('key', 'default value');
});
});

Expand Down
53 changes: 39 additions & 14 deletions packages/core/src/highlighter/TranslationHighlighter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@ import { ElementWithMeta } from '../types';
import { PluginManager } from '../toolsManager/PluginManager';
import { DependencyStore } from '../services/DependencyStore';

type KeyWithDefault = { key: string; defaultValue?: string };

export class TranslationHighlighter {
public pluginManager: PluginManager;

constructor(private dependencies: DependencyStore) {}

private _renderer: any;
Expand All @@ -19,13 +22,18 @@ export class TranslationHighlighter {
return this._renderer;
}

private static getKeyOptions(node: ElementWithMeta): Set<string> {
private static getKeyOptions(node: ElementWithMeta): KeyWithDefault[] {
const nodes = Array.from(node._tolgee.nodes);
const keys = nodes.reduce(
(acc, curr) => [...acc, ...curr._tolgee.keys.map((k) => k.key)],
return nodes.reduce(
(acc, curr) => [
...acc,
...curr._tolgee.keys.map((k) => ({
key: k.key,
defaultValue: k.defaultValue,
})),
],
[]
);
return new Set(keys);
}

listen(element: ElementWithMeta & ElementCSSInlineStyle) {
Expand All @@ -36,29 +44,46 @@ export class TranslationHighlighter {
);
}

private async getKey(
private async getKeyAndDefault(
mouseEvent: MouseEvent,
element: ElementWithMeta
): Promise<string> {
): Promise<KeyWithDefault> {
if (element._tolgee.wrappedWithElementOnlyKey) {
return element._tolgee.wrappedWithElementOnlyKey;
return {
key: element._tolgee.wrappedWithElementOnlyKey,
defaultValue: element._tolgee.wrappedWithElementOnlyDefaultHtml,
};
}
const keys = TranslationHighlighter.getKeyOptions(element);
if (keys.size > 1) {
return await this.renderer.getKey({ keys: keys, openEvent: mouseEvent });
const keysWithDefaults = TranslationHighlighter.getKeyOptions(element);

// create Set to remove duplicated key values
const keySet = new Set(
keysWithDefaults.map((keyWithDefault) => keyWithDefault.key)
);
if (keySet.size > 1) {
// this opens the popover where user chooses the key
const selectedKey = await this.renderer.getKey({
keys: keySet,
openEvent: mouseEvent,
});
// get the key with default
const found = keysWithDefaults.find((kwd) => kwd.key === selectedKey);
if (found) {
return found;
}
}
if (keys.size === 1) {
return Array.from(keys)[0];
if (keySet.size === 1) {
return keysWithDefaults[0];
}
// eslint-disable-next-line no-console
console.error('No key to translate. This seems like a bug in tolgee.');
}

private translationEdit = async (e: MouseEvent, element: ElementWithMeta) => {
if (typeof this.renderer === 'object') {
const key = await this.getKey(e, element);
const key = await this.getKeyAndDefault(e, element);
if (key) {
this.renderer.renderViewer(key);
this.renderer.renderViewer(key.key, key.defaultValue);
return;
}
return;
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ export type ElementWithMeta = Element &

export type ElementMeta = {
wrappedWithElementOnlyKey?: string;
wrappedWithElementOnlyDefaultHtml?: string;
nodes: Set<NodeWithMeta>;
listeningForHighlighting?: boolean;
removeAllEventListeners?: () => void;
Expand Down
2 changes: 1 addition & 1 deletion packages/ngx/projects/ngx-tolgee/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
![@tolgee/ngx version](https://img.shields.io/npm/v/@tolgee/ngx?label=%40tolgee%2Fngx)
![types typescript](https://img.shields.io/badge/Types-Typescript-blue)
![licence](https://img.shields.io/github/license/tolgee/tolgee-js)
![twitter](https://img.shields.io/twitter/follow/Tolgee_i18n?style=social)
[![twitter](https://img.shields.io/twitter/follow/Tolgee_i18n?style=social)](https://twitter.com/Tolgee_i18n)
[![github stars](https://img.shields.io/github/stars/tolgee/tolgee-js?style=social)](https://github.com/tolgee/tolgee-js)

# Tolgee for Angular
Expand Down
2 changes: 1 addition & 1 deletion packages/react/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
![@tolgee/react version](https://img.shields.io/npm/v/@tolgee/react?label=%40tolgee%2Freact)
![types typescript](https://img.shields.io/badge/Types-Typescript-blue)
![licence](https://img.shields.io/github/license/tolgee/tolgee-js)
![twitter](https://img.shields.io/twitter/follow/Tolgee_i18n?style=social)
[![twitter](https://img.shields.io/twitter/follow/Tolgee_i18n?style=social)](https://twitter.com/Tolgee_i18n)
[![github stars](https://img.shields.io/github/stars/tolgee/tolgee-js?style=social)](https://github.com/tolgee/tolgee-js)

# Tolgee for React
Expand Down
2 changes: 1 addition & 1 deletion packages/ui/README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
![test workflow](https://github.com/tolgee/tolgee-js/actions/workflows/test.yml/badge.svg)
![@tolgee/ui version](https://img.shields.io/npm/v/@tolgee/ui?label=%40tolgee%2Fui)
![types typescript](https://img.shields.io/badge/Types-Typescript-blue)
![twitter](https://img.shields.io/twitter/follow/Tolgee_i18n?style=social)
[![twitter](https://img.shields.io/twitter/follow/Tolgee_i18n?style=social)](https://twitter.com/Tolgee_i18n)
[![github stars](https://img.shields.io/github/stars/tolgee/tolgee-js?style=social)](https://github.com/tolgee/tolgee-js)

# Tolgee JS UI library
Expand Down
11 changes: 7 additions & 4 deletions packages/ui/src/KeyDialog/KeyDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,21 @@ export type Props = {

export class KeyDialog extends React.Component<Props> {
state = {
translationInput: null,
key: null,
defaultValue: undefined,
dialogOpened: false,
};

constructor(props: Props) {
super(props);
}

public translationEdit(input) {
public translationEdit(key: string, defaultValue?: string) {
this.setState({
...this.state,
dialogOpened: true,
translationInput: input,
defaultValue: defaultValue,
key: key,
});
}

Expand All @@ -33,8 +35,9 @@ export class KeyDialog extends React.Component<Props> {
<BodyEnd>
<TranslationDialogContextProvider
dependencies={this.props.dependencies}
defaultValue={this.state.defaultValue}
open={this.state.dialogOpened}
input={this.state.translationInput}
input={this.state.key}
onClose={this.onClose}
>
<TranslationDialog />
Expand Down
39 changes: 35 additions & 4 deletions packages/ui/src/KeyDialog/TranslationDialogContextProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ interface TranslationInterface {

type DialogProps = {
input: string;
defaultValue: string;
open: boolean;
onClose: () => void;
dependencies: ComponentDependencies;
Expand Down Expand Up @@ -100,7 +101,7 @@ export const TranslationDialogContextProvider: FunctionComponent<DialogProps> =
setTranslationsForm({ ...translationsForm });
};

const loadTranslations = (languages?: Set<string>, reinitiliaze = true) => {
const loadTranslations = (languages?: Set<string>, reinitialize = true) => {
translationService
.getTranslationsOfKey(props.input, languages)
.then(([result, languages]) => {
Expand All @@ -119,10 +120,12 @@ export const TranslationDialogContextProvider: FunctionComponent<DialogProps> =
setSelectedLanguages(new Set(languages));
}

if (!translationsForm || reinitiliaze) {
setTranslationsForm(
responseToTranslationData(result?.translations)
if (!translationsForm || reinitialize) {
const translationsData = responseToTranslationData(
result?.translations
);
setTranslationsForm(translationsData);

setScreenshots(
result?.screenshots?.map((sc) => ({
...sc,
Expand Down Expand Up @@ -270,6 +273,34 @@ export const TranslationDialogContextProvider: FunctionComponent<DialogProps> =
properties.preferredLanguages || new Set([properties.currentLanguage])
);

// sets the default value for base language if is not stored already
useEffect(() => {
if (
props.defaultValue &&
availableLanguages &&
selectedLanguages &&
translationsForm
) {
const baseLanguageDefinition = availableLanguages.find((l) => l.base);
if (
baseLanguageDefinition &&
selectedLanguages.has(baseLanguageDefinition.tag)
) {
if (!translationsForm[baseLanguageDefinition.tag]) {
setTranslationsForm({
...translationsForm,
[baseLanguageDefinition.tag]: props.defaultValue,
});
}
}
}
}, [
availableLanguages,
translationsForm,
selectedLanguages,
props.defaultValue,
]);

const onSelectedLanguagesChange = (value: Set<string>) => {
if (value.size) {
setSelectedLanguages(value);
Expand Down
4 changes: 2 additions & 2 deletions packages/ui/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ export class UI {
);
}

public renderViewer(key: string) {
this.viewerComponent.translationEdit(key);
public renderViewer(key: string, defaultValue?: string) {
this.viewerComponent.translationEdit(key, defaultValue);
}

public async getKey(props: {
Expand Down
29 changes: 27 additions & 2 deletions testapps/react/src/Page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,33 @@ export const Page: FunctionComponent = () => {
</div>

<div>
{t('hey', undefined, true)}
{t('hey', undefined, false)}
<h3>Keys with defaults</h3>
<p>
<T keyName="with_default">This is default</T>
</p>
<p>{t({ key: 'key', defaultValue: 'This is default value!' })}</p>
</div>

<div>
<h3>Same key multiplied in same element</h3>
<div className="same-key-multiple">
{t({ key: 'key', defaultValue: 'First one' })}
<br />
{t({ key: 'key', defaultValue: 'Second one' })}
</div>
</div>

<div>
<h3>Multiple keys in same element</h3>
<div className="multiple-keys">
{t({ key: 'key', defaultValue: 'First one' })}
<br />
{t({ key: 'key 2', defaultValue: 'Second one' })}
<br />
{t({ key: 'key 3', defaultValue: 'Third one' })}
<br />
{t({ key: 'key 3', defaultValue: 'Third one again' })}
</div>
</div>
</div>
);
Expand Down

0 comments on commit 5f66114

Please sign in to comment.