blob: 329d28f0d9e3e53cfeaa7e30280617a85e609c8a [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more contributor license
* agreements. See the NOTICE file distributed with this work for additional information regarding
* copyright ownership. The ASF licenses this file to You 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.apache.geode.internal.i18n;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.Locale;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import org.apache.geode.InternalGemFireException;
import org.apache.geode.i18n.StringId;
import org.apache.geode.internal.classloader.ClassPathLoader;
/**
* Baseclass for all {@link StringId} based ResourceBundles
*
* @see java.util.ResourceBundle
*
* @since GemFire 5.7
*/
public class AbstractStringIdResourceBundle {
private Int2ObjectOpenHashMap data;
/**
* Init method to populate the TIntObjectHashMap for Non-english locales
* <code>data = new TIntObjectHashMap();</code>
*
* The default bundle, English, will be <code>data = null</code>
*/
private void initData(String baseName, Locale l) {
String resource = baseName + "_" + l.getLanguage() + ".txt";
InputStream is = null;
try {
is = ClassPathLoader.getLatest().getResourceAsStream(getClass(), resource);
} catch (SecurityException se) {
// We do not have a logger yet
System.err.println(
"A SecurityException occurred while attempting to load the resource bundle, defaulting to English."
+ se);
se.printStackTrace();
System.err.flush();
}
if (is == null) {
// No matching data file for the requested langauge,
// defaulting to English
data = null;
} else {
data = readDataFile(is);
}
}
private Int2ObjectOpenHashMap readDataFile(InputStream is) {
Int2ObjectOpenHashMap map = new Int2ObjectOpenHashMap();
boolean complete = false;
BufferedReader input = null;
try {
input = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8));
String line = null;
while ((line = input.readLine()) != null) {
int equalSign = line.indexOf('=');
String idAsString = line.substring(0, equalSign - 1).trim();
// The +2 is because we need to skip the "= ", we dont use trim because some messages want
// leading whitespace
String message = line.substring(equalSign + 2).replaceAll("\\\\n", "\n");
try {
int id = Integer.parseInt(idAsString);
map.put(id, message);
} catch (NumberFormatException nfe) {
// unit tests should prevent this from happening in a customer situation
throw new InternalGemFireException(nfe);
}
complete = true;
}
} catch (IOException ioe) {
// @TODO log this exception
} finally {
if (!complete) {
// something went wrong, clean up and revert back to English
try {
if (input != null) {
input.close();
} else {
is.close();
}
} catch (IOException ignore) {
}
// set map back to null so we default to English
map = null;
}
}
return map;
}
private AbstractStringIdResourceBundle() {
// Intentionally blank
}
/**
* @param key StringId passed for translation.
* @return a String translated to the current {@link java.util.Locale}
*/
public String getString(StringId key) {
if (usingRawMode()) {
return key.getRawText();
}
String txt = (String) data.get(key.id);
if (txt != null) {
return txt;
} else {
// found an untranslated message, use the English as a fall back
return key.getRawText();
}
}
/**
* Returns true if this resource bundle will always return english strings.
*/
public boolean usingRawMode() {
return data == null;
}
public static AbstractStringIdResourceBundle getBundle(String baseName, Locale l) {
AbstractStringIdResourceBundle newMessageBundle = new AbstractStringIdResourceBundle();
newMessageBundle.initData(baseName, l);
return newMessageBundle;
}
}