/**
* <a href="http://www.openolat.org">
* OpenOLAT - Online Learning and Training</a><br>
* <p>
* Licensed under the Apache License, Version 2.0 (the "License"); <br>
* you may not use this file except in compliance with the License.<br>
* You may obtain a copy of the License at the
* <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
* <p>
* Unless required by applicable law or agreed to in writing,<br>
* software distributed under the License is distributed on an "AS IS" BASIS, <br>
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
* See the License for the specific language governing permissions and <br>
* limitations under the License.
* <p>
* Initial code contributed and copyrighted by<br>
* frentix GmbH, http://www.frentix.com
* <p>
*/
package org.olat.core.util.i18n;
import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import org.olat.core.configuration.AbstractOLATModule;
import org.olat.core.configuration.Destroyable;
import org.olat.core.configuration.PersistedProperties;
import org.olat.core.gui.control.Event;
import org.olat.core.helpers.Settings;
import org.olat.core.id.OLATResourceable;
import org.olat.core.logging.OLATRuntimeException;
import org.olat.core.logging.OLog;
import org.olat.core.logging.Tracing;
import org.olat.core.util.ArrayHelper;
import org.olat.core.util.StringHelper;
import org.olat.core.util.WebappHelper;
import org.olat.core.util.coordinate.CoordinatorManager;
import org.olat.core.util.resource.OresHelper;
/**
* <h3>Description:</h3> The I18nModule initializes the localization
* infrastructure. It offers configuration options to define the default
* language, the available and enabled languages etc.
* <p>
* Initial Date: 28.08.2008 <br>
*
* @author Florian Gnaegi, frentix GmbH, http://www.frentix.com
*/
public class I18nModule extends AbstractOLATModule implements Destroyable {
private static final OLog log = Tracing.createLoggerFor(I18nModule.class);
// Some general variables
public static final String LOCAL_STRINGS_FILE_PREFIX = "LocalStrings_";
public static final String LOCAL_STRINGS_FILE_POSTFIX = ".properties";
// Location of customizing directory and i18n configuration (configured at
// runtime)
public static File LANG_CUSTOMIZING_DIRECTORY;
public static File LANG_PACKS_DIRECTORY;
public static File LANG_OVERLAY_DIRECTORY;
// Constants for the translation statistics scheduler job
public static final String SCHEDULER_NAME = "i18n.status.generator";
// User GUI prefs keys
public static final String GUI_PREFS_PREFERRED_COMPARE_LANG = "REFERRED_COMPARE_LANG";
public static final String GUI_PREFS_PREFERRED_REFERENCE_LANG = "PREFERRED_REFERENCE_LANG";
public static final String GUI_PREFS_COMPARE_LANG_ENABLED = "COMPARE_LANG_ENABLED";
public static final String GUI_PREFS_INLINE_TRANSLATION_ENABLED = "INLINE_TRANSLATION_ENABLED";
// Configuration parameter read from i18nmanager spring file (configured at system
// setup time)
private static final String CONFIG_LANGUAGES_ENABLED = "enabledLanguages";
private static final String CONFIG_LANGUAGES_ENABLED_ALL = "all";
private static final String CONFIG_DEFAULT_LANG = "defaultLanguage";
private static final String CONFIG_FALLBACK_LANG = "fallbackLanguage";
private static final String CONFIG_LANGUAGES_REFERENCES = "transToolReferenceLanguages";
private static final String CONFIG_OVERLAY = "overlayName";
private static final String CONFIG_OVERLAY_ENABLED = "overlayEnabled";
private static final String CONFIG_CACHING_ENABLED = "cachingEnabled";
private static final String CONFIG_LANGUAGE_LIST_ENABLED = "dropDownListEnabled";
private static final String CONFIG_APPLICATION_FALLBACK_BUNDLE = "applicationFallbackBundle";
private static final String CONFIG_CORE_FALLBACK_BUNDLE = "coreFallbackBundle";
private static final String CONFIG_TRANS_TOOL_ENABLED = "transToolEnabled";
private static final String CONFIG_TRANS_TOOL_APPLICATION_SRC_PATH = "transToolApplicationSrcPath";
private static final String CONFIG_TRANS_TOOL_APPLICATION_OPT_SRC_PATH = "transToolApplicationOptSrcPath";
// General configuration
private static String overlayName;
private static boolean overlayEnabled;
private static boolean cachingEnabled;
private static boolean languageDropDownListEnabled;
// Lists of the available and enabled languages and locales
private static final Set<String> availableLanguages = new HashSet<String>();
private static final Set<String> translatableLanguages = new HashSet<String>();
private static final Map<String, File> translatableLangAppBaseDirLookup = new HashMap<String, File>();
// keys: lang string, values: locale
private static final Map<String, Locale> allLocales = new HashMap<String, Locale>();
// keys: orig Locale, values: overlay Locale
private static final Map<Locale, Locale> overlayLocales = new HashMap<Locale, Locale>();
private static final Set<String> overlayLanguagesKeys = new HashSet<String>();
private static final Set<String> enabledLanguagesKeys = new HashSet<String>();
// The default locale (used on loginscreen and as first fallback) and the
// fallback (used as second fallback)
private static Locale defaultLocale;
private static Locale fallbackLocale;
// The available bundles
private static List<String> bundleNames = null; // sorted alphabetically
private static String coreFallbackBundle = null;
private static String applicationFallbackBundle = null;
// Translation tool related configuration
private static final List<String> transToolReferenceLanguages = new ArrayList<String>();
private static File transToolApplicationLanguagesDir = null;
private static File transToolApplicationOptLanguagesSrcDir = null;
private static boolean transToolEnabled = false;
// When running on a cluster, we need an event when flushing the i18n cache to do this on all machines
private static OLATResourceable I18N_CACHE_FLUSHED_EVENT_CHANNEL;
// Reference to instance for static methods
private static I18nModule INSTANCE;
private CoordinatorManager coordinatorManager;
/**
* [spring]
*/
private I18nModule(CoordinatorManager coordinatorManager) {
super();
this.coordinatorManager = coordinatorManager;
//if (INSTANCE != null && !Settings.isJUnitTest()) { throw new OLATRuntimeException("Tried to construct I18nModule, but module was already loaded!", null); }
INSTANCE = this;
}
@Override
protected void initDefaultProperties() {
// First read default configuration from the module config and then set
// is as default in the properties
String defaultLanguageKey = getStringConfigParameter(CONFIG_DEFAULT_LANG, "en", false);
setStringPropertyDefault(CONFIG_DEFAULT_LANG, defaultLanguageKey);
String enabledLanguagesConfig = getStringConfigParameter(CONFIG_LANGUAGES_ENABLED, CONFIG_LANGUAGES_ENABLED_ALL, false);
setStringPropertyDefault(CONFIG_LANGUAGES_ENABLED, enabledLanguagesConfig);
}
@Override
protected void initFromChangedProperties() {
doReInitialize();
}
/**
* @see org.olat.core.configuration.AbstractOLATModule#init()
*/
@Override
public void init() {
// Check that necessary directories are there
LANG_CUSTOMIZING_DIRECTORY = new File(WebappHelper.getUserDataRoot() + "/customizing/lang/");
LANG_PACKS_DIRECTORY = new File(LANG_CUSTOMIZING_DIRECTORY, "/packs/");
LANG_OVERLAY_DIRECTORY = new File(LANG_CUSTOMIZING_DIRECTORY, "/overlay/");
LANG_CUSTOMIZING_DIRECTORY.mkdirs();
LANG_OVERLAY_DIRECTORY.mkdirs();
LANG_PACKS_DIRECTORY.mkdirs();
// Initialize configuration
doInit();
// Register on the event channel to get cache flushes of other nodes
I18N_CACHE_FLUSHED_EVENT_CHANNEL = OresHelper.createOLATResourceableType(this.getClass().getSimpleName() + "I18N_CACHE_FLUSHED_EVENT_CHANNEL");
coordinatorManager.getCoordinator().getEventBus().registerFor(this, null, I18N_CACHE_FLUSHED_EVENT_CHANNEL);
if(isTransToolEnabled()) {
String sourcePath = WebappHelper.getSourcePath();
if(!StringHelper.containsNonWhitespace(sourcePath) || !(new File(sourcePath).exists())) {
log.error("Path to source wrong, translation tool may not work as expected: " + sourcePath, null);
}
}
}
private void doInit() {
// A) Initialize system configuration from config file - those values
// can't be changed at runtime and are project specific
// Set configured reference languages
String referenceLanguagesConfig = getStringConfigParameter(CONFIG_LANGUAGES_REFERENCES, "en", false);
String[] referenceAndFallbackKeys = referenceLanguagesConfig.split(",");
// remove whitespace and check for douplicates
for (int i = 0; i < referenceAndFallbackKeys.length; i++) {
String langKey = referenceAndFallbackKeys[i];
langKey = langKey.trim();
transToolReferenceLanguages.add(langKey);
}
// Language overlay: used to override a language with some custom wording
overlayName = getStringConfigParameter(CONFIG_OVERLAY, "customizing", false);
overlayEnabled = getBooleanConfigParameter(CONFIG_OVERLAY_ENABLED, true);
// Set caching configuration of local strings
cachingEnabled = getBooleanConfigParameter(CONFIG_CACHING_ENABLED, true);
logInfo("Localization caching set to: " + cachingEnabled, null);
// Set how the list of available availableLanguages will be shown
// (drop-down[true] or in one line[false])
languageDropDownListEnabled = getBooleanConfigParameter(CONFIG_LANGUAGE_LIST_ENABLED, true);
logInfo("Configuring 'dropDownListEnabled = " + languageDropDownListEnabled + "'", null);
// Set additional source path to load languages from and to store
// languages when using the translation tool. Init the values even when transtool is not configured for development mode
String appSrc = getStringConfigParameter(CONFIG_TRANS_TOOL_APPLICATION_SRC_PATH, "", false);
if (StringHelper.containsNonWhitespace(appSrc)) {
appSrc = appSrc.trim();
transToolApplicationLanguagesDir = new File(appSrc);
}
String optAppSrc = getStringConfigParameter(CONFIG_TRANS_TOOL_APPLICATION_OPT_SRC_PATH, "", false);
if (StringHelper.containsNonWhitespace(optAppSrc)) {
optAppSrc = optAppSrc.trim();
transToolApplicationOptLanguagesSrcDir = new File(optAppSrc);
}
// Enable or disable translation tool and i18n source directories
transToolEnabled = getBooleanConfigParameter(CONFIG_TRANS_TOOL_ENABLED, false);
if (transToolEnabled) {
//
if (transToolApplicationLanguagesDir != null && transToolApplicationOptLanguagesSrcDir != null) {
// Check if configuration is valid, otherwise disable translation server mode
} else {
// disable, pathes not configured properly
transToolEnabled = false;
}
// error handling, notify on console about disabled translation tool
if (!transToolEnabled) {
logWarn(
"Translation configuration enabled but invalid translation tool source path defined. Disabling translation tool. Fix your configuration in spring config of i18Module",
null);
logWarn(" transToolApplicationSrcPath::" + appSrc + " transToolApplicationI18nSrcPath::" + optAppSrc, null);
}
}
I18nManager i18nMgr = I18nManager.getInstance();
i18nMgr.setCachingEnabled(cachingEnabled);
// Get all bundles that contain i18n files
initBundleNames();
// Set the base bundles for olatcore and the application. When a key is
// not found, the manager looks it up in the application base and the in
// the core base bundle before it gives up
applicationFallbackBundle = getStringConfigParameter(CONFIG_APPLICATION_FALLBACK_BUNDLE, "org.olat", false);
coreFallbackBundle = getStringConfigParameter(CONFIG_CORE_FALLBACK_BUNDLE, "org.olat.core", false);
// Search for all available languages on the build path and initialize them
doInitAvailableLanguages();
// B) Initialize default language and the list of enabled languages from
// the persisted system configuration
doInitLanguageConfiguration();
logInfo("Configured i18nModule with default language::" + getDefaultLocale().toString() + " and the reference languages '"
+ referenceLanguagesConfig + "' and the following enabled languages: " + enabledLanguagesKeys.toString(), null);
}
/**
*
* @see org.olat.core.configuration.Destroyable#destroy()
*/
public void destroy() {
// remove from event channel
if (I18N_CACHE_FLUSHED_EVENT_CHANNEL != null) {
coordinatorManager.getCoordinator().getEventBus().deregisterFor(this, I18N_CACHE_FLUSHED_EVENT_CHANNEL);
I18N_CACHE_FLUSHED_EVENT_CHANNEL = null;
}
}
/**
* Initialize the available languages and load all locales
*/
private void doInitAvailableLanguages() {
I18nManager i18nMgr = I18nManager.getInstance();
// Search all availableLanguages files that exist
String i18nDirRelPath = File.separator + applicationFallbackBundle.replace(".", File.separator) + File.separator + I18nManager.I18N_DIRNAME;
if (transToolApplicationLanguagesDir != null) {
File coreSrcI18nDir = new File(transToolApplicationLanguagesDir, i18nDirRelPath);
if (coreSrcI18nDir.exists()) {
for (String languageCode : i18nMgr.searchForAvailableLanguages(transToolApplicationLanguagesDir)) {
if (availableLanguages.contains(languageCode)) {
String path = "";
if (transToolApplicationOptLanguagesSrcDir != null) path = transToolApplicationOptLanguagesSrcDir.getAbsolutePath();
logDebug("Skipping duplicate or previously loaded language::" + languageCode + " found in " +path , null);
continue;
}
logDebug("Detected translatable language " + languageCode + " in " + transToolApplicationLanguagesDir.getAbsolutePath(), null);
availableLanguages.add(languageCode);
translatableLanguages.add(languageCode);
translatableLangAppBaseDirLookup.put(languageCode, transToolApplicationLanguagesDir);
}
}
}
// 2) Add languages from the translation tool source path
if (isTransToolEnabled()) {
for (String languageCode : i18nMgr.searchForAvailableLanguages(transToolApplicationOptLanguagesSrcDir)) {
if (availableLanguages.contains(languageCode)) {
logDebug("Skipping duplicate or previously loaded language::" + languageCode + " found in " + transToolApplicationOptLanguagesSrcDir.getAbsolutePath(), null);
continue;
}
logDebug("Detected translatable language " + languageCode + " in " + transToolApplicationOptLanguagesSrcDir.getAbsolutePath(), null);
availableLanguages.add(languageCode);
translatableLanguages.add(languageCode);
translatableLangAppBaseDirLookup.put(languageCode, transToolApplicationOptLanguagesSrcDir);
}
}
String folderRoot = WebappHelper.getBuildOutputFolderRoot();
if(StringHelper.containsNonWhitespace(folderRoot)) {
//started from WEB-INF/classes
File libDir = new File(WebappHelper.getBuildOutputFolderRoot());
for (String languageCode : i18nMgr.searchForAvailableLanguages(libDir)) {
if (availableLanguages.contains(languageCode)) {
logDebug("Skipping duplicate or previously loaded language::" + languageCode + " found in " + libDir.getAbsolutePath(), null);
continue;
}
logDebug("Detected non-translatable language " + languageCode + " in " + libDir.getAbsolutePath(), null);
availableLanguages.add(languageCode);
// don't add to translatable languages nor to source lookup maps - those
// langs are read only
}
} else {
//started from jar (like weblogic does) -> load from the configuration
String enabledLanguagesConfig = getStringPropertyValue(CONFIG_LANGUAGES_ENABLED, false);
String[] enabledLanguages = enabledLanguagesConfig.split(",");
for (String languageCode : enabledLanguages) {
if (availableLanguages.contains(languageCode)) {
logWarn("Skipping duplicate or previously loaded language::" + languageCode + " found in "
+ LANG_PACKS_DIRECTORY.getAbsolutePath(), null);
continue;
}
logDebug("Force non-translatable language " + languageCode + " defined from enabledLanguages.", null);
availableLanguages.add(languageCode);
}
}
// 4) Add languages from the customizing lang packs
for (String languageCode : i18nMgr.searchForAvailableLanguages(LANG_PACKS_DIRECTORY)) {
if (availableLanguages.contains(languageCode)) {
logWarn("Skipping duplicate or previously loaded language::" + languageCode + " found in "
+ LANG_PACKS_DIRECTORY.getAbsolutePath(), null);
continue;
}
logDebug("Detected non-translatable language " + languageCode + " in " + LANG_PACKS_DIRECTORY.getAbsolutePath(), null);
availableLanguages.add(languageCode);
// don't add to translatable languages nor to source lookup maps - those
// langs are read only
}
//
// Finished detecting available languages
//
// Proceed with some sanity checks
if (availableLanguages.size() == 0 || !availableLanguages.contains(Locale.ENGLISH.toString())) { throw new OLATRuntimeException(
"Did not find any language files, not even 'en'! At least 'en' must be available.", null); }
List<String> toRemoveLangs = new ArrayList<String>();
//
// Build list of all locales and the overlay locales if available
for (String langKey : availableLanguages) {
Locale locale = i18nMgr.createLocale(langKey);
if (locale == null) {
logError("Could not create locale for lang::" + langKey + ", skipping language and remove it from list of available languages",
null);
toRemoveLangs.add(langKey);
continue;
}
// Don't add same language twice
if (!allLocales.containsKey(langKey)) {
allLocales.put(langKey, locale);
}
//
// Add overlay
if (isOverlayEnabled()) {
Locale overlayLocale = i18nMgr.createOverlay(locale);
// Calculate the overlay key as used as reference. Note, this is not the
// same as overlayLocale.toString(), this would add '_' for each element
String overlayKey = i18nMgr.getLocaleKey(overlayLocale);
if (overlayLocale == null) {
logError("Could not create overlay locale for lang::" + langKey + " (" + overlayKey + "), skipping language", null);
continue;
}
// Don't add same overlay twice
if (!allLocales.containsKey(overlayKey)) {
overlayLanguagesKeys.add(overlayKey);
allLocales.put(overlayKey, overlayLocale);
overlayLocales.put(locale, overlayLocale);
// Add translation tool base dir for overlay local to customizing dir
translatableLangAppBaseDirLookup.put(overlayKey, LANG_OVERLAY_DIRECTORY);
}
}
}
// Remove langs that failed to be created
for (String langKey : toRemoveLangs) {
availableLanguages.remove(langKey);
translatableLanguages.remove(langKey);
translatableLangAppBaseDirLookup.remove(langKey);
}
// Set fallback locale from configuration
String fallbackLangKey = getStringConfigParameter(CONFIG_FALLBACK_LANG, Locale.ENGLISH.toString(), false);
// fallbackLangKey can't be null because EN is guaranteed to be available,
// see above
fallbackLocale = allLocales.get(fallbackLangKey);
// Check if translation tool reference languages are available
if (isTransToolEnabled() && transToolReferenceLanguages.size() == 0) {
logError("Did not find the fallback language configuration in the configuration, using language::en instead", null);
} else {
for (String langKey : transToolReferenceLanguages) {
if (!allLocales.containsKey(langKey)) {
logError("The configured fallback language::" + langKey + " does not exist. Using language::en instead", null);
}
}
}
}
private void doInitLanguageConfiguration() {
// Set the default language
String defaultLanguageKey = getStringPropertyValue(CONFIG_DEFAULT_LANG, false);
Locale newDefaultLocale = allLocales.get(defaultLanguageKey);
if (newDefaultLocale == null) {
logError("Could not set default locale to value::" + defaultLanguageKey + " - no such language found. Using fallback locale instead",
null);
newDefaultLocale = allLocales.get(transToolReferenceLanguages.get(0));
} else if (!availableLanguages.contains(newDefaultLocale.toString())) {
logError("Did not find the default language::" + newDefaultLocale.toString()
+ " in the available availableLanguages files! Using fallback locale instead", null);
newDefaultLocale = allLocales.get(transToolReferenceLanguages.get(0));
}
defaultLocale = newDefaultLocale;
logInfo("Setting default locale::" + newDefaultLocale.toString(), null);
// Enabling configured languages (a subset of the available languages)
String[] enabledLanguages;
String enabledLanguagesConfig = getStringPropertyValue(CONFIG_LANGUAGES_ENABLED, false);
if (!StringHelper.containsNonWhitespace(enabledLanguagesConfig) || enabledLanguagesConfig.equals(CONFIG_LANGUAGES_ENABLED_ALL)) {
enabledLanguages = ArrayHelper.toArray(availableLanguages);
} else {
enabledLanguages = enabledLanguagesConfig.split(",");
}
enabledLanguagesKeys.clear(); // reset first
for (String langKey : enabledLanguages) {
langKey = langKey.trim();
if (StringHelper.containsNonWhitespace(langKey) && availableLanguages.contains(langKey)) {
enabledLanguagesKeys.add(langKey);
} // else skip this entry
}
logInfo("Enabling languages::" + enabledLanguagesConfig, null);
// Make sure that the configured default language is enabled
if (!enabledLanguagesKeys.contains(getDefaultLocale().toString())) {
String defLang = getDefaultLocale().toString();
enabledLanguagesKeys.add(defLang);
logWarn("The configured default language::" + defLang + " is not in the list of enabled languages. Enabling language::" + defLang,
null);
}
}
//
// Getters and Setters
//
/**
* @return The default locale configured for this web app
*/
public static Locale getDefaultLocale() {
return defaultLocale;
}
/**
* Method to set new default locale
*
* @param newDefaultLocale
*/
public static void setDefaultLocale(Locale newDefaultLocale) {
if (defaultLocale == null || !defaultLocale.toString().equals(newDefaultLocale.toString())) {
// Just set the string property here. This will fire an event and
// call the method initFromChangedProperties()
INSTANCE.setStringProperty(CONFIG_DEFAULT_LANG, newDefaultLocale.toString(), true);
}
}
/**
* @return The locale that is used when a string is not found in any other
* locale
*/
public static Locale getFallbackLocale() {
return fallbackLocale;
}
/*
* Static getter methods, mainly used by I18nManager
*/
/**
* @return true: caching is enabled; false: caching is disabled
*/
static boolean isCachingEnabled() {
return cachingEnabled;
}
/**
* @return as keys: a Set of Strings with the supported languages (e.g. de,
* de_CH, en, ...). those are the languages that are installed. See
* the enabled languages to get the list of languages that are enabled
* to be used
*/
public static Set<String> getAvailableLanguageKeys() {
return availableLanguages;
}
/**
* @return A set of language keys that can be translated by the translation
* tool. Theses are the languages that are available in the source
* form. Languages embedded in jars can't be edited.
*/
public static Set<String> getTranslatableLanguageKeys() {
return translatableLanguages;
}
/**
* @return the map (with dummy value) of all languages including
* overlayLocales (as a String)
*/
public static Map<String, Locale> getAllLocales() {
return allLocales;
}
/**
* @return The lookup map of the overlay locales. Key: the locale; value: the
* corresponding overlay
*/
public static Map<Locale, Locale> getOverlayLocales() {
return overlayLocales;
}
/**
* @return as keys: a List of Strings with the supported languages (e.g. de,
* de_CH, en, ...). those are the languages which can be chosen by the
* user
*/
public static Collection<String> getEnabledLanguageKeys() {
synchronized (enabledLanguagesKeys) {
return new HashSet<String>(enabledLanguagesKeys);
}
}
/**
* @return as keys: a List of Strings with the supported languages overlay keys
*/
public static Set<String> getOverlayLanguageKeys() {
return overlayLanguagesKeys;
}
/**
* Set the languages that are enabled on the system. The change affects the
* system immediately and is persisted in the olatdata/system/configuration
*
* @param newEnabledLangKeys
*/
public static void setEnabledLanguageKeys(Collection<String> newEnabledLangKeys) {
if (!newEnabledLangKeys.equals(enabledLanguagesKeys)) {
String newEnabledConfig = "";
for (String enabledKey : newEnabledLangKeys) {
newEnabledConfig += enabledKey + ",";
}
if (newEnabledConfig.length() > 0) {
// remove last comma
newEnabledConfig = newEnabledConfig.substring(0, newEnabledConfig.length() - 1);
}
// Just set the string property here. This will fire an event and
// call the method initFromChangedProperties()
INSTANCE.setStringProperty(CONFIG_LANGUAGES_ENABLED, newEnabledConfig.toString(), true);
// No need to reinitialize i18n Module, setting the new property will already do this
}
}
/**
* @return A list of language keys that are reference and fallback languages
*/
public static List<String> getTransToolReferenceLanguages() {
return transToolReferenceLanguages;
}
/**
* @return All bundles that contain a _i18n directory with translation files
*/
public static List<String> getBundleNamesContainingI18nFiles() {
return bundleNames;
}
/**
* @return The bundle name that contains the commonly used translations from
* the olatcore framework
*/
public static String getCoreFallbackBundle() {
return coreFallbackBundle;
}
/**
* @return The bundle name that contains the commonly used translations from
* the application
*/
public static String getApplicationFallbackBundle() {
return applicationFallbackBundle;
}
/**
* Checks if the overlay mechanism is enabled. The overlay is similar to the
* locale variant, but adds another layer on top of it.
*
* @return true: enabled; false: disabled
*/
public static boolean isOverlayEnabled() {
return (overlayEnabled && StringHelper.containsNonWhitespace(overlayName));
}
/**
* Returns the overlay name or NULL if not configured. For an overlay file
* with the name 'LocalStrings_de__VENDOR.properties' it will return 'VENDOR'
*
* @return name of the overlay
*/
public static String getOverlayName() {
if (isOverlayEnabled()) return overlayName;
else return null;
}
/**
* @return true: enable the translation tool; false: disable the translation
* tool
*/
public static boolean isTransToolEnabled() {
return transToolEnabled;
}
/**
* search for bundles that contain i18n files. Searches in the org.olat.core
* package
*/
static void initBundleNames() {
I18nManager i18nMgr = I18nManager.getInstance();
bundleNames = i18nMgr.searchForBundleNamesContainingI18nFiles();
}
/**
* Get the base source directory for the given language where the language
* files for this bundle are stored
*
* @param locale
* @param bundleName
* @return The file or null if the language is not read-write configured
*/
public static File getPropertyFilesBaseDir(Locale locale, String bundleName) {
// 1) Special case, junit test files are not in olat source path
// We don't want translator to translate those files!
if (Settings.isJUnitTest() && bundleName.startsWith("org.olat.core.util.i18n.junittestdata") ) {
return new File(transToolApplicationLanguagesDir, "/../../test/java");
}
// 2) Metadata file: metadata file is always on the core / application
// source path
if (locale == null) {
return transToolApplicationLanguagesDir;
}
// 3) Locale files from core or application
String localeKey = I18nManager.getInstance().getLocaleKey(locale);
return translatableLangAppBaseDirLookup.get(localeKey);
}
/**
* Reinitialize the entire i18n system
*/
public static void reInitializeAndFlushCache() {
synchronized (enabledLanguagesKeys) {
// Re-initialize all local caches
doReInitialize();
// Notify other nodes to reInitialize the caches as well
I18nReInitializeCachesEvent changedConfigEvent = new I18nReInitializeCachesEvent();
CoordinatorManager.getInstance().getCoordinator().getEventBus().fireEventToListenersOf(changedConfigEvent, I18N_CACHE_FLUSHED_EVENT_CHANNEL);
}
}
/**
* Private helper that implements the reinitialization of all caches. This
* is decoupled from the reInitialize() to prevent endless firing of events
* in the cluster.
*/
private static void doReInitialize() {
synchronized (enabledLanguagesKeys) {
// Clear everything
availableLanguages.clear();
translatableLanguages.clear();
translatableLangAppBaseDirLookup.clear();
allLocales.clear();
overlayLanguagesKeys.clear();
overlayLocales.clear();
enabledLanguagesKeys.clear();
transToolReferenceLanguages.clear();
I18nManager.getInstance().clearCaches();
// Now rebuild everything from scratch
INSTANCE.doInit();
}
}
/**
* @see org.olat.core.configuration.AbstractOLATModule#event(org.olat.core.gui.control.Event)
*/
public void event(Event event) {
// First delegate to AbstractOLATModule
super.event(event);
// Take care of our own things
if (event instanceof I18nReInitializeCachesEvent) {
// Fired when the cache is flushed on another node without any config changes
I18nReInitializeCachesEvent i18nInitEvent = (I18nReInitializeCachesEvent) event;
if (!i18nInitEvent.isEventOnThisNode()) {
doReInitialize();
}
}
}
/**
* Get the language dir for the applications DE and EN files. Only available when in
* translation server mode
*
* @return
*/
public static File getTransToolApplicationLanguagesSrcDir() {
return transToolApplicationLanguagesDir;
}
/**
* Get the language dir for the applications i18n different than DE and EN
* files. Only available when in translation server mode
*
* @return
*/
public static File getTransToolApplicationOptLanguagesSrcDir() {
return transToolApplicationOptLanguagesSrcDir;
}
@Override
public void setPersistedProperties(PersistedProperties persistedProperties) {
this.moduleConfigProperties = persistedProperties;
}
}