Add support for properties / resource bundles

This commit is contained in:
Marcel Haßlinger 2021-03-14 13:22:59 +01:00
parent 45aa5b18c5
commit 76c94f3c48
2 changed files with 139 additions and 4 deletions

View File

@ -0,0 +1,123 @@
package de.marhali.easyi18n.io.translator;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import de.marhali.easyi18n.data.LocalizedNode;
import de.marhali.easyi18n.data.Translations;
import de.marhali.easyi18n.util.TranslationsUtil;
import org.jetbrains.annotations.NotNull;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;
import java.util.function.Consumer;
/**
* Implementation for properties translation files.
* @author marhali
*/
public class PropertiesTranslatorIO implements TranslatorIO {
public static final String FILE_EXTENSION = "properties";
@Override
public void read(@NotNull String directoryPath, @NotNull Consumer<Translations> callback) {
ApplicationManager.getApplication().saveAll(); // Save opened files (required if new locales were added)
ApplicationManager.getApplication().runReadAction(() -> {
VirtualFile directory = LocalFileSystem.getInstance().findFileByIoFile(new File(directoryPath));
if(directory == null || directory.getChildren() == null) {
throw new IllegalArgumentException("Specified folder is invalid (" + directoryPath + ")");
}
VirtualFile[] files = directory.getChildren();
List<String> locales = new ArrayList<>();
LocalizedNode nodes = new LocalizedNode(LocalizedNode.ROOT_KEY, new ArrayList<>());
try {
for (VirtualFile file : files) {
locales.add(file.getNameWithoutExtension());
Properties properties = new Properties();
properties.load(new InputStreamReader(file.getInputStream()));;
readProperties(file.getNameWithoutExtension(), properties, nodes);
}
callback.accept(new Translations(locales, nodes));
} catch(IOException e) {
e.printStackTrace();
callback.accept(null);
}
});
}
@Override
public void save(@NotNull Translations translations, @NotNull String directoryPath, @NotNull Consumer<Boolean> callback) {
ApplicationManager.getApplication().runWriteAction(() -> {
try {
for(String locale : translations.getLocales()) {
Properties properties = new Properties();
writeProperties(locale, properties, translations.getNodes(), "");
String fullPath = directoryPath + "/" + locale + "." + FILE_EXTENSION;
VirtualFile file = LocalFileSystem.getInstance().findFileByIoFile(new File(fullPath));
ByteArrayOutputStream content = new ByteArrayOutputStream();
properties.store(content, "I18n " + locale + " keys");
file.setBinaryContent(content.toByteArray());
}
// Successfully saved
callback.accept(true);
} catch(IOException e) {
e.printStackTrace();
callback.accept(false);
}
});
}
private void writeProperties(String locale, Properties props, LocalizedNode node, String parentPath) {
if(node.isLeaf() && !node.getKey().equals(LocalizedNode.ROOT_KEY)) {
if(node.getValue().get(locale) != null) { // Translation is defined - track it
props.setProperty(parentPath, node.getValue().get(locale));
}
} else {
for(LocalizedNode children : node.getChildren()) {
writeProperties(locale, props, children,
parentPath + (parentPath.isEmpty() ? "" : ".") + children.getKey());
}
}
}
private void readProperties(String locale, Properties props, LocalizedNode parent) {
props.forEach((key, value) -> {
List<String> sections = TranslationsUtil.getSections(String.valueOf(key));
LocalizedNode node = parent;
for (String section : sections) {
LocalizedNode subNode = node.getChildren(section);
if(subNode == null) {
subNode = new LocalizedNode(section, new ArrayList<>());
node.addChildren(subNode);
}
node = subNode;
}
Map<String, String> messages = node.getValue();
messages.put(locale, String.valueOf(value));
node.setValue(messages);
});
}
}

View File

@ -3,15 +3,27 @@ package de.marhali.easyi18n.util;
import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFile;
import de.marhali.easyi18n.io.translator.JsonTranslatorIO; import de.marhali.easyi18n.io.translator.JsonTranslatorIO;
import de.marhali.easyi18n.io.translator.PropertiesTranslatorIO;
import de.marhali.easyi18n.io.translator.TranslatorIO; import de.marhali.easyi18n.io.translator.TranslatorIO;
import org.jetbrains.annotations.NotNull;
import java.io.File; import java.io.File;
import java.util.Arrays; import java.util.Arrays;
import java.util.Optional; import java.util.Optional;
/**
* IO operations utility.
* @author marhali
*/
public class IOUtil { public class IOUtil {
public static TranslatorIO determineFormat(String directoryPath) { /**
* Determines the {@link TranslatorIO} which should be used for the specified directoryPath
* @param directoryPath The full path to the parent directory which holds the translation files
* @return IO handler to use for file operations
*/
public static TranslatorIO determineFormat(@NotNull String directoryPath) {
VirtualFile directory = LocalFileSystem.getInstance().findFileByIoFile(new File(directoryPath)); VirtualFile directory = LocalFileSystem.getInstance().findFileByIoFile(new File(directoryPath));
if(directory == null || directory.getChildren() == null) { if(directory == null || directory.getChildren() == null) {
@ -21,7 +33,7 @@ public class IOUtil {
Optional<VirtualFile> any = Arrays.stream(directory.getChildren()).findAny(); Optional<VirtualFile> any = Arrays.stream(directory.getChildren()).findAny();
if(!any.isPresent()) { if(!any.isPresent()) {
throw new IllegalStateException("Could not determine format"); throw new IllegalStateException("Could not determine i18n format. At least one locale file must be defined");
} }
switch (any.get().getFileType().getDefaultExtension().toLowerCase()) { switch (any.get().getFileType().getDefaultExtension().toLowerCase()) {
@ -29,10 +41,10 @@ public class IOUtil {
return new JsonTranslatorIO(); return new JsonTranslatorIO();
case "properties": case "properties":
throw new UnsupportedOperationException(); return new PropertiesTranslatorIO();
default: default:
throw new UnsupportedOperationException("Unsupported format: " + throw new UnsupportedOperationException("Unsupported i18n locale file format: " +
any.get().getFileType().getDefaultExtension()); any.get().getFileType().getDefaultExtension());
} }
} }