Skip to content

Instantly share code, notes, and snippets.

@fbaierl
Last active October 26, 2018 13:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fbaierl/35a981a9849ea44e3d4fde04fbef46ca to your computer and use it in GitHub Desktop.
Save fbaierl/35a981a9849ea44e3d4fde04fbef46ca to your computer and use it in GitHub Desktop.
Java I18n wrapper for scaposer lib (Scala)
// dependencies:
// https://mvnrepository.com/artifact/tv.cntt/scaposer
// compile group: 'tv.cntt', name: 'scaposer_2.12', version: '1.11.0'
package internationalization;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import scala.collection.Seq;
import scala.util.Either;
import scaposer.ParseFailure;
import scaposer.Parser$;
import scaposer.Translation;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;
public final class I18n {
private static final Logger LOG = LoggerFactory.getLogger(I18n.class);
/**
* The current language to translate to.
*/
private static Locale _currentLocale = Locale.ENGLISH;
private static Map<Locale, scaposer.I18n> _dictionaries = new HashMap<>();
/**
* Selects the current language as the default language to translate to.
* @param locale target language
*/
public static void select(Locale locale){
_currentLocale = locale;
}
public static String t(String singular){
if(_dictionaries.containsKey(_currentLocale)){
return _dictionaries.get(_currentLocale).t(singular);
}
return singular; // fallback
}
public static String tc(String ctx, String singular){
if(_dictionaries.containsKey(_currentLocale)){
return _dictionaries.get(_currentLocale).tc(ctx, singular);
}
return singular; // fallback
}
public static String tn(String singular, String plural, Long n) {
if(_dictionaries.containsKey(_currentLocale)){
return _dictionaries.get(_currentLocale).tn(singular, plural, n);
}
return (n != 1) ? plural : singular; // fallback
}
public static String tcn(String ctx, String singular, String plural, Long n){
if(_dictionaries.containsKey(_currentLocale)){
return _dictionaries.get(_currentLocale).tcn(ctx, singular, plural, n);
}
return (n != 1) ? plural : singular; // fallback
}
public static Locale localeFromFileName(String fileName){
String[] ns = fileName.split("\\.");
return Locale.forLanguageTag(ns[0]);
}
/**
* Loads all *.po files from the given <code>path</code>.
* <p>
* The files should follow this naming convention:
* <br>
* <code>*language_code*.*name*.po</code>
* <nr
* *name* is optional
* <br>
* example: <code>de.myComponent.po</code> & <code>de.myOtherComponent.po</code> & <code>de.po</code>
* </p>
* @param path the path to search for language files for
*/
public static void init(String path){
File dir = new File(path);
if(!dir.isDirectory()){
throw new IllegalArgumentException("Path needs to point to a directory.");
}
String[] fileNames = dir.list((dir1, name) -> name.endsWith(".po"));
if(fileNames == null || fileNames.length == 0){
LOG.warn("No translation files (*.po) found.");
return;
}
initPoFiles(path, fileNames);
}
private static void initPoFiles(String path, String[] fileNames){
_dictionaries.clear();
for(String name: fileNames){
try {
Locale loc = localeFromFileName(name);
scaposer.I18n i18n = readPoFile(path + File.separator + name);
if(_dictionaries.containsKey(loc)){
// if a dictionary already exists, combine them
_dictionaries.put(loc, _dictionaries.get(loc).$plus$plus(i18n));
} else {
_dictionaries.put(loc, i18n);
}
} catch (IOException e) {
LOG.error("Error while reading translation file: " + path);
} catch (PoParseFailure poParseFailure) {
LOG.error("Error while parsing translation file: " + path + "; Error: " + poParseFailure.getMessage());
}
}
}
private static scaposer.I18n readPoFile(String pathToFile) throws IOException, PoParseFailure {
byte[] encoded = Files.readAllBytes(Paths.get(pathToFile));
String fileContent = new String(encoded, Charset.forName("UTF-8"));
return parsePoFile(fileContent);
}
private static scaposer.I18n parsePoFile(String fileContent) throws PoParseFailure {
final Either<ParseFailure, Seq<Translation>> parseFailureSeqEither = Parser$.MODULE$.parse(fileContent);
if(parseFailureSeqEither.isRight()){
Seq<Translation> translationSeq = parseFailureSeqEither.right().get();
return scaposer.I18n.apply(translationSeq);
}else {
throw new PoParseFailure (parseFailureSeqEither.left().toString());
}
}
private static class PoParseFailure extends Exception {
PoParseFailure (String message) {
super(message);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment