我试图得到一种情况,我可以使用i18n属性文件与数据库备份?
所以对于一些标准的东西,我想使用属性文件,但有些字段必须由最终用户编辑,所以我计划在数据库中使用i18n。所以一个真正的组合会很好。如果在属性文件中找不到i18n代码,则在DB中进行查找。
你知道我该怎么解决这个问题吗?我看到过Grails i18n From Database but Default Back To File
但是这个问题没有真正的答案,关于如何解决这个问题有其他建议吗?
在项目中添加一个新的域类:
class Message {
String code
Locale locale
String text
}
将以下行添加到您的resources.groovy
:
// Place your Spring DSL code here
beans = {
messageSource(DatabaseMessageSource) {
messageBundleMessageSource = ref("messageBundleMessageSource")
}
messageBundleMessageSource(org.codehaus.groovy.grails.context.support.PluginAwareResourceBundleMessageSource) {
basenames = "WEB-INF/grails-app/i18n/messages"
}
}
并将以下类添加到您的src/groovy
文件夹:
class DatabaseMessageSource extends AbstractMessageSource {
def messageBundleMessageSource
protected MessageFormat resolveCode(String code, Locale locale) {
Message msg = messageBundleMessageSource.resolveCode(code, locale)
def format
if(msg) {
format = new MessageFormat(msg.text, msg.locale)
}
else {
format = Message.findByCodeAndLocale(code, locale)
}
return format;
}
}
现在grails将尝试解析来自消息包的消息。如果它不可用,它将从数据库中查找。您可以添加一些错误处理,但如果所有消息至少在一个地方可用,则此版本可以工作。
详情见http://graemerocher.blogspot.com/2010/04/reading-i18n-messages-from-database.html
关于resources.groovy
改动的一些细节:
在这个文件中,您可以定义可注入的groovy类,它可以通过定义一个与resources.groovy
中定义的名称相同的变量来包含。例如,在这个文件中,有messageSource
和messageBundleMessageSource
,您可以将它们包含在任何控制器或服务文件中。如果定义了这个变量,则创建括号中类的一个实例。
在这种情况下,我们覆盖一般的messageSource
来使用我们的自定义实现DatabaseMessageSource
。因此,I18n函数message
现在将使用我们的自定义实现。
由于我们的自定义实现需要检查message.properties
-文件,因此我们将原始消息源保留在第二个bean中。通过在自定义实现中定义这个实例,我们仍然可以使用旧的实现(因此可以用通常的方式查找消息)。
我不太明白你说的
是什么意思使用数据库备份的i18n属性文件
但是,如果您只是希望使用数据库表(而不是.properties文件)解析消息键,那么您可以通过编写自己的MessageSource接口
实现来实现这一点class DBMessageSource implements MessageSource {
String getMessage(MessageSourceResolvable resolvable, Locale locale) {
// IMPLEMENT ME
}
String getMessage(String code, Object[] args, Locale locale) {
// IMPLEMENT ME
}
String getMessage(String code, Object[] args, String defaultMessage, Locale locale) {
// IMPLEMENT ME
}
}
然后通过向resources.groovy
messageSource
bean的默认实现替换为您的实现messageSource(DBMessageSource)
在@crudolf的回答之后,我实现了以下方法来实现我的目标。
class DatabaseMessageSource extends AbstractMessageSource {
// the message bundle resource that holds all of the messages
def messageBundleMessageSource
// the default locale used when there is no correct results found
// if a visitor (x) comes along with an unknown locale in the DB
// then this locale will be used as fallback!
Locale fallbackLocale = new Locale("nl", "NL")
protected MessageFormat resolveCode(String code, Locale locale) {
// first try to find the message in the messagebundles
MessageFormat messageFormat = messageBundleMessageSource.resolveCode(code, locale)
if(!messageFormat) {
// no message found so lets find one in the database
def message = Message.findByCodeAndLocale(code, locale) ?: Message.findByCodeAndLocale(code, fallbackLocale)
if (message) {
// found one create a message format!
messageFormat = new MessageFormat(message.text, message.locale)
} else {
// not found! create a standard message format
messageFormat = new MessageFormat(code, locale)
}
}
return messageFormat
}
}
看看https://github.com/goeh/grails-i18n-db和https://github.com/halfbaked/grails-localizations。两者都提供了一个gui来管理本地化。