Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Event based I18N support for components #3371

Open
heruan opened this issue Jan 22, 2018 · 3 comments
Open

Event based I18N support for components #3371

heruan opened this issue Jan 22, 2018 · 3 comments

Comments

@heruan
Copy link
Member

heruan commented Jan 22, 2018

Any component with text attributes should support I18N in a simple way, e.g. being able to translate its text values reacting on locale change. The current implementation support for this is limited to custom components, which should take responsibility for translating their children, e.g.

class MyComponent extends Component implements LocaleChangeObserver {

    private TextField usernameField = new TextField();

    public MyComponent() {
        this.add(this.usernameField);
    }

    @Override
    public void localeChange(LocalChangeEvent event) {
        usernameField.setLabel(getI18NProvider().getTranslation("username.label"));
        usernameField.setPlaceholder(getI18NProvider().getTranslation("username.placeholder"));
    }
}

I see a couple of issues here:

  1. the need having fields for each child component to localize, while having the component itself being able to react to locale changes would be simpler, e.g. with an event which provides an instance of the component itself and I18NProvider, e.g.
TextField usernameField = new TextField();
usernameField.addLocaleChangeListener(event -> {
    I18NProvider i18n = event.getI18NProvider();
    usernameField.setLabel(i18n.getTranslation("username.label"));
    usernameField.setPlaceholder(i18n.getTranslation("username.placeholder"));
});
  1. cannot apply I18N logic when a component is provided by a list/factory/etc., e.g.
interface RouterLinkSupplier {

    RouterLink getRouterLink();
}

@Route("foo")
class MyComponent extends Component implements RouterLinkSupplier {
    // ...
    @Override
    public RouterLink getRouterLink() {
        RouterLink link = new RouterLink(null, MyComponent.class);
        link.addLocaleChangeListener(event -> link.setText(getI18NProvider().getTranslation("foo")));
        return link;
    }
}

class MyLayout extends Component implements RouterLayout {
    // ...
    public MyLayout(List<RouterLinkSupplier> navigationTargets) {
        for (RouterLinkSupplier t : navigationTargets) {
            // all the router links will already know how to translate themselves
            this.navbar.add(t.getRouterLink());
        }
    }
}
@heruan
Copy link
Member Author

heruan commented Feb 16, 2018

For reference, I'm using this right now:

public class LocalizedTextField extends TextField implements LocaleChangeObserver {

    private final List<LocaleChangeListener> localeChangeListeners = new ArrayList<>();

    public Registration addLocaleChangeListener(LocaleChangeListener listener) {
        this.localeChangeListeners.add(listener);
        return () -> this.localeChangeListeners.remove(listener);
    }

    @Override
    public void localeChange(LocaleChangeEvent event) {
        this.localeChangeListeners
                .forEach(listener -> listener.onLocaleChange(event));
    }
}

But of course I need to extend every core component to do this. Since LocaleChangeEvent is not a ComponentEvent this cannot be done in a mixin interface since Component::addListener only accepts events extending ComponentEvent.

@heruan
Copy link
Member Author

heruan commented Mar 11, 2018

Would it be acceptable for this to have a generic event map in Component and implement a behavior for generic events similar to how ComponentEvents are handled? So that any component which may be target of I18N can simply implement a mixin interface and have locale change listeners attached to it.

@heruan
Copy link
Member Author

heruan commented Jul 5, 2018

I just noticed new I18N methods were recently added to the Component class, i.e. getTranslation(key, ...params) and getTranslation(key, locale, ...params).

What about adding a method like this?

public void setTranslation(Setter<C, String> setter, String key, Object... args) {
   addLocaleChangeListener(event -> setter.accept(this, getTranslation(key, args));
}

to be used like button.setTranslation(Button::setText, "my-key"), so that whenever the locale changes, the button has the right label.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants