Grails i18n Из базы данных, но по умолчанию Back To File

После в этой статье в блоге Я включил мое приложение для загрузки сообщений i18n из базы данных. Он отлично работает. Однако я не хочу управлять всеми сообщениями в базе данных. Поэтому я хотел бы сказать, не найти код в базе данных, а затем загрузить его с использованием механизма по умолчанию.

Вот что у меня есть:

class DatabaseMessageSource extends AbstractMessageSource {
  protected MessageFormat resolveCode(String code, Locale locale) {
    Message msg = Message.findByCodeAndLocale(code, locale)
    def format = null
    if (msg) {
      format = new MessageFormat(msg.text, msg.locale)
    }else{
      // What do I do here to grab it from the file
    }
    return format;
  }
}

Я попытался вызвать super.resolveCode(код, локаль), но это привело к ошибкам компиляции. И я с трудом отслеживаю реализацию AbstractMessageSource, который Grails использует по умолчанию, чтобы посмотреть на источник.

UPDATE: Благодаря doelleri я теперь понимаю, что мне нужно сделать, это нечто вроде расширения ResourceBundleMessageSource. К сожалению, есть несколько проблем с этим подходом. В моем файле resources.groovy у меня есть следующее:

messageSource(DatabaseMessageSource)

Прежде всего, если я просто расширяю ResourceBundleMessageSource и переопределяю метод resolveCode, этот метод никогда не вызывается. Поэтому в моем блоке else вызов super.resolveCode является спорным.

Затем я попытался просто реализовать свой класс DatabaseMessageSource со всем кодом из ResourceBundleMessageSource, но я, очевидно, что-то пропустил в resource.groovy, потому что пакеты по умолчанию не подключаются.

Итак, в этот момент я все еще теряюсь в том, что мне нужно делать. Я хочу сначала проверить базу данных. Если код не существует, вернитесь к тому же поведению по умолчанию, что и ResourceBundleMessageSource.

Ответ 1

Я бы предложил оставить один источник сообщений в новом bean и ввести его в DatabaseMessageSource.

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"
    }
}

DatabaseMessageSource.groovy:

class DatabaseMessageSource extends AbstractMessageSource {

    def messageBundleMessageSource

    protected MessageFormat resolveCode(String code, Locale locale) {
         Message msg = Message.findByCodeAndLocale(code, locale)
         def format
         if(msg) {
             format = new MessageFormat(msg.text, msg.locale)
         }
         else {
             format = messageBundleMessageSource.resolveCode(code, locale)
         }
         return format;
    }
}

Таким образом, в резервном решении сообщение будет считано из соответствующего файла messages_*.properties, просто запросив его из одного источника сообщений пакета ресурсов. Обратите внимание, что вы должны использовать PluginAwareResourceBundleMessageSource, иначе вы могли бы пропустить некоторые важные сообщения из ваших плагинов.

Ответ 2

Вместо этого вы можете продлить ReloadableResourceBundleMessageSource (исходный комплект сообщений Grails, который не кажется окончательным), а затем применить этот код:

class DatabaseMessageSource extends ReloadableResourceBundleMessageSource {
  protected MessageFormat resolveCode(String code, Locale locale) {
    Message msg = Message.findByCodeAndLocale(code, locale)
    def format = null
    if (msg) {
      format = new MessageFormat(msg.text, msg.locale)
    }else{
      format = super.resolveCode(code,locale)
    }
    return format;
  }
}

Вы также можете перенастроить свои ресурсы сообщений в Resources.groovy:

 beans = {
    messageSource(com.mycompany.DatabaseMessageSource) {
        basename = "WEB-INF/grails-app/i18n/messages"
    }
 }

Ответ 4

Несмотря на то, что это не Grails, мы в Griffon создали CompositeResourceBundle и DelegatingResourceBundle как часть нашего собственного i18n-плагина (источник найден в http://svn.codehaus.org/griffon/plugins/griffon-i18n/trunk/src/main/griffon/plugins/i18n/).

ExtendedResourceBundleMessageSource показывает, как эти классы могут быть использованы.

Ответ 5

Я настоятельно рекомендую вам использовать Copycopter (http://copycopter.com) для управления содержимым ключей i18n. Это позволит вашей команде легко обновлять ключи "на лету", используя дружественный интерфейс, и вы сможете установить по умолчанию по своему усмотрению. Таким образом, никто не придет к вам, когда нужно обновить ключ.

ThoughtBot, сильная консалтинговая компания по разработке веб-сайтов, стоит за этим продуктом. Он прочен.

Ваш код будет выглядеть следующим образом:

mail :to => member.email,
     :subject => I18n.translate("member_mailer.reminder_to_sign_in.#{underscored_number_of_days}.subject",
                                :default => %{You have not signed in for #{humanized_number_of_days}})

Клавиши i18n генерируются "на лету" на copytcopter, при первом использовании. Это действительно легко использовать.

Проверьте это, это того стоит.