/** * *************************************************************************** * Copyright (c) 2010 Qcadoo Limited * Project: Qcadoo Framework * Version: 1.4 * * This file is part of Qcadoo. * * Qcadoo is free software; you can redistribute it and/or modify * it under the terms of the GNU Affero 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * *************************************************************************** */ package com.qcadoo.localization.internal; import java.io.IOException; import java.io.InputStream; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Properties; import java.util.Set; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.MessageSource; import org.springframework.core.io.Resource; import org.springframework.stereotype.Service; import com.google.common.collect.Lists; import org.springframework.context.support.ReloadableResourceBundleMessageSource; @Service public final class TranslationServiceImpl implements InternalTranslationService { private static final Logger LOG = LoggerFactory.getLogger(TranslationServiceImpl.class); private static final Logger TRANSLATION_LOG = LoggerFactory.getLogger("TRANSLATION"); private static final Map<String, Set<String>> GROUP_MESSAGES = new HashMap<>(); @Value("${ignoreMissingTranslations}") private boolean ignoreMissingTranslations; private long lastHotDeployClearCache; private final Map<String, String> locales = new HashMap<>(); @Autowired private MessageSource messageSource; @Autowired private TranslationModuleService translationModuleService; @Autowired private ConfigUtil configUtil; @Override public String translate(final String code, final Locale locale, final String... args) { String message = translateWithError(code, locale, args); if (message != null) { return message.trim(); } TRANSLATION_LOG.warn("Missing translation " + code + " for locale " + locale); if (ignoreMissingTranslations) { return DEFAULT_MISSING_MESSAGE; } else { return code; } } private String translate(final List<String> messageCodes, final Locale locale, final String... args) { for (String messageCode : messageCodes) { String message = translateWithError(messageCode, locale, args); if (message != null) { return message.trim(); } } TRANSLATION_LOG.warn("Missing translation " + messageCodes + " for locale " + locale); if (ignoreMissingTranslations) { return DEFAULT_MISSING_MESSAGE; } else { return messageCodes.toString(); } } @Override public String translate(final String code, final String secondCode, final Locale locale, final String... args) { return translate(Lists.newArrayList(code, secondCode), locale, args); } @Override public String translate(final String code, final String secondCode, final String thirdCode, final Locale locale, final String... args) { return translate(Lists.newArrayList(code, secondCode, thirdCode), locale, args); } private String translateWithError(final String messageCode, final Locale locale, final String[] args) { if (configUtil.isHotDeploy() && this.messageSource instanceof ReloadableResourceBundleMessageSource) { ReloadableResourceBundleMessageSource reloadableResourceBundleMessageSource = (ReloadableResourceBundleMessageSource) this.messageSource; if ((System.currentTimeMillis() - lastHotDeployClearCache) >= 2500) { reloadableResourceBundleMessageSource.clearCache(); lastHotDeployClearCache = System.currentTimeMillis(); } return reloadableResourceBundleMessageSource.getMessage(messageCode, args, null, locale); } else { return messageSource.getMessage(messageCode, args, null, locale); } } @Override public Map<String, String> getMessagesGroup(final String group, final Locale locale) { if (!GROUP_MESSAGES.containsKey(group)) { return Collections.emptyMap(); } Map<String, String> commonsTranslations = new HashMap<>(); for (String commonMessage : GROUP_MESSAGES.get(group)) { commonsTranslations.put(commonMessage, translate(commonMessage, locale)); } return commonsTranslations; } @Override public void prepareMessagesGroup(final String group, final String prefix) { Set<String> messages = new HashSet<>(); GROUP_MESSAGES.put(group, messages); getMessagesByPrefix(prefix, messages); } private void getMessagesByPrefix(final String prefix, final Set<String> messages) { try { for (Resource resource : translationModuleService.getLocalizationResources()) { getMessagesByPrefix(prefix, messages, resource.getInputStream()); } } catch (IOException e) { LOG.error("Can not read messages file", e); } LOG.info("Messages for " + prefix + ": " + messages); } private void getMessagesByPrefix(final String prefix, final Set<String> messages, final InputStream inputStream) throws IOException { Properties properties = new Properties(); properties.load(inputStream); for (Object property : properties.keySet()) { if (String.valueOf(property).startsWith(prefix)) { messages.add((String) property); } } } @Override public void addLocaleToList(final String locale, final String label) { locales.put(locale, label); } @Override public void removeLocaleToList(final String locale) { locales.remove(locale); } @Override public Map<String, String> getLocales() { return locales; } }