<< ГЛИКЕМИЧЕСКИЙ ИНДЕКС ПРОДУКТОВ | На главную | Import Mini DV в Windows 7 через firewire 1394 >>

grails интернационализация (i18n)

Осваиваю grails. Первая проблема - интернационализация. К счастью в grails уже всё для этого готово, единственное что захотелось ускорить - создание ключей для строк всех объектов в проекте.

Плагин который позволяет сгенерировать все ключи для домена называется i18n-templates.

Устанавливаем плагин:

grails install-plugin i18n-templates -global

Допиливаем под grails 2.3: В файле $USER_HOME/.grails/<grailsVersion>/projects/<PROJECTNAME>/plugins/i18n-templates-1.1.0.1/scripts/GenerateI18nMessages.groovy Изменяем процедуру generateForDomainClass (изменения выделены жирным):

def generateForDomainClass(domainClass) {
    // print generic messages for this domain class
    println "# ${domainClass.shortName} messages"
    println "${domainClass.shortName}.label=${domainClass.shortName}"
    println "${domainClass.propertyName}.create.label=Create ${domainClass.shortName}"
    println "${domainClass.propertyName}.edit.label=Edit ${domainClass.shortName}"
    println "${domainClass.propertyName}.list.label=${domainClass.shortName} List"
    println "${domainClass.propertyName}.new.label=New ${domainClass.shortName}"
    println "${domainClass.propertyName}.show.label=Show ${domainClass.shortName}"
    println "${domainClass.propertyName}.created.label=${domainClass.shortName} {0} created"
    println "${domainClass.propertyName}.updated.label=${domainClass.shortName} {0} updated"
    println "${domainClass.propertyName}.deleted.label=${domainClass.shortName} {0} deleted"
    println "${domainClass.propertyName}.not.found.label=${domainClass.shortName} not found with id {0}"
    println "${domainClass.propertyName}.not.deleted.label=${domainClass.shortName} not deleted with id {0}"
    println "${domainClass.propertyName}.optimistic.locking.failure.label=Another user has updated this ${domainClass.shortName} while you were editing"

    // print messages for all properties contained by domain class
    props = domainClass.properties.findAll { it.name != 'version' }
    Collections.sort(props, new DomainClassPropertyComparator(domainClass))
    props.each { p ->
        println "${domainClass.propertyName}.${p.name}.label=${p.naturalName}"

        // print messages for inList constaint values
        cp = domainClass.constrainedProperties[p.name]
        if (cp?.inList) {
            cp.inList.each { v ->
                println "${domainClass.propertyName}.${p.name}.${v}.label=${v}"
            }
        }

        // print error messages for constraints
        cp?.appliedConstraints?.each { c ->
            switch (c.name) {
                case ConstrainedProperty.BLANK_CONSTRAINT:
                    if (!c.parameter)
                        println "${domainClass.propertyName}.${p.name}.${c.name}.error=Property [${p.naturalName}] of class [${domainClass.shortName}] cannot be blank"
                    break
                case ConstrainedProperty.CREDIT_CARD_CONSTRAINT:
                    println "${domainClass.propertyName}.${p.name}.${c.name}.error=Property [${p.naturalName}] of class [${domainClass.shortName}] with value [{2}] is not a valid credit card number"
                    break
                case ConstrainedProperty.EMAIL_CONSTRAINT:
                    println "${domainClass.propertyName}.${p.name}.${c.name}.error=Property [${p.naturalName}] of class [${domainClass.shortName}] with value [{2}] is not a valid e-mail address"
                    break
                case ConstrainedProperty.IN_LIST_CONSTRAINT:
                    println "${domainClass.propertyName}.${p.name}.${c.name}.error=Property [${p.naturalName}] of class [${domainClass.shortName}] with value [{2}] is not contained within the list [{3}]"
                    break
                case ConstrainedProperty.MATCHES_CONSTRAINT:
                    println "${domainClass.propertyName}.${p.name}.${c.name}.error=Property [${p.naturalName}] of class [${domainClass.shortName}] with value [{2}] does not match the required pattern [{3}]"
                    break
                case ConstrainedProperty.MAX_CONSTRAINT:
                    println "${domainClass.propertyName}.${p.name}.${c.name}.error=Property [${p.naturalName}] of class [${domainClass.shortName}] with value [{2}] exceeds maximum value [{3}]"
                    break
                case ConstrainedProperty.MAX_SIZE_CONSTRAINT:
                    println "${domainClass.propertyName}.${p.name}.${c.name}.error=Property [${p.naturalName}] of class [${domainClass.shortName}] with value [{2}] exceeds the maximum size of [{3}]"
                    break
                case ConstrainedProperty.MIN_CONSTRAINT:
                    println "${domainClass.propertyName}.${p.name}.${c.name}.error=Property [${p.naturalName}] of class [${domainClass.shortName}] with value [{2}] is less than minimum value [{3}]"
                    break
                case ConstrainedProperty.MIN_SIZE_CONSTRAINT:
                    println "${domainClass.propertyName}.${p.name}.${c.name}.error=Property [${p.naturalName}] of class [${domainClass.shortName}] with value [{2}] is less than the minimum size of [{3}]"
                    break
                case ConstrainedProperty.NOT_EQUAL_CONSTRAINT:
                    println "${domainClass.propertyName}.${p.name}.${c.name}.error=Property [${p.naturalName}] of class [${domainClass.shortName}] with value [{2}] cannot equal [{3}]"
                    break
                case ConstrainedProperty.NULLABLE_CONSTRAINT:
                    if (!c.nullable)
                        println "${domainClass.propertyName}.${p.name}.${c.name}.error=Property [${p.naturalName}] of class [${domainClass.shortName}] cannot be null"
                    break
                case ConstrainedProperty.RANGE_CONSTRAINT:
                    println "${domainClass.propertyName}.${p.name}.${c.name}.error=Property [${p.naturalName}] of class [${domainClass.shortName}] with value [{2}] does not fall within the valid range from [{3}] to [{4}]"
                    break
                case ConstrainedProperty.SIZE_CONSTRAINT:
                    println "${domainClass.propertyName}.${p.name}.${c.name}.error=Property [${p.naturalName}] of class [${domainClass.shortName}] with value [{2}] does not fall within the valid size range from [{3}] to [{4}]"
                    break
                //case ConstrainedProperty.UNIQUE_CONSTRAINT: // unique constraint reference not available
                //    println "${domainClass.propertyName}.${p.name}.${c.name}.error=Property [${p.naturalName}] of class [${domainClass.shortName}] with value [{2}] must be unique"
                //    break
                case ConstrainedProperty.URL_CONSTRAINT:
                    println "${domainClass.propertyName}.${p.name}.${c.name}.error=Property [${p.naturalName}] of class [${domainClass.shortName}] with value [{2}] is not a valid URL"
                    break
                case ConstrainedProperty.VALIDATOR_CONSTRAINT:
                    println "${domainClass.propertyName}.${p.name}.${c.name}.error=Property [${p.naturalName}] of class [${domainClass.shortName}] with value [{2}] does not pass custom validation"
                    break
            }
        }
    }
    println ""
}

Запускаем для домена:

grails generate-i18n-messages <domainClass>

или для всех (что ещё проще):

grails generate-i18n-messages *

В окне вывода получаем готовые строки для переноса их в messages.properties

Часть фраз не переведено по умолчанию, их лучше сразу добавить в messages_ru.properties

default.list.label=Список {0}
default.create.label=Создать {0}
default.link.skip.label=Пропустить
default.home.label=Главная
default.edit.label=Редактировать {0}
default.new.label=Новый {0}
default.show.label=Показать {0}
default.button.create.label=Создать
default.button.edit.label=Редактировать
default.button.update.label=Сохранить
default.button.delete.label=Удалить

Если необходимо установить по умолчанию русский язык, то добавляем в conf/spring/resources.groovy:

beans = {
   localeResolver(org.springframework.web.servlet.i18n.SessionLocaleResolver) {
      defaultLocale = new Locale("ru","RU")
      java.util.Locale.setDefault(defaultLocale)
   }
}

 

Ссылки:

http://grails.org/plugin/i18n-templates

Интернационализация javascript: http://mrhaki.blogspot.ru/2011/11/grails-goodness-internationalize.html

Ярлыки :



Комментировать Отправить TrackBack