diff --git a/src/main/java/cz/cvut/kbss/termit/service/MessageFormatter.java b/src/main/java/cz/cvut/kbss/termit/service/MessageFormatter.java new file mode 100644 index 000000000..10b147a60 --- /dev/null +++ b/src/main/java/cz/cvut/kbss/termit/service/MessageFormatter.java @@ -0,0 +1,48 @@ +package cz.cvut.kbss.termit.service; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.lang.NonNull; + +import java.text.MessageFormat; +import java.util.Locale; +import java.util.MissingResourceException; +import java.util.Objects; +import java.util.ResourceBundle; + +/** + * Formats internationalized messages. + *
+ * The message bundles should be located in {@code src/main/resources/i18n} and be called {@code messages}. + */ +public class MessageFormatter { + + private static final Logger LOG = LoggerFactory.getLogger(MessageFormatter.class); + + private final ResourceBundle messages; + + public MessageFormatter(@NonNull String lang) { + Objects.requireNonNull(lang); + final Locale locale = new Locale(lang); + this.messages = ResourceBundle.getBundle("i18n/messages", locale); + LOG.info("Loaded message bundle '{}_{}'.", messages.getBaseBundleName(), locale); + } + + /** + * Formats message with the specified identifier using the specified parameters. + * + * @param messageId Message identifier + * @param params Parameters to substitute into the message string + * @return Formatted message + */ + public String formatMessage(@NonNull String messageId, Object... params) { + Objects.requireNonNull(messageId); + try { + final MessageFormat formatter = new MessageFormat(messages.getString(messageId)); + return formatter.format(params); + } catch (MissingResourceException e) { + LOG.error("No message found for message id '{}'. Returning the message id.", messageId, e); + return messageId; + } + } +} diff --git a/src/main/java/cz/cvut/kbss/termit/service/repository/VocabularyRepositoryService.java b/src/main/java/cz/cvut/kbss/termit/service/repository/VocabularyRepositoryService.java index d00b5c125..71c2c51bb 100644 --- a/src/main/java/cz/cvut/kbss/termit/service/repository/VocabularyRepositoryService.java +++ b/src/main/java/cz/cvut/kbss/termit/service/repository/VocabularyRepositoryService.java @@ -28,16 +28,19 @@ import cz.cvut.kbss.termit.model.Glossary; import cz.cvut.kbss.termit.model.Model; import cz.cvut.kbss.termit.model.Vocabulary; +import cz.cvut.kbss.termit.model.resource.Document; import cz.cvut.kbss.termit.model.validation.ValidationResult; import cz.cvut.kbss.termit.persistence.dao.BaseAssetDao; import cz.cvut.kbss.termit.persistence.dao.VocabularyDao; import cz.cvut.kbss.termit.persistence.dao.skos.SKOSImporter; import cz.cvut.kbss.termit.service.IdentifierResolver; +import cz.cvut.kbss.termit.service.MessageFormatter; import cz.cvut.kbss.termit.service.snapshot.SnapshotProvider; import cz.cvut.kbss.termit.util.Configuration; import cz.cvut.kbss.termit.util.Constants; import cz.cvut.kbss.termit.util.Utils; import cz.cvut.kbss.termit.workspace.EditableVocabularies; +import jakarta.validation.Validator; import org.apache.tika.Tika; import org.apache.tika.metadata.Metadata; import org.apache.tika.metadata.TikaCoreProperties; @@ -52,11 +55,14 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.MultipartFile; -import jakarta.validation.Validator; import java.io.IOException; import java.net.URI; import java.time.Instant; -import java.util.*; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Objects; +import java.util.Set; import java.util.stream.Collectors; @CacheConfig(cacheNames = "vocabularies") @@ -137,6 +143,7 @@ protected void prePersist(@NotNull Vocabulary instance) { } verifyIdentifierUnique(instance); initGlossaryAndModel(instance); + initDocument(instance); if (instance.getDocument() != null) { instance.getDocument().setVocabulary(null); } @@ -154,6 +161,19 @@ private void initGlossaryAndModel(Vocabulary vocabulary) { } } + private void initDocument(Vocabulary vocabulary) { + if (vocabulary.getDocument() != null) { + return; + } + final Document doc = new Document(); + doc.setUri(idResolver.generateIdentifier(vocabulary.getUri().toString(), + Constants.DEFAULT_DOCUMENT_IRI_COMPONENT)); + doc.setLabel( + new MessageFormatter(config.getPersistence().getLanguage()).formatMessage("vocabulary.document.label", + vocabulary.getLabel())); + vocabulary.setDocument(doc); + } + @Override protected void preUpdate(@NotNull Vocabulary instance) { super.preUpdate(instance); diff --git a/src/main/java/cz/cvut/kbss/termit/util/Constants.java b/src/main/java/cz/cvut/kbss/termit/util/Constants.java index 2468b1d12..c33e0969c 100644 --- a/src/main/java/cz/cvut/kbss/termit/util/Constants.java +++ b/src/main/java/cz/cvut/kbss/termit/util/Constants.java @@ -65,8 +65,8 @@ public class Constants { /** * Path to directory containing queries used by the system. *
- * The path should be relative to the classpath, so that queries from it can be loaded using {@link - * ClassLoader#getResourceAsStream(String)}. + * The path should be relative to the classpath, so that queries from it can be loaded using + * {@link ClassLoader#getResourceAsStream(String)}. */ public static final String QUERY_DIRECTORY = "query"; @@ -88,9 +88,16 @@ public class Constants { */ public static final String DEFAULT_MODEL_IRI_COMPONENT = "model"; + /** + * Default identifier component for {@link cz.cvut.kbss.termit.model.resource.Document}. + *
+ * This component is appended to the containing vocabulary identifier to form the document identifier. + */ + public static final String DEFAULT_DOCUMENT_IRI_COMPONENT = "document"; + /** * Default language when none is specified in configuration. - * + *
* Used mainly for resolving internationalized templates.
*/
public static final String DEFAULT_LANGUAGE = "en";
diff --git a/src/main/resources/i18n/messages_cs.properties b/src/main/resources/i18n/messages_cs.properties
new file mode 100644
index 000000000..40f0c75ae
--- /dev/null
+++ b/src/main/resources/i18n/messages_cs.properties
@@ -0,0 +1 @@
+vocabulary.document.label=Dokument pro {0}
diff --git a/src/main/resources/i18n/messages_en.properties b/src/main/resources/i18n/messages_en.properties
new file mode 100644
index 000000000..105c6c25c
--- /dev/null
+++ b/src/main/resources/i18n/messages_en.properties
@@ -0,0 +1 @@
+vocabulary.document.label=Document for {0}
diff --git a/src/test/java/cz/cvut/kbss/termit/service/MessageFormatterTest.java b/src/test/java/cz/cvut/kbss/termit/service/MessageFormatterTest.java
new file mode 100644
index 000000000..a4aee2eb4
--- /dev/null
+++ b/src/test/java/cz/cvut/kbss/termit/service/MessageFormatterTest.java
@@ -0,0 +1,40 @@
+package cz.cvut.kbss.termit.service;
+
+import cz.cvut.kbss.termit.environment.Environment;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+import java.util.stream.Stream;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+class MessageFormatterTest {
+
+ @ParameterizedTest
+ @MethodSource("i18nFormattingValues")
+ void formatsMessageWithSpecifiedIdUsingSpecifiedValues(String language, String expectedMessage) {
+ final MessageFormatter sut = new MessageFormatter(language);
+ final String vocabularyLabel = "Test";
+ assertEquals(expectedMessage, sut.formatMessage("vocabulary.document.label", vocabularyLabel));
+ }
+
+ static Stream