Skip to content

Commit

Permalink
Add example and example tests
Browse files Browse the repository at this point in the history
  • Loading branch information
alaugks committed Jun 7, 2024
1 parent 1d9f67b commit 4c3954d
Show file tree
Hide file tree
Showing 2 changed files with 304 additions and 5 deletions.
189 changes: 184 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@
<dependency>
<groupId>io.github.alaugks</groupId>
<artifactId>spring-messagesource-base</artifactId>
<version>0.1.0.1-SNAPSHOT</version>
<version>1.0.0.rc1-SNAPSHOT</version>
</dependency>
</dependencies>
```

## Configuration
## MessageSource Configuration
```java
import io.github.alaugks.spring.messagesource.base.catalog.Catalog;
import io.github.alaugks.spring.messagesource.base.catalog.CatalogHandler;
Expand All @@ -36,13 +36,31 @@ public class MessageConfig {
public MessageSource messageSource() {

List<Translation> translations = new ArrayList<>();
translations.add(new Translation(Locale.forLanguageTag("en"), "hello_world", "Hello World"));
translations.add(new Translation(Locale.forLanguageTag("de"), "hello_world", "Hallo Welt"));

var localeEn = Locale.forLanguageTag("en");
translations.add(new Translation(localeEn, "headline", "Headline"));
translations.add(new Translation(localeEn, "postcode", "Postcode"));
translations.add(new Translation(localeEn, "email-notice", "Your email {0} has been registered."));
translations.add(new Translation(localeEn, "default-message", "This is a default message."));
translations.add(new Translation(localeEn, "headline", "Payment", "payment"));
translations.add(new Translation(localeEn, "expiry_date", "Expiry date", "payment"));

var localeEnUs = Locale.forLanguageTag("en-US");
translations.add(new Translation(localeEnUs, "postcode", "Zip code"));
translations.add(new Translation(localeEnUs, "expiry_date", "Expiration date", "payment"));

var localeDe = Locale.forLanguageTag("de");
translations.add(new Translation(localeDe, "headline", "Überschrift"));
translations.add(new Translation(localeDe, "postcode", "Postleitzahl"));
translations.add(new Translation(localeDe, "email-notice", "Ihre E-Mail {0} wurde registriert."));
translations.add(new Translation(localeDe, "default-message", "Das ist ein Standardtext."));
translations.add(new Translation(localeDe, "headline", "Zahlung", "payment"));
translations.add(new Translation(localeDe, "expiry_date", "Ablaufdatum", "payment"));

return new BaseTranslationMessageSource(
CatalogHandler
.builder(
new Catalog(
new Catalog(
translations,
Locale.forLanguageTag("en")
)
Expand All @@ -53,6 +71,167 @@ public class MessageConfig {
}
```


### Target values

<table>
<thead>
<tr>
<th>id</th>
<th>en</th>
<th>en-US</th>
<th>de</th>
<th>jp***</th>
</tr>
</thead>
<tbody>
<tr>
<td>headline*<br>messages.headline</td>
<td>Headline</td>
<td>Headline**</td>
<td>Überschrift</td>
<td>Headline</td>
</tr>
<tr>
<td>postcode*<br>messages.postcode</td>
<td>Postcode</td>
<td>Zip code</td>
<td>Postleitzahl</td>
<td>Postcode</td>
</tr>
<tr>
<td>email-notice*<br>messages.email-notice</td>
<td>Your email {0} has been registered.</td>
<td>Your email {0} has been registered.**</td>
<td>Ihre E-Mail {0} wurde registriert.</td>
<td>Your email {0} has been registered.</td>
</tr>
<tr>
<td>default-message*<br>messages.default-message</td>
<td>This is a default message.</td>
<td>This is a default message.**</td>
<td>Das ist ein Standardtext.</td>
<td>This is a default message.</td>
</tr>
<tr>
<td>payment.headline</td>
<td>Payment</td>
<td>Payment**</td>
<td>Zahlung</td>
<td>Payment</td>
</tr>
<tr>
<td>payment.expiry_date</td>
<td>Expiry date</td>
<td>Expiration date</td>
<td>Ablaufdatum</td>
<td>Expiry date</td>
</tr>
</tbody>
</table>

> *Default domain is `messages`.
>
> **Example of a fallback from Language_Region (`en-US`) to Language (`en`). The `id` does not exist in `en-US`, so it tries to select the translation with locale `en`.
>
> ***There is no translation for Japanese (`jp`). The default locale translations (`en`) are selected.
<a name="a5"></a>

## Using the MessageSource

With the implementation and use of the MessageSource interface, the translations are also available in **Thymeleaf**, as **Service (Dependency Injection)** and **Custom Validation Messages**. Also in packages and implementations that use the MessageSource.

### Thymeleaf

With the configured MessageSource, the translations are available in Thymeleaf.

```html
<!-- Default domain: messages -->

<!-- "Headline" -->
<h1 th:text="#{headline}"/>
<h1 th:text="#{messages.headline}"/>

<!-- "Postcode" -->
<label th:text="#{postcode}"/>
<label th:text="#{messages.postcode}"/>

<!-- "Your email john.doe@example.com has been registered." -->
<span th:text="#{email-notice('john.doe@example.com')}"/>
<span th:text="#{messages.email-notice('john.doe@example.com')}"/>

<!-- "This is a default message." -->
<span th:text="${#messages.msgOrNull('not-exists-id')} ?: #{default-message}"/>
<span th:text="${#messages.msgOrNull('not-exists-id')} ?: #{messages.default-message}"/>


<!-- Domain: payment -->

<!-- "Payment" -->
<h2 th:text="#{payment.headline}"/>

<!-- "Expiry date" -->
<strong th:text="#{payment.expiry_date}"/>
```

### Service (Dependency Injection)

The MessageSource can be set via Autowire to access the translations.

```java
import org.springframework.context.MessageSource;

private final MessageSource messageSource;

// Autowire MessageSource
public MyClass(MessageSource messageSource) {
this.messageSource = messageSource;
}


// Default domain: messages

// "Headline"
this.messageSource.getMessage("headline", null, locale);
this.messageSource.getMessage("messages.headline", null, locale);

// "Postcode"
this.messageSource.getMessage("postcode", null, locale);
this.messageSource.getMessage("messages.postcode", null, locale);

// "Your email john.doe@example.com has been registered."
Object[] args = {"john.doe@example.com"};
this.messageSource.getMessage("email-notice", args, locale);
this.messageSource.getMessage("messages.email-notice", args, locale);

// "This is a default message."
//String defaultMessage = this.messageSource.getMessage("default-message", null, locale);
String defaultMessage = this.messageSource.getMessage("messages.default-message", null, locale);
this.messageSource.getMessage("not-exists-id", null, defaultMessage, locale);


// Domain: payment

// "Payment"
this.messageSource.getMessage("payment.headline", null, locale);

// "Expiry date"
this.messageSource.getMessage("payment.expiry-date", null, locale);
```

### Custom Validation Messages

The article [Custom Validation MessageSource in Spring Boot](https://www.baeldung.com/spring-custom-validation-message-source) describes how to use custom validation messages.


## Support

If you have questions, comments or feature requests please use the [Discussions](https://github.com/alaugks/spring-xliff-translation/discussions) section.

<a name="a8"></a>


## Translation Sources

* [XLIFF 2.0.0-SNAPSHOT](https://github.com/alaugks/spring-messagesource-xliff/tree/snapshot/2.0.0)
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
package io.github.alaugks.spring.messagesource.base;

import static org.junit.jupiter.api.Assertions.assertEquals;

import io.github.alaugks.spring.messagesource.base.catalog.Catalog;
import io.github.alaugks.spring.messagesource.base.catalog.CatalogHandler;
import io.github.alaugks.spring.messagesource.base.records.Translation;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.stream.Stream;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.springframework.context.MessageSource;

class BaseTranslationMessageSourceExampleTest {

MessageSource messageSource;

public BaseTranslationMessageSourceExampleTest() {
this.messageSource = this.messageSource();
}

public MessageSource messageSource() {

List<Translation> translations = new ArrayList<>();

var localeEn = Locale.forLanguageTag("en");
translations.add(new Translation(localeEn, "headline", "Headline"));
translations.add(new Translation(localeEn, "postcode", "Postcode"));
translations.add(new Translation(localeEn, "email-notice", "Your email {0} has been registered."));
translations.add(new Translation(localeEn, "default-message", "This is a default message."));
translations.add(new Translation(localeEn, "headline", "Payment", "payment"));
translations.add(new Translation(localeEn, "expiry_date", "Expiry date", "payment"));

var localeEnUs = Locale.forLanguageTag("en-US");
translations.add(new Translation(localeEnUs, "postcode", "Zip code"));
translations.add(new Translation(localeEnUs, "expiry_date", "Expiration date", "payment"));

var localeDe = Locale.forLanguageTag("de");
translations.add(new Translation(localeDe, "headline", "Überschrift"));
translations.add(new Translation(localeDe, "postcode", "Postleitzahl"));
translations.add(new Translation(localeDe, "email-notice", "Ihre E-Mail {0} wurde registriert."));
translations.add(new Translation(localeDe, "default-message", "Das ist ein Standardtext."));
translations.add(new Translation(localeDe, "headline", "Zahlung", "payment"));
translations.add(new Translation(localeDe, "expiry_date", "Ablaufdatum", "payment"));

return new BaseTranslationMessageSource(
CatalogHandler
.builder(
new Catalog(
translations,
Locale.forLanguageTag("en")
)
)
.build()
);
}


@ParameterizedTest()
@MethodSource("dataProvider_examples")
void test_example(String code, String locale, Object expected, Object[] args) {
String message = this.messageSource.getMessage(
code,
args,
Locale.forLanguageTag(locale)
);
assertEquals(expected, message);
}

private static Stream<Arguments> dataProvider_examples() {
return Stream.of(
Arguments.of("headline", "en", "Headline", null),
Arguments.of("messages.headline", "en", "Headline", null),
Arguments.of("postcode", "en", "Postcode", null),
Arguments.of("messages.postcode", "en", "Postcode", null),
Arguments.of("email-notice", "en", "Your email foo@example.com has been registered.", new Object[] {"foo@example.com"}),
Arguments.of("messages.email-notice", "en", "Your email foo@example.com has been registered.", new Object[] {"foo@example.com"}),
Arguments.of("default-message", "en", "This is a default message.", null),
Arguments.of("messages.default-message", "en", "This is a default message.", null),
Arguments.of("payment.headline", "en", "Payment", null),
Arguments.of("payment.expiry_date", "en", "Expiry date", null),

Arguments.of("headline", "en-US", "Headline", null),
Arguments.of("messages.headline", "en-US", "Headline", null),
Arguments.of("postcode", "en-US", "Zip code", null),
Arguments.of("messages.postcode", "en-US", "Zip code", null),
Arguments.of("email-notice", "en-US", "Your email foo@example.com has been registered.", new Object[] {"foo@example.com"}),
Arguments.of("messages.email-notice", "en-US", "Your email foo@example.com has been registered.", new Object[] {"foo@example.com"}),
Arguments.of("default-message", "en-US", "This is a default message.", null),
Arguments.of("messages.default-message", "en-US", "This is a default message.", null),
Arguments.of("payment.headline", "en-US", "Payment", null),
Arguments.of("payment.expiry_date", "en-US", "Expiration date", null),

Arguments.of("headline", "de", "Überschrift", null),
Arguments.of("messages.headline", "de", "Überschrift", null),
Arguments.of("postcode", "de", "Postleitzahl", null),
Arguments.of("messages.postcode", "de", "Postleitzahl", null),
Arguments.of("email-notice", "de", "Ihre E-Mail foo@example.com wurde registriert.", new Object[] {"foo@example.com"}),
Arguments.of("messages.email-notice", "de", "Ihre E-Mail foo@example.com wurde registriert.", new Object[] {"foo@example.com"}),
Arguments.of("default-message", "de", "Das ist ein Standardtext.", null),
Arguments.of("messages.default-message", "de", "Das ist ein Standardtext.", null),
Arguments.of("payment.headline", "de", "Zahlung", null),
Arguments.of("payment.expiry_date", "de", "Ablaufdatum", null),

Arguments.of("headline", "jp", "Headline", null),
Arguments.of("messages.headline", "jp", "Headline", null),
Arguments.of("postcode", "jp", "Postcode", null),
Arguments.of("messages.postcode", "jp", "Postcode", null),
Arguments.of("email-notice", "jp", "Your email foo@example.com has been registered.", new Object[] {"foo@example.com"}),
Arguments.of("messages.email-notice", "jp", "Your email foo@example.com has been registered.", new Object[] {"foo@example.com"}),
Arguments.of("default-message", "jp", "This is a default message.", null),
Arguments.of("messages.default-message", "jp", "This is a default message.", null),
Arguments.of("payment.headline", "jp", "Payment", null),
Arguments.of("payment.expiry_date", "jp", "Expiry date", null)
);
}
}

0 comments on commit 4c3954d

Please sign in to comment.