/*
* 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.assets;
import com.google.common.base.Charsets;
import com.google.common.reflect.TypeToken;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonParseException;
import org.terasology.assets.ResourceUrn;
import org.terasology.assets.exceptions.InvalidAssetFilenameException;
import org.terasology.assets.format.AssetDataFile;
import org.terasology.assets.format.AssetFileFormat;
import org.terasology.assets.module.annotations.RegisterAssetFileFormat;
import org.terasology.engine.SimpleUri;
import org.terasology.naming.Name;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.file.PathMatcher;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Defines the file format of translation data. Matching files are of the form:
* <pre>
* <project-name>.lang
* <project-name>_<language-tag>.lang
* </pre>
* All IETF BCP 47 language tags are supported, but consider sticking to ISO 639-1 for simplicity.
* The data in the files is expected to be JSON entries of the form of a <String, String> map.
*/
@RegisterAssetFileFormat
public class TranslationFormat implements AssetFileFormat<TranslationData> {
/**
* The extension of translation files
*/
public static final String LANGDATA_EXT = ".lang";
private static final Pattern FILENAME_PATTERN = Pattern.compile("([^_]+)_?([\\w-]+)?.lang");
private static final TypeToken<Map<String, String>> MAP_TOKEN = new TypeToken<Map<String, String>>() {
private static final long serialVersionUID = -2255189133660408141L;
};
private final Gson gson = new GsonBuilder().create();
@Override
public PathMatcher getFileMatcher() {
return path -> {
String name = path.getFileName().toString();
return FILENAME_PATTERN.matcher(name).matches();
};
}
@Override
public Name getAssetName(String filename) throws InvalidAssetFilenameException {
if (filename.endsWith(LANGDATA_EXT)) {
return new Name(filename.substring(0, filename.length() - LANGDATA_EXT.length()));
}
throw new InvalidAssetFilenameException("File '" + filename + "' does not end with '" + LANGDATA_EXT + "'.");
}
@Override
public TranslationData load(ResourceUrn urn, List<AssetDataFile> inputs) throws IOException {
if (inputs.size() != 1) {
throw new IOException("Failed to load translation data '" + urn + "': " + inputs);
}
AssetDataFile file = inputs.get(0);
Locale locale = localeFromFilename(file.getFilename());
Name projName = basenameFromFilename(file.getFilename());
SimpleUri projUri = new SimpleUri(urn.getModuleName(), projName);
TranslationData data = new TranslationData(projUri, locale);
try (InputStreamReader isr = new InputStreamReader(file.openStream(), Charsets.UTF_8)) {
Map<String, String> entry = gson.fromJson(isr, MAP_TOKEN.getType());
data.addAll(entry);
} catch (JsonParseException e) {
throw new IOException("Could not parse file '" + file + "'", e);
}
return data;
}
private static Name basenameFromFilename(String filename) throws IOException {
Matcher m = FILENAME_PATTERN.matcher(filename);
if (m.matches()) {
return new Name(m.group(1));
}
throw new IOException("Could not parse project name: " + filename);
}
private static Locale localeFromFilename(String filename) throws IOException {
Matcher m = FILENAME_PATTERN.matcher(filename);
if (m.matches()) {
String langTag = m.group(2);
return (langTag != null) ? Locale.forLanguageTag(langTag) : Locale.ROOT;
}
throw new IOException("Could not parse locale: " + filename);
}
}