| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You 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.apache.hop.ui.i18n; |
| |
| import org.apache.hop.core.exception.HopException; |
| import org.apache.hop.core.exception.HopFileException; |
| import org.apache.hop.core.util.Assert; |
| |
| import java.io.File; |
| import java.io.IOException; |
| import java.nio.file.Files; |
| import java.nio.file.Path; |
| import java.nio.file.Paths; |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.stream.Collectors; |
| |
| public class BundlesStore { |
| |
| private List<String> bundleRootFolders; |
| |
| /* |
| This map contains the content of message bundles per package, per language and per file |
| */ |
| private Map<String, Map<String, BundleFile>> packageLanguageBundleMap; |
| private final Map<String, List<String>> collisionPackages; |
| |
| public BundlesStore() { |
| this.bundleRootFolders = new ArrayList<>(); |
| this.packageLanguageBundleMap = new HashMap<>(); |
| this.collisionPackages = new HashMap<>(); |
| } |
| |
| public BundlesStore(List<String> bundleRootFolders) { |
| this(); |
| this.bundleRootFolders = bundleRootFolders; |
| } |
| |
| /** |
| * Let's look at all the messages bundle package root folders. We only look at src/main/resources/ |
| * Avoid impl folders |
| * |
| * @param rootFolder |
| */ |
| public BundlesStore(String rootFolder) throws HopException { |
| this(); |
| try { |
| Files.walk(Paths.get(rootFolder)) |
| .filter( |
| path -> |
| Files.isDirectory(path) |
| && path.endsWith("src/main/resources") |
| && !path.toString().contains("/impl/")) |
| .forEach(path -> bundleRootFolders.add(path.toAbsolutePath().toFile().getPath())); |
| } catch (IOException e) { |
| throw new HopException("Error reading root folder: " + rootFolder, e); |
| } |
| } |
| |
| public void findAllMessagesBundles() throws HopException { |
| try { |
| for (String bundleRootFolder : bundleRootFolders) { |
| Files.walk(Paths.get(bundleRootFolder)) |
| .filter( |
| path -> |
| Files.isRegularFile(path) |
| && path.getFileName().toString().startsWith("messages_") |
| && path.getFileName().toString().endsWith(".properties")) |
| .forEach(path -> addMessagesFile(bundleRootFolder, path)); |
| } |
| if (!collisionPackages.isEmpty()) { |
| String collisionFiles = |
| collisionPackages.values().stream() |
| .flatMap(Collection::stream) |
| .collect(Collectors.joining("\n\t")); |
| collisionPackages.clear(); |
| throw new HopFileException( |
| "Bundle file collision! " |
| + "We're trying to add all files to the bundle store but some files already exists " |
| + "in the same package. You should rename part of collision files, " |
| + "otherwise the package bundle will be ignored.\nList of collision file:\n\t" |
| + collisionFiles); |
| } |
| } catch (HopFileException e) { |
| throw e; |
| } catch (Exception e) { |
| throw new HopException("Error searching for messages bundles", e); |
| } |
| } |
| |
| /** |
| * @param bundleRootFolder |
| * @param messagesFilePath |
| */ |
| private void addMessagesFile(String bundleRootFolder, Path messagesFilePath) |
| throws RuntimeException { |
| // Root folder : /home/matt/git/project-hop/hop/ui/src/main/resources |
| // Messages folder: |
| // /home/matt/git/project-hop/hop/ui/src/main/resources/org/apache/hop/ui/hopgui/messages/ |
| // |
| |
| String messagesFileFolder = messagesFilePath.toFile().getParent(); |
| if (messagesFileFolder.startsWith(bundleRootFolder)) { |
| // We can determine the package... |
| // |
| String packageName = |
| messagesFileFolder |
| .substring(bundleRootFolder.length()) |
| .replace(File.separator, "/") |
| .replaceAll("\\/messages$", "") |
| .replaceAll("^\\/", "") |
| .replaceAll("\\/", "."); |
| |
| // What is the language? |
| // Decompose messages_en_US.properties to en_US using some regex |
| // |
| String locale = |
| messagesFilePath |
| .getFileName() |
| .toString() |
| .replaceAll("^messages_", "") |
| .replaceAll("\\.properties$", ""); |
| |
| // Now store this bundle in the store... |
| // |
| String filename = messagesFilePath.toString(); |
| try { |
| BundleFile bundleFile = new BundleFile(filename, packageName, locale); |
| addBundleFile(packageName, locale, bundleFile); |
| } catch (Exception e) { |
| throw new RuntimeException("Unable to read messages bundle file : " + filename, e); |
| } |
| } |
| } |
| |
| public void addBundleFile(String packageName, String language, BundleFile bundleFile) { |
| // Find the languages for the package: |
| // |
| Map<String, BundleFile> languageBundleMap = packageLanguageBundleMap.get(packageName); |
| if (languageBundleMap == null) { |
| languageBundleMap = new HashMap<>(); |
| packageLanguageBundleMap.put(packageName, languageBundleMap); |
| } |
| |
| // Find the bundle file for the language: |
| // If it already exists we're storing messages bundles twice or something like that. |
| // |
| BundleFile existingFile = languageBundleMap.get(language); |
| if (existingFile != null || collisionPackages.containsKey(packageName)) { |
| List<String> collisionFiles = collisionPackages.get(packageName); |
| if (collisionFiles == null) { |
| Assert.assertNotNull(existingFile); |
| collisionFiles = new ArrayList<>(); |
| collisionFiles.add(existingFile.getFilename()); |
| collisionPackages.put(packageName, collisionFiles); |
| languageBundleMap.remove(language, existingFile); |
| } |
| packageLanguageBundleMap.remove(packageName); |
| collisionFiles.add(bundleFile.getFilename()); |
| return; |
| } |
| |
| languageBundleMap.put(language, bundleFile); |
| } |
| |
| public Map<String, String> findTranslations(String packageName, String key) { |
| Map<String, String> translations = new HashMap<>(); |
| Map<String, BundleFile> languageBundleFileMap = packageLanguageBundleMap.get(packageName); |
| if (languageBundleFileMap != null) { |
| for (String language : languageBundleFileMap.keySet()) { |
| String translation = languageBundleFileMap.get(language).get(key); |
| if (translation != null) { |
| translations.put(language, translation); |
| } |
| } |
| } |
| return translations; |
| } |
| |
| public String lookupTranslation(String packageName, String locale, String key) { |
| Map<String, BundleFile> languageBundleFileMap = packageLanguageBundleMap.get(packageName); |
| if (languageBundleFileMap != null) { |
| BundleFile bundleFile = languageBundleFileMap.get(locale); |
| if (bundleFile != null) { |
| return bundleFile.get(key); |
| } |
| } |
| return null; |
| } |
| |
| public void removeTranslation(String packageName, String locale, String key) { |
| Map<String, BundleFile> languageBundleFileMap = packageLanguageBundleMap.get(packageName); |
| if (languageBundleFileMap != null) { |
| BundleFile bundleFile = languageBundleFileMap.get(locale); |
| if (bundleFile != null) { |
| bundleFile.remove(key); |
| } |
| } |
| } |
| |
| public void addTranslation( |
| String sourceFolder, String packageName, String locale, String key, String value) { |
| Map<String, BundleFile> languageBundleFileMap = packageLanguageBundleMap.get(packageName); |
| if (languageBundleFileMap == null) { |
| languageBundleFileMap = new HashMap<>(); |
| packageLanguageBundleMap.put(packageName, languageBundleFileMap); |
| } |
| |
| BundleFile bundleFile = languageBundleFileMap.get(locale); |
| if (bundleFile == null) { |
| // Create a new bundle file |
| // |
| // Calculate the resources folder based off the Java folder |
| // sourceFolder would be /path/plugins/databases/firebird/src/main/java |
| // We need to come up with /path/plugins/databases/firebird/src/main/resources |
| |
| String bundleFileName = |
| sourceFolder |
| // Use File.separator to build a path that is system agnostic |
| .replace("java", "resources" + File.separator) |
| // append package folders |
| .concat(packageName.replace(".", File.separator)) |
| // append messages folder and localized file |
| .concat( |
| File.separator |
| + "messages" |
| + File.separator |
| + "messages_" |
| + locale |
| + ".properties"); |
| |
| // TODO finish/test calculating filename |
| bundleFile = new BundleFile(bundleFileName, packageName, locale, new HashMap<>()); |
| languageBundleFileMap.put(locale, bundleFile); |
| } |
| bundleFile.put(key, value); |
| } |
| |
| public List<BundleFile> getChangedBundleFiles() { |
| List<BundleFile> bundleFiles = new ArrayList<>(); |
| for (String packageName : packageLanguageBundleMap.keySet()) { |
| Map<String, BundleFile> languageBundleMap = packageLanguageBundleMap.get(packageName); |
| for (String locale : languageBundleMap.keySet()) { |
| BundleFile bundleFile = languageBundleMap.get(locale); |
| if (bundleFile.hasChanged()) { |
| bundleFiles.add(bundleFile); |
| } |
| } |
| } |
| return bundleFiles; |
| } |
| |
| /** |
| * Get the bundle file for the given package of all bundles for the locale if the package name is |
| * null. |
| * |
| * @param packageName The package name or null if you want all files for a locale |
| * @param locale The locale to search for |
| * @return The bundle files |
| */ |
| public List<BundleFile> getBundleFiles(String packageName, String locale) { |
| List<BundleFile> bundleFiles = new ArrayList<>(); |
| |
| for (String pckName : packageLanguageBundleMap.keySet()) { |
| if (packageName == null || packageName.equals(pckName)) { |
| Map<String, BundleFile> languageBundleMap = packageLanguageBundleMap.get(pckName); |
| if (languageBundleMap != null) { |
| BundleFile bundleFile = languageBundleMap.get(locale); |
| if (bundleFile != null) { |
| bundleFiles.add(bundleFile); |
| } |
| } |
| } |
| } |
| |
| return bundleFiles; |
| } |
| |
| public BundleFile findBundleFile(String packageName, String locale) { |
| Map<String, BundleFile> languageBundleMap = packageLanguageBundleMap.get(packageName); |
| if (languageBundleMap != null) { |
| return languageBundleMap.get(locale); |
| } |
| return null; |
| } |
| |
| /** |
| * Gets bundleRootFolders |
| * |
| * @return value of bundleRootFolders |
| */ |
| public List<String> getBundleRootFolders() { |
| return bundleRootFolders; |
| } |
| |
| /** @param bundleRootFolders The bundleRootFolders to set */ |
| public void setBundleRootFolders(List<String> bundleRootFolders) { |
| this.bundleRootFolders = bundleRootFolders; |
| } |
| |
| /** |
| * Gets packageLanguageBundleMap |
| * |
| * @return value of packageLanguageBundleMap |
| */ |
| public Map<String, Map<String, BundleFile>> getPackageLanguageBundleMap() { |
| return packageLanguageBundleMap; |
| } |
| |
| /** @param packageLanguageBundleMap The packageLanguageBundleMap to set */ |
| public void setPackageLanguageBundleMap( |
| Map<String, Map<String, BundleFile>> packageLanguageBundleMap) { |
| this.packageLanguageBundleMap = packageLanguageBundleMap; |
| } |
| } |