/* * Copyright 2015 MovingBlocks * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.terasology.i18n; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.concurrent.CopyOnWriteArrayList; import java.util.function.Consumer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.terasology.assets.ResourceUrn; import org.terasology.assets.management.AssetManager; import org.terasology.config.Config; import org.terasology.config.SystemConfig; import org.terasology.context.Context; import org.terasology.engine.SimpleUri; import org.terasology.engine.Uri; import org.terasology.i18n.assets.Translation; import org.terasology.persistence.TemplateEngine; import org.terasology.persistence.TemplateEngineImpl; /** * A translation system that uses {@link Translation} data assets to * perform the lookup. */ public class TranslationSystemImpl implements TranslationSystem { private static final Logger logger = LoggerFactory.getLogger(TranslationSystemImpl.class); private final List<Consumer<TranslationProject>> changeListeners = new CopyOnWriteArrayList<>(); private final Map<Uri, TranslationProject> projects = new HashMap<>(); private final SystemConfig config; private AssetManager assetManager; /** * @param context the context to use */ public TranslationSystemImpl(Context context) { config = context.get(Config.class).getSystem(); assetManager = context.get(AssetManager.class); refresh(); } @Override public void refresh() { Set<ResourceUrn> urns = assetManager.getAvailableAssets(Translation.class); for (ResourceUrn urn : urns) { Optional<Translation> asset = assetManager.getAsset(urn, Translation.class); if (asset.isPresent()) { Translation trans = asset.get(); Uri uri = trans.getProjectUri(); if (uri.isValid()) { TranslationProject proj = projects.computeIfAbsent(uri, e -> new StandardTranslationProject()); proj.add(trans); trans.subscribe(this::onAssetChanged); logger.info("Discovered " + trans); } else { logger.warn("Ignoring invalid project uri: {}", uri); } } } } @Override public TranslationProject getProject(Uri name) { return projects.get(name); } @Override public String translate(String id) { return translate(id, config.getLocale()); } @Override public String translate(String text, Locale otherLocale) { TemplateEngine templateEngine = new TemplateEngineImpl(id -> { ResourceUrn uri = new ResourceUrn(id); SimpleUri projectUri = new SimpleUri(uri.getModuleName(), uri.getResourceName()); TranslationProject project = getProject(projectUri); if (project != null) { Optional<String> opt = project.translate(uri.getFragmentName(), otherLocale); if (opt.isPresent()) { return opt.get(); } else { logger.warn("No translation for '{}'", id); return "?" + uri.getFragmentName() + "?"; } } else { logger.warn("Invalid project id '{}'", id); return "?" + uri.getFragmentName() + "?"; } }); return templateEngine.transform(text); } @Override public void subscribe(Consumer<TranslationProject> reloadListener) { changeListeners.add(reloadListener); } @Override public void unsubscribe(Consumer<TranslationProject> reloadListener) { changeListeners.remove(reloadListener); } private void onAssetChanged(Translation trans) { Uri uri = trans.getProjectUri(); TranslationProject project = projects.get(uri); if (trans.isDisposed()) { project.remove(trans); } for (Consumer<TranslationProject> listener : changeListeners) { listener.accept(project); } } }