One way of doing this is to intercept loading of all messages for a specific language. It’s done by the Resources
implementation used by JmixMessageSource
bean created by the framework. So you can define your own JmixMessageSource
bean and provide a custom Resources
implementation to it.
For example:
@SpringBootApplication
public class AppApplication {
// ...
@Bean(name = "customMessageSource")
@Primary
MessageSource messageSource(JmixModules modules, ApplicationContext applicationContext) {
CustomResources customResources = new CustomResources(applicationContext);
return new JmixMessageSource(modules, customResources);
}
}
package com.company.app;
import io.jmix.core.Resources;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.core.io.InputStreamResource;
import org.springframework.core.io.Resource;
import javax.annotation.Nullable;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
public class CustomResources implements Resources {
private ApplicationContext applicationContext;
private Resources delegate;
@Autowired
public CustomResources(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
this.delegate = applicationContext.getBean(Resources.class);
}
@Override
public Resource getResource(String location) {
byte[] data = loadResourceFromCustomLocation(location);
if (data.length > 0) {
return new InputStreamResource(new ByteArrayInputStream(data));
} else {
return delegate.getResource(location);
}
}
private byte[] loadResourceFromCustomLocation(String location) {
// load messages for a specific language from the database and
// optionally merge with a content loaded by delegate.getResource(location)
return new byte[0];
}
@Override
public ClassLoader getClassLoader() {
return delegate.getClassLoader();
}
@Nullable
@Override
public InputStream getResourceAsStream(String location) {
try {
Resource resource = getResource(location);
if (resource.exists())
return resource.getInputStream();
else
return null;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Nullable
@Override
public String getResourceAsString(String location) {
try (InputStream stream = getResourceAsStream(location)) {
if (stream == null)
return null;
return IOUtils.toString(stream, StandardCharsets.UTF_8);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
Another option is to redefine the JmixMessageSource
bean itself and override its methods loading individual messages. The new bean should be defined as follows:
@SpringBootApplication
public class AppApplication {
// ...
@Bean(name = "customMessageSource")
@Primary
MessageSource messageSource(JmixModules modules, Resources resources) {
return new CustomMessageSource(modules, resources);
}
}
Regards,
Konstantin