package org.jabref.logic.l10n;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.stream.Collectors;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
public class LocalizationConsistencyTest {
@Test
public void allFilesMustHaveSameKeys() {
for (String bundle : Arrays.asList("JabRef", "Menu")) {
Set<String> englishKeys = LocalizationParser
.getKeysInPropertiesFile(String.format("/l10n/%s_%s.properties", bundle, "en"));
List<String> nonEnglishLanguages = Languages.LANGUAGES.values().stream().filter(l -> !"en".equals(l))
.collect(Collectors.toList());
for (String lang : nonEnglishLanguages) {
Set<String> nonEnglishKeys = LocalizationParser
.getKeysInPropertiesFile(String.format("/l10n/%s_%s.properties", bundle, lang));
List<String> missing = new LinkedList<>(englishKeys);
missing.removeAll(nonEnglishKeys);
List<String> obsolete = new LinkedList<>(nonEnglishKeys);
obsolete.removeAll(englishKeys);
assertEquals("Missing keys of " + lang, Collections.emptyList(), missing);
assertEquals("Obsolete keys of " + lang, Collections.emptyList(), obsolete);
}
}
}
@Test
public void ensureNoDuplicates() {
for (String bundle : Arrays.asList("JabRef", "Menu")) {
for (String lang : Languages.LANGUAGES.values()) {
String propertyFilePath = String.format("/l10n/%s_%s.properties", bundle, lang);
// read in
DuplicationDetectionProperties properties = new DuplicationDetectionProperties();
try (InputStream is = LocalizationConsistencyTest.class.getResourceAsStream(propertyFilePath);
InputStreamReader reader = new InputStreamReader(is, StandardCharsets.UTF_8)) {
properties.load(reader);
} catch (IOException e) {
throw new RuntimeException(e);
}
List<String> duplicates = properties.getDuplicates();
assertEquals("Duplicate keys inside bundle " + bundle + "_" + lang, Collections.emptyList(), duplicates);
}
}
}
@Test
public void keyValueShouldBeEqualForEnglishPropertiesMenu() {
Properties englishKeys = LocalizationParser
.getProperties(String.format("/l10n/%s_%s.properties", "Menu", "en"));
for (Map.Entry<Object, Object> entry : englishKeys.entrySet()) {
String expectedKeyEqualsKey = String.format("%s=%s", entry.getKey(), entry.getKey());
String actualKeyEqualsValue = String.format("%s=%s", entry.getKey(),
entry.getValue().toString().replace("&", ""));
assertEquals(expectedKeyEqualsKey, actualKeyEqualsValue);
}
}
@Test
public void keyValueShouldBeEqualForEnglishPropertiesMessages() {
Properties englishKeys = LocalizationParser
.getProperties(String.format("/l10n/%s_%s.properties", "JabRef", "en"));
for (Map.Entry<Object, Object> entry : englishKeys.entrySet()) {
String expectedKeyEqualsKey = String.format("%s=%s", entry.getKey(), entry.getKey());
String actualKeyEqualsValue = String.format("%s=%s", entry.getKey(), entry.getValue());
assertEquals(expectedKeyEqualsKey, actualKeyEqualsValue);
}
}
@Test
public void findMissingLocalizationKeys() throws IOException {
List<LocalizationEntry> missingKeys = LocalizationParser.find(LocalizationBundleForTest.LANG).stream().sorted()
.distinct().collect(Collectors.toList());
assertEquals("DETECTED LANGUAGE KEYS WHICH ARE NOT IN THE ENGLISH LANGUAGE FILE\n" +
"1. PASTE THESE INTO THE ENGLISH LANGUAGE FILE\n" +
"2. EXECUTE: gradlew localizationUpdate\n" +
missingKeys.parallelStream()
.map(key -> String.format("%s=%s", key.getKey(), key.getKey()))
.collect(Collectors.toList()),
Collections.<LocalizationEntry>emptyList(), missingKeys);
}
@Test
public void findMissingMenuLocalizationKeys() throws IOException {
Set<LocalizationEntry> missingKeys = LocalizationParser.find(LocalizationBundleForTest.MENU);
assertEquals("DETECTED LANGUAGE KEYS WHICH ARE NOT IN THE ENGLISH MENU FILE\n" +
"1. PASTE THESE INTO THE ENGLISH MENU FILE\n" +
"2. EXECUTE: gradlew localizationUpdate\n" +
missingKeys.parallelStream()
.map(key -> String.format("%s=%s", key.getKey(), key.getKey()))
.collect(Collectors.toList()),
Collections.<LocalizationEntry>emptySet(), missingKeys);
}
@Test
public void findObsoleteLocalizationKeys() throws IOException {
Set<String> obsoleteKeys = LocalizationParser.findObsolete(LocalizationBundleForTest.LANG);
assertEquals("Obsolete keys found in language properties file: " + obsoleteKeys + "\n" +
"1. CHECK IF THE KEY IS REALLY NOT USED ANYMORE\n" +
"2. REMOVE THESE FROM THE ENGLISH LANGUAGE FILE\n" +
"3. EXECUTE: gradlew localizationUpdate\n",
Collections.<String>emptySet(), obsoleteKeys);
}
@Test
public void findObsoleteMenuLocalizationKeys() throws IOException {
Set<String> obsoleteKeys = LocalizationParser.findObsolete(LocalizationBundleForTest.MENU);
assertEquals("Obsolete keys found in the menu properties file: " + obsoleteKeys + "\n" +
"1. CHECK IF THE KEY IS REALLY NOT USED ANYMORE\n" +
"2. REMOVE THESE FROM THE ENGLISH MENU FILE\n" +
"3. EXECUTE: gradlew localizationUpdate\n",
Collections.<String>emptySet(), obsoleteKeys);
}
@Test
public void localizationParameterMustIncludeAString() throws IOException {
// Must start or end with "
// Localization.lang("test"), Localization.lang("test" + var), Localization.lang(var + "test")
// TODO: Localization.lang(var1 + "test" + var2) not covered
// Localization.lang("Problem downloading from %1", address)
Set<LocalizationEntry> keys = LocalizationParser.findLocalizationParametersStringsInJavaFiles(LocalizationBundleForTest.LANG);
for(LocalizationEntry e : keys) {
assertTrue("Illegal localization parameter found. Must include a String with potential concatenation or replacement parameters. Illegal parameter: Localization.lang(" + e.getKey(),
e.getKey().startsWith("\"") || e.getKey().endsWith("\""));
}
keys = LocalizationParser.findLocalizationParametersStringsInJavaFiles(LocalizationBundleForTest.MENU);
for(LocalizationEntry e : keys) {
assertTrue("Illegal localization parameter found. Must include a String with potential concatenation or replacement parameters. Illegal parameter: Localization.lang(" + e.getKey(),
e.getKey().startsWith("\"") || e.getKey().endsWith("\""));
}
}
private static class DuplicationDetectionProperties extends Properties {
private static final long serialVersionUID = 1L;
private final List<String> duplicates = new LinkedList<>();
public DuplicationDetectionProperties() {
super();
}
/**
* Overriding the HashTable put() so we can check for duplicates
*/
@Override
public synchronized Object put(Object key, Object value) {
// Have we seen this key before?
if (containsKey(key)) {
duplicates.add(String.valueOf(key));
}
return super.put(key, value);
}
public List<String> getDuplicates() {
return duplicates;
}
}
}