问题
I have a Spring-boot
application that uses JPA
and Hibernate
. You can find the whole code on this GitHub repository.
My question is how can I add internationalization functionality to a specific column without any foreign keys and by using JSON
structure?
For example I would like to define a JPA entity like this:
@Entity
class Book {
@Id
private int id;
private Author author;
@I18n //<- this annotation is something that I am looking for
private String title;
}
and then the data in title
column would be stored like the following for en
and de
locales:
{"en":"Cologne","de":"Köln"}
And then when the current locale is de
the Köln
and when the en
is set as locale then Cologne
fetch in the time of reading data!
Also when we store the data, the passed string is stored in the relevant property in the JSON format. For example if the locale is set to es
and user passes Kolne
then we have to have the following data in the DB:
{"en":"Cologne","de":"Köln","es":"Kolne"}
It is interesting for me that most of the solutions in the web for hibernate and JPA is based on an old method that we have languages
and translations
tables. Something like here or here.
However what I am looking for is some solutions like this one which is suggested for Laravel and store the translations exactly in the way that I explained (i.e. in a JSON object and in the same column)!
The only solution that I found and could be somehow relevant (Not 100%) is this one, however it does not working when I tried to test it and it seems does not supported anymore!
回答1:
Since this is a very common requirement, this answer is based on this article I wrote on my blog, which explains how the Hibernate Types project adds support for mapping
Map
entity attributes as JSON column types.
Hibernate Types project
First, you need to add the Hibernate Type project dependency.
Afterward, you could use either an HStore column or a JSONB column to store the locate-specific titles:
@Entity
@TypeDef(name = "jsonb", typeClass = JsonBinaryType.class)
class Book {
@Id
private int id;
private Author author;
@Type(type = "jsonb")
@Column(name = "localized_titles", columnDefinition = "jsonb")
private Map<String, String> localizedTitles = new HashMap<>();
public String getLocalizedTitle(String locale) {
return localizedTitles.get(locale);
}
public String getLocalizedTitle() {
return localizedTitles.get(LocaleUtil.getDefaultLocale());
}
}
So, you can call the getLocalizedTitle
and pass the current locale to get the current localized title.
Book book = entityManager.find(Book.class, bookId);
String title = book.getLocalizedTitle("en");
Or, you could store the current locale in a ThreadLocal
in a class called LocaleUtil
:
public class LocaleUtil {
private static final ThreadLocal<String> LOCALE_HOLDER =
new ThreadLocal<>();
public static String getLocale() {
return LOCALE_HOLDER.get();
}
public static void setLocale(String locale) {
LOCALE_HOLDER.set(locale);
}
public static void reset() {
LOCALE_HOLDER.remove();
}
}
And store the current locale like this:
LocaleUtil.setLocale("en");
And, then just call the getLocalizedTitle
method that takes no argument:
Book book = entityManager.find(Book.class, bookId);
String title = book.getLocalizedTitle();
Check out this PostgreSQLJsonMapTest test case on GitHub for more details about using Hibernate Types to persiste Java
Map
asJSON
column types.
来源:https://stackoverflow.com/questions/62409871/how-can-i-implement-i18n-as-a-json-object-for-a-jpa-or-hibernate-entity