Improve saving in messages import

- Keep same style (messages wrapped in single quotes)
- Remove verification comments and run verification after merge again
This commit is contained in:
ljacqu 2016-04-16 11:47:18 +02:00
parent f4bc4322f0
commit 6c49f5844f
3 changed files with 98 additions and 16 deletions

View File

@ -93,7 +93,7 @@ public final class VerifyMessagesTask implements ToolTask {
} }
} }
private static void verifyFileAndAddKeys(MessageFileVerifier verifier, FileConfiguration defaultMessages) { public static void verifyFileAndAddKeys(MessageFileVerifier verifier, FileConfiguration defaultMessages) {
Map<String, Boolean> missingKeys = verifier.getMissingKeys(); Map<String, Boolean> missingKeys = verifier.getMissingKeys();
if (!missingKeys.isEmpty() || !verifier.getMissingTags().isEmpty()) { if (!missingKeys.isEmpty() || !verifier.getMissingTags().isEmpty()) {
verifier.addMissingKeys(defaultMessages); verifier.addMissingKeys(defaultMessages);

View File

@ -0,0 +1,58 @@
package messages.translation;
import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.YamlConfiguration;
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.Yaml;
import java.io.File;
import java.io.IOException;
import java.util.regex.Pattern;
/**
* Extension of {@link YamlConfiguration} to customize the writing style.
*/
public class AuthMeYamlConfiguration extends YamlConfiguration {
// Differences to YamlConfiguration: Texts are always in single quotes
// and line breaks are only applied after 200 chars
@Override
public String saveToString() {
DumperOptions options = new DumperOptions();
options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
options.setDefaultScalarStyle(DumperOptions.ScalarStyle.SINGLE_QUOTED);
options.setPrettyFlow(true);
options.setWidth(200);
Yaml yaml = new Yaml(options);
String header = buildHeader();
String dump = yaml.dump(getValues(false));
if (dump.equals(BLANK_CONFIG)) {
dump = "";
}
// By setting the scalar style to SINGLE_QUOTED both keys and values will be enclosed in single quotes.
// We want all texts wrapped in single quotes, but not the keys. Seems like this is not possible in SnakeYAML
dump = Pattern.compile("^'([a-zA-Z0-9-_]+)': ", Pattern.MULTILINE)
.matcher(dump).replaceAll("$1: ");
return header + dump;
}
/**
* Behaves similarly to {@link YamlConfiguration#loadConfiguration(File)} but returns an object
* of this class instead.
*
* @param file the file to load
* @return the constructed AuthMeYamlConfiguration instance
*/
public static AuthMeYamlConfiguration loadConfiguration(File file) {
AuthMeYamlConfiguration config = new AuthMeYamlConfiguration();
try {
config.load(file);
} catch (IOException | InvalidConfigurationException ex) {
throw new IllegalStateException(ex);
}
return config;
}
}

View File

@ -2,21 +2,27 @@ package messages.translation;
import com.google.common.io.Resources; import com.google.common.io.Resources;
import com.google.gson.Gson; import com.google.gson.Gson;
import messages.MessageFileVerifier;
import messages.VerifyMessagesTask;
import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.configuration.file.YamlConfiguration;
import org.yaml.snakeyaml.DumperOptions; import utils.FileUtils;
import utils.ToolTask; import utils.ToolTask;
import utils.ToolsConstants; import utils.ToolsConstants;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.lang.reflect.Field;
import java.net.URL; import java.net.URL;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.util.Scanner; import java.util.Scanner;
import java.util.regex.Pattern;
/** /**
* Imports a message file from a JSON export. * Imports a message file from a remote JSON export and validates the resulting file.
* <p>
* Comments at the top of an existing file should remain after the import, but it is important
* to verify that no unwanted changes have been applied to the file. Note that YAML comments
* tend to disappear if there is no space between the <code>#</code> and the first character.
*/ */
public class ImportMessagesTask implements ToolTask { public class ImportMessagesTask implements ToolTask {
@ -30,8 +36,9 @@ public class ImportMessagesTask implements ToolTask {
@Override @Override
public void execute(Scanner scanner) { public void execute(Scanner scanner) {
System.out.println("Enter URL to export from"); System.out.println("Enter URL to import from");
String url = scanner.nextLine(); String url = scanner.nextLine();
LanguageExport languageExport = getLanguageExportFromUrl(url); LanguageExport languageExport = getLanguageExportFromUrl(url);
if (languageExport == null) { if (languageExport == null) {
throw new IllegalStateException("An error occurred: constructed language export is null"); throw new IllegalStateException("An error occurred: constructed language export is null");
@ -41,10 +48,10 @@ public class ImportMessagesTask implements ToolTask {
System.out.println("Saved to messages file for code '" + languageExport.code + "'"); System.out.println("Saved to messages file for code '" + languageExport.code + "'");
} }
private LanguageExport getLanguageExportFromUrl(String url) { private LanguageExport getLanguageExportFromUrl(String location) {
try { try {
URL uri = new URL(url); URL url = new URL(location);
String json = Resources.toString(uri, Charset.forName("UTF-8")); String json = Resources.toString(url, Charset.forName("UTF-8"));
return gson.fromJson(json, LanguageExport.class); return gson.fromJson(json, LanguageExport.class);
} catch (IOException e) { } catch (IOException e) {
throw new IllegalStateException(e); throw new IllegalStateException(e);
@ -53,23 +60,40 @@ public class ImportMessagesTask implements ToolTask {
private void mergeExportIntoFile(LanguageExport export) { private void mergeExportIntoFile(LanguageExport export) {
String languageCode = export.code; String languageCode = export.code;
File file = new File(MESSAGES_FOLDER + "messages_" + languageCode + ".yml"); String fileName = MESSAGES_FOLDER + "messages_" + languageCode + ".yml";
File file = new File(fileName);
if (!file.exists()) { if (!file.exists()) {
throw new IllegalStateException("Messages file for language code " + languageCode + " does not exist"); throw new IllegalStateException("Messages file for language code " + languageCode + " does not exist");
} }
FileConfiguration fileConfiguration = YamlConfiguration.loadConfiguration(file); removeAllTodoComments(fileName);
FileConfiguration fileConfiguration = AuthMeYamlConfiguration.loadConfiguration(file);
for (MessageExport messageExport : export.messages) { for (MessageExport messageExport : export.messages) {
fileConfiguration.set(messageExport.key, messageExport.translatedMessage); if (!messageExport.translatedMessage.isEmpty()) {
fileConfiguration.set(messageExport.key, messageExport.translatedMessage);
}
} }
try { try {
Field dumperOptionsField = YamlConfiguration.class.getDeclaredField("yamlOptions");
dumperOptionsField.setAccessible(true);
DumperOptions options = (DumperOptions) dumperOptionsField.get(fileConfiguration);
options.setDefaultScalarStyle(DumperOptions.ScalarStyle.SINGLE_QUOTED);
fileConfiguration.save(file); fileConfiguration.save(file);
} catch (IOException | NoSuchFieldException | IllegalAccessException e) { } catch (IOException e) {
throw new IllegalStateException(e); throw new IllegalStateException(e);
} }
MessageFileVerifier verifier = new MessageFileVerifier(fileName);
VerifyMessagesTask.verifyFileAndAddKeys(verifier, YamlConfiguration.loadConfiguration(
new File(MESSAGES_FOLDER + "messages_en.yml")));
}
/**
* Removes all to-do comments written by {@link VerifyMessagesTask}. This is helpful as the YamlConfiguration
* moves those comments otherwise upon saving.
*
* @param file The file whose to-do comments should be removed
*/
private static void removeAllTodoComments(String file) {
String contents = FileUtils.readFromFile(file);
String regex = "^# TODO .*$";
contents = Pattern.compile(regex, Pattern.MULTILINE).matcher(contents).replaceAll("");
FileUtils.writeToFile(file, contents);
} }
} }