org.nuiton.i18n.I18nDefinitionFile Maven / Gradle / Ivy
The newest version!
package org.nuiton.i18n;
/*-
* #%L
* I18n :: Api
* %%
* Copyright (C) 2004 - 2017 Code Lutin, Ultreia.io
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Lesser Public License for more details.
*
* You should have received a copy of the GNU General Lesser Public
* License along with this program. If not, see
* .
* #L%
*/
import com.google.common.base.Joiner;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Multimap;
import io.ultreia.java4all.util.SortedProperties;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.io.IOUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.nuiton.version.Version;
import org.nuiton.version.Versions;
import java.io.BufferedWriter;
import java.io.Closeable;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Date;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Properties;
import java.util.Set;
import java.util.TreeMap;
import java.util.stream.Collectors;
/**
* Created by tchemit on 09/07/17.
*
* @author Tony Chemit - [email protected]
* @since 3.7
*/
public class I18nDefinitionFile implements Closeable {
/** Logger. */
private static final Logger log = LogManager.getLogger(I18nDefinitionFile.class);
private static final String ENTRY_VERSION = "version";
private static final String ENTRY_ENCODING = "encoding";
private static final String ENTRY_LOCALES = "locales";
private static final String ENTRY_TEMPLATE_EXTENSION = "template.extension";
private static final String ENTRY_TEMPLATE_LIST = "template.list";
private static final String ENTRY_BUNDLE_PREFIX = "bundles.";
private static final String ENTRY_KEY_CATEGORIES = "key.categories";
private static final String SUFFIX_DEFINITION_PROPERTIES = "-definition.properties";
private final String name;
private final Version version;
private final Set locales;
private final String templateExtension;
private final Set templateList;
private final Map keyCategories;
private final Multimap bundles;
private final Map propertiesCache;
private final Map contentCache;
private String urlPrefix;
private Charset encoding;
private HashMultimap translationKeys;
public I18nDefinitionFile(String name,
Charset encoding,
Version version,
Set locales,
String templateExtension,
Set templateList,
Map keyCategories,
Multimap bundles) {
this.name = name;
this.encoding = encoding;
this.version = version;
this.locales = locales;
this.templateExtension = templateExtension;
this.templateList = templateList;
this.keyCategories = keyCategories;
this.bundles = bundles;
this.propertiesCache = new TreeMap<>();
this.contentCache = new TreeMap<>();
}
public I18nDefinitionFile(URL url) throws IOException, NullPointerException {
Objects.requireNonNull(url);
propertiesCache = new TreeMap<>();
contentCache = new TreeMap<>();
InputStream inputStream = url.openStream();
if (inputStream == null) {
throw new IllegalArgumentException(String.format("Url [%s] does not exists.", url));
}
String i18nBundleUrlPrefix = url.toString().replace(SUFFIX_DEFINITION_PROPERTIES, "");
name = i18nBundleUrlPrefix.substring(url.toString().lastIndexOf("/") + 1);
urlPrefix = i18nBundleUrlPrefix.substring(0, url.toString().lastIndexOf("/") + 1);
Properties i18nProperties = loadProperties(url);
encoding = Charset.forName(i18nProperties.getProperty(ENTRY_ENCODING));
version = Versions.valueOf(i18nProperties.getProperty(ENTRY_VERSION));
templateExtension = i18nProperties.getProperty(ENTRY_TEMPLATE_EXTENSION);
String templatesListStr = i18nProperties.getProperty(ENTRY_TEMPLATE_LIST);
ImmutableSet.Builder templateNamesBuilder = ImmutableSet.builder();
if (templatesListStr != null) {
for (String templateName : templatesListStr.split(",")) {
templateNamesBuilder.add(templateName.trim());
}
}
templateList = templateNamesBuilder.build();
String keyCategoriesStr = i18nProperties.getProperty(ENTRY_KEY_CATEGORIES);
ImmutableMap.Builder keyCategoriesBuilder = ImmutableMap.builder();
if (keyCategoriesStr != null) {
for (String templateName : keyCategoriesStr.split(",")) {
String[] parts = templateName.split("=");
keyCategoriesBuilder.put(parts[0].trim(), parts[1].trim());
}
}
keyCategories = keyCategoriesBuilder.build();
ImmutableSet.Builder localesBuilder = ImmutableSet.builder();
bundles = ArrayListMultimap.create();
for (String localeStr : ((String) i18nProperties.get(ENTRY_LOCALES)).split(",")) {
String[] split = localeStr.split("_");
Locale locale = new Locale(split[0], split[1]);
localesBuilder.add(locale);
String bundleList = (String) i18nProperties.get(ENTRY_BUNDLE_PREFIX + locale.getLanguage() + "_" + locale.getCountry());
for (String bundle : bundleList.split(",")) {
bundles.put(locale, bundle.trim());
}
}
locales = localesBuilder.build();
}
public URL getDefinitionFileURL() {
return url(urlPrefix + name + SUFFIX_DEFINITION_PROPERTIES);
}
public URL getMainBundleURL(Locale locale) {
return url(urlPrefix + String.format("%s_%s_%s.properties", name, locale.getLanguage(), locale.getCountry()));
}
public Map getKeyCategories() {
return keyCategories;
}
public Optional getTemplateURL(String templateName, Locale locale) {
URL url;
if (templateName.startsWith("classpath:")) {
String urlStart = String.format("/%s/%s_%s.%s", templateExtension, templateName.substring("classpath:".length()), locale.getLanguage(), templateExtension);
url = getClass().getResource(urlStart);
if (url == null && locale.equals(locales.iterator().next())) {
urlStart = String.format("/%s/%s.%s", templateExtension, templateName.substring("classpath:".length()), templateExtension);
url = Objects.requireNonNull(getClass().getResource(urlStart));
}
} else {
url = url(urlPrefix + String.format("%s/%s_%s.%s", templateExtension, templateName, locale.getLanguage(), templateExtension));
}
try {
InputStream inputStream = url.openStream();
try {
if (inputStream == null) {
url = null;
}
} finally {
if (inputStream != null) {
inputStream.close();
}
}
} catch (IOException e) {
throw new IllegalStateException(e);
}
return Optional.ofNullable(url);
}
public URL getBundleURL(String bundleName) {
return getClass().getClassLoader().getResource(bundleName);
}
private URL url(String suffix) {
try {
return new URL(suffix);
} catch (MalformedURLException e) {
throw new IllegalStateException(e);
}
}
private Properties loadProperties(URL url) {
Objects.requireNonNull(url);
return propertiesCache.computeIfAbsent(url.toString(), u -> {
log.info("Loading " + url);
Properties p = new Properties();
try (Reader inputStream = new InputStreamReader(url.openStream(), encoding == null ? StandardCharsets.UTF_8 : encoding)) {
p.load(inputStream);
} catch (IOException e) {
throw new IllegalStateException("Can't load properties at: " + url, e);
}
return p;
});
}
private String loadContent(URL url) {
Objects.requireNonNull(url);
return contentCache.computeIfAbsent(url.toString(), u -> {
log.info("Loading " + url);
try {
return IOUtils.toString(url, encoding);
} catch (IOException e) {
throw new IllegalStateException("Can't load properties at: " + url, e);
}
});
}
public void store(File directory) throws IOException {
Joiner joiner = Joiner.on(",");
SortedProperties p = new SortedProperties();
p.put(ENTRY_VERSION, version.toString());
p.put(ENTRY_ENCODING, encoding.toString());
p.put(ENTRY_LOCALES, joiner.join(locales));
if (templateExtension != null) {
p.put(ENTRY_TEMPLATE_EXTENSION, templateExtension);
}
if (CollectionUtils.isNotEmpty(templateList)) {
p.put(ENTRY_TEMPLATE_LIST, joiner.join(templateList));
}
if (!keyCategories.isEmpty()) {
p.put(ENTRY_KEY_CATEGORIES, joiner.join(keyCategories.entrySet().stream().map(e -> e.getKey() + "=" + e.getValue()).collect(Collectors.toList())));
}
for (Locale locale : locales) {
p.put("bundles." + locale.getLanguage() + "_" + locale.getCountry(), joiner.join(bundles.get(locale)));
}
Path target = directory.toPath().resolve(String.format("%s%s", name, SUFFIX_DEFINITION_PROPERTIES));
log.info("Store definition file to " + target);
try (BufferedWriter writer = Files.newBufferedWriter(target)) {
p.store(writer, "Generated by " + getClass().getName() + " at " + new Date());
}
}
public String getName() {
return name;
}
public Version getVersion() {
return version;
}
public Set getLocales() {
return locales;
}
public String getTemplateExtension() {
return templateExtension;
}
public Set getTemplateList() {
return templateList;
}
public Properties getMainBundle(Locale locale) {
return loadProperties(getMainBundleURL(locale));
}
public HashMultimap getTranslationKeys() {
if (translationKeys == null) {
translationKeys = HashMultimap.create();
for (Locale locale : locales) {
Properties properties = loadProperties(getMainBundleURL(locale));
properties.keySet().forEach(o -> {
translationKeys.put(null, (String) o);
translationKeys.put(locale, (String) o);
});
}
}
return translationKeys;
}
public Multimap getBundles() {
return bundles;
}
public String getTemplateContent(String templateName, Locale locale) {
return getTemplateURL(templateName, locale).map(this::loadContent).orElse(null);
}
@Override
public void close() {
contentCache.clear();
propertiesCache.clear();
translationKeys = null;
}
public Charset getEncoding() {
return encoding;
}
public String getMainBundleFilename(Locale locale) {
return String.format("%s_%s_%s.properties", getName(), locale.getLanguage(), locale.getCountry());
}
public String getTemplateFilename(Locale locale, String templateName) {
return String.format("%s/%s_%s.%s", getTemplateExtension(), templateName, locale.getLanguage(), getTemplateExtension());
}
public Properties getBundle(String bundleName) {
return loadProperties(getBundleURL(bundleName));
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy