Writing stories in your language

Good and effective communication is key to BDD. Therefore, writing stories in the language spoken by the business users is essential. And even though the patterns used to match the scenario steps to Java methods can be written in any language, the Keywords still need to be expressed in different languages.

JBehave by default uses English as the scenario language. By supporting the internationalisation (i18n) of keywords by Java Locale, it also allows the stories to be written in any language. All is needed to configure the use of LocalizedKeywords for a given locale. Each locale has a separate keywords properties file, e.g. for Italian i18n/keywords_it.properties contained in the jbehave-core.jar.

We need to configure the use of the localized keywords, e.g.:

public class ItTraderStory extends JUnitStory {

	public ItTraderStory() {
        // use Italian for keywords
        ClassLoader classLoader = this.getClass().getClassLoader();
        Keywords keywords = new LocalizedKeywords(new Locale("it"));
        Configuration configuration = new MostUsefulConfiguration()
                .useStoryPathResolver(new UnderscoredCamelCaseResolver(".story"))
                .useKeywords(keywords)
                .useStoryParser(new RegexStoryParser(keywords))
                .useStoryLoader(
                        new LoadFromClasspath(classLoader))
                .useDefaultStoryReporter(new ConsoleOutput(keywords))
                .useStoryReporterBuilder(new StoryReporterBuilder()
                    .withCodeLocation(codeLocation)
                    .withDefaultFormats()
                    .withFormats(CONSOLE, TXT, HTML, XML)
                    .withFailureTrace(false)
                    .withKeywords(keywords))
        useConfiguration(configuration);
        addSteps(new InstanceStepsFactory(configuration, new ItTraderSteps()).createCandidateSteps());
    }

}

The parsing of the story with then understand the language that has been configured via the localized keywords and the patterns annotating the Steps methods must be in the same language:

public class ItTraderSteps {

    private Stock stock;
    private ExamplesTable table;

    @Given("ho un'azione con simbolo $symbol e una soglia di $threshold")
    public void aStock(@Named("symbol") String symbol, @Named("threshold") double threshold) {
        stock = new Stock(symbol, threshold);
    }

}

Note that the localized keywords not only allow the translation of the keywords used in parsing the textual story, but also the keywords used in the reporting of the story execution, e.g. Pending, NotPerformed and Failed.

What encoding should I use for textual stories and Java source classes?

Always use encoding UTF-8 for textual stories and Java source classes.

What languages are supported out-of-the-box?

JBehave supports a number of languages out-of-the-box, allowing users to simply specify the locale in the LocalizedKeywords. You can verify which language is supported by looking at the i18n/ directory in the jbehave-core-resources.zip. If you'd like your language to be supported, you can contribute the keywords in that language and we'll happily add it.

Note that Java resource bundles require non-English language characters to be expressed as Unicode escaped characters (of the form \uxxxx where xxxx is 4-digit Hexadecimal number), using ISO-8859-1 encoding. There are a number of tools that enable easy conversion between your non-English language characters and Unicode escaped characters.

How do I add my own keywords bundle?

Write a properties bundle containing the following keywords and save it as i18n/keywords_xx.properties. E.g. for Lolcatz we'll have i18n/keywords_lc.properties:

Narrative=Narratif:
InOrderTo=In Oder to
AsA=As a
IWantTo=I Wan
Scenario=I can haz:
GivenStories=Gief I can haz:
ExamplesTable=Exemples:
ExamplesTableRow=Exemple:
ExamplesTableHeaderSeparator=!!
ExamplesTableValueSeparator=!
Given=Gief
When=Wen
Then=Den
And=And
Ignorable=!--
Pending=PENDING
NotPerformed=NOT PERFORMED
Failed=FAILED
DryRun=Dry Run

Make sure the bundle is in the your classpath and invoke it as (if using default bundle name):

 Keywords keywords = new LocalizedKeywords(new Locale("lc"));

If using a non-standard bundle name, e.g. mykeywords/keys:

 ClassLoader classLoader = ... // the classloader where to find the bundle from
 Keywords keywords = new LocalizedKeywords(new Locale("lc"), "mykeywords/keys", classLoader);