0

I have found this great gant script on http://blog.armbruster-it.de/2010/07/getting-a-list-of-all-i18n-properties-used-in-a-grails-application/ Thanks Stefan!

Description: create a list of all i18n properties used in groovy code and gsp templates

def properties = []

new File(".").eachFileRecurse {
    if (it.file) {
        switch (it) {
            case ~/.*\.groovy/:
                def matcher = it.text =~ /code:\s*["'](.*?)["']/
                matcher.each { properties << it[1] }
                break
            case ~/.*\.gsp/:
                def matcher = it.text =~ /code=["'](.*?)["']/
                matcher.each { properties << it[1] }
                break
        }
    }
}
println properties.sort().unique().join("\n")

I tried to extend it in the following way. Let's say we have soem message properties like:

message(code: 'product.label', default: 'Product')

What we want to have as output of the script something like:

product.label=Product

I tried to add some condition to the regex:

def matcher = it.text =~ /code=["'](.*?)["'] | default=\s*["'](.*?)["']/

and to fill it to properties. But as the regex does not find pairs of "code and default"-parts this is not going to work.

Any idea how to change the regex or the whole script to do this?

skurt
  • 1,019
  • 2
  • 13
  • 29

4 Answers4

2

Your regular expression is incorrect. For the following message method call:

message(code: 'product.label', default: 'Product')

It should look like this:

def properties = [:]
def txt = "message(code: 'product.label', default: 'Product')"
def matcher = txt =~ /code:\s*["'](.*?)["'].*default:\s*["'](.*?)["']/
matcher.each{ properties[it[1]] = it[2] }
assert properties == ['product.label':'Product']
Kai Sternad
  • 22,214
  • 7
  • 47
  • 42
  • ups, I read your solution after I post mine. nearly the same and working, thanks! – skurt Apr 20 '11 at 09:17
  • as I worked with this code I experience some weakness: It only finds one matching per line of code. To fix this we have to change matcher. – skurt Apr 26 '11 at 12:54
  • From what I understand it's not even looking at lines but at the whole text and actually finds multiple matchings for me. A problem is, that it (a) only finds matchings that have a default and ignores those without and (b) ignores the fact that sometimes you'll have to use ${g.message(…)} in .gsp files as well. – fluxon Mar 11 '13 at 11:05
1

Aside from providing a better regex as bunting did, I found a pretty useful Grails plugin: message-reports

Stefan Armbruster
  • 39,465
  • 6
  • 87
  • 97
  • but one thing I have to add. What I was looking for is more a script what gets me all the codes together with its defaults. As our app has not used i18n until now all strings have to be separated from inside the code. I will try what groups in regex can do to solve this. – skurt Apr 20 '11 at 06:20
0

I worked a bit with this script and found some details that needed attention. I want to find messages with and without defined defaults and I want to find the non-tag verson (i.e. ${g.message(code:"the.code", default:"the.default"}) as well.

It seems good to not go over the file's content but parse it line by line. This is because iIf there is a code in a line, I'll (in a second step) take a look if it has a default. Don't want to parse the whole file twice though.

def properties = [:]

new File(".").eachFileRecurse { file ->
    if (file.file) {
        switch (file) {
            case ~/.*\.groovy/:
                file.eachLine {line ->
                    // check if there is a message in the current line
                    def matcherNoDefault = line =~ /code:\s*["'](.*?)["']/
                    // if there is one, check if it has a default
                    if (matcherNoDefault.getCount() > 0) {
                        def matcher = line =~ /code:\s*["'](.*?)["'].*default:\s*["'](.*?)["']/
                        if (matcher.getCount() > 0) {
                            matcher.each{ properties[it[1]] = it[2] }
                        } else {
                            matcherNoDefault.each{ properties[it[1]] = "NO_DEFAULT" }
                        }
                    }
                }
                break
            case ~/.*\.gsp/:
                file.eachLine {line ->
                    // check if there is a message in the current line (as a g.message(...) function)
                    def matcherNoDefault = line =~ /code:\s*["'](.*?)["']/
                    // if there is one, check if it has a default
                    if (matcherNoDefault.getCount() > 0) {
                        def matcher = line =~ /code:\s*["'](.*?)["'].*default:\s*["'](.*?)["']/
                        if (matcher.getCount() > 0) {
                            matcher.each{ properties[it[1]] = it[2] }
                        } else {
                            matcherNoDefault.each{ properties[it[1]] = "NO_DEFAULT" }
                        }
                    }

                    // check if there is a message in the current line (in tag form)
                    matcherNoDefault = line =~ /code=["'](.*?)["']/
                    // if there is one, check if it has a default
                    if (matcherNoDefault.getCount() > 0) {
                        def matcher = line =~ /code=["'](.*?)["'].*default=["'](.*?)["']/
                        if (matcher.getCount() > 0) {
                            matcher.each{ properties[it[1]] = it[2] }
                        } else {
                            matcherNoDefault.each{ properties[it[1]] = "NO_DEFAULT" }
                        }
                    }
                }
        }
    }
}
println properties.each {k, v ->
    println("${k}=${v}")
}

Like this I cannot mix messages with and without default in a single line. I can live with that for now.

Have fun!

fluxon
  • 538
  • 7
  • 19
0

the better regex to solve it is:

/code=["'](.*?)["'].*default=\s*["'](.*?)["']/

output format can be

properties << it[1]+"="+it[2]

results

product.label=Product
skurt
  • 1,019
  • 2
  • 13
  • 29