Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /*
   This is free and unencumbered software released into the public domain.
  
   Anyone is free to copy, modify, publish, use, compile, sell, or
   distribute this software, either in source code form or as a compiled
   binary, for any purpose, commercial or non-commercial, and by any
   means.
  
   In jurisdictions that recognize copyright laws, the author or authors
  of this software dedicate any and all copyright interest in the
  software to the public domain. We make this dedication for the benefit
  of the public at large and to the detriment of our heirs and
  successors. We intend this dedication to be an overt act of
  relinquishment in perpetuity of all present and future rights to this
  software under copyright law.
 
  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
  OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  OTHER DEALINGS IN THE SOFTWARE.
  */
 package base.text;
 
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
Cache all available translations of text strings discovered within the application. Each newly discovered string may be persisted to the database. Each string persisted in the database may have a corresponding translation in any language. Initialise on web application startup as follows:

 LocalText.instance(dataSource);
 
At run time, text strings are looked up using the static helper function:

 LocalText.local("Sample text", locale);
 
Request that any recently newly discovered text is persisted back into the database:

 LocalText.instance().persistNewTextForTranslation();
 
Translation helper functions
The following methods are used to view and update text translations.

Search for a particular keyword in any string in any language:

 List<String> items = LocalText.instance().search("keyword");
 
Search for a particular keyword in any string in a pre-defined language, or null for the default text:

 List<String> items = LocalText.instance().search("en", "keyword");
 
Update the application with a new translation of a particular text string:

 LocalText.instance().translate(hash, "en", "This is the english version of the string");
 
 
 public class LocalText {
 
 	private static LocalText instance;
 
 	public static LocalText instance(DataSource dsthrows IOException {
 		if( == null) {
 			 = new LocalText(ds);
 		}
 		return ;
 	}
 
 	public static String local(String textString language) {
 		if( == null) {
			throw new IllegalStateException("LocalText.instance() must be called before LocalText.local()");
		}
		return .getTranslation(textlanguage);
	}
	public static String local(String textLocale locale) {
		if( == null) {
			throw new IllegalStateException("LocalText.instance() must be called before LocalText.local()");
		}
		return .getTranslation(textlocale.getLanguage() +"_" + locale.getCountry());
	}
	private Map<IntegerStringdefaults = new Hashtable<IntegerString>();
	private Map<StringMap<IntegerString>> strings = new Hashtable<StringMap<IntegerString>>();
	private DataSource ds;

Instantiate an instance of a LocalText cache, backed by a JDBC data source.

Parameters:
ds
Throws:
java.io.IOException
	public LocalText(DataSource dsthrows IOException {
		this. = ds;
	}

If a translation exists for the `text` parameter, return the translation, otherwise return the `text` parameter itself.

Parameters:
text Default text to display to the end user.
language Language to check for translated version of the text.
Returns:
Returns the `text` input parameter unless a translation exists.
	public String getTranslation(String textString language) {
		String result = null;
		Integer hash = text.hashCode();
		if(.containsKey(language)) {
			result = .get(language).get(hash);
		}
		if(result == null) {
			result = text;
			if(!.containsKey(hash)) {
				.put(hashtext);
			}
		}
		return result;
	}
	public String getTranslation(String textLocale locale) {
		return local(textlocale.getLanguage() +"_" + locale.getCountry());
	}

Should be called on a regular scheduled interval by the web application, to ensure any as yet untranslated text is added to the list of text strings.

	public void persistNewTextForTranslation() throws IOException {
		Connection c = null;
		PreparedStatement p1 = null;
		PreparedStatement p2 = null;
		ResultSet r = null;
		Set<Stringuncommitted = new HashSet<String>();
		try {
			p2 = c.prepareStatement("select t_hash from translations where t_hash=? and t_lang='default'");
			p1 = c.prepareStatement("insert into translations (t_hash,t_text,t_lang) values(?,?,'default')");
			uncommitted.addAll(items);
			for(String text : items) {
				p2.setInt(1, text.hashCode());
				r = p2.executeQuery();
				if(!r.next()) {
					p1.setInt(1, text.hashCode());
					p1.setString(2, text);
					p1.execute();
					uncommitted.remove(text);
				}
				r.close();
				r = null;
			}
catch(SQLException e) {
			throw new IOException(e);
finally {
			if(r != null) { try { r.close(); } catch(SQLException e) {} }
			if(p1 != null) { try { p1.close(); } catch(SQLException e) {} }
			if(p2 != null) { try { p2.close(); } catch(SQLException e) {} }
			if(c != null) { try { c.close(); } catch(SQLException e) {} }
			// If some sort of error results in saved text not being persisted, put
			// it back on the queue for later.
			for(String item : uncommitted) {
			}
		}
	}
	public void translate(int hashString languageString newTextthrows SQLException {
		if(language == null || language.equalsIgnoreCase("default")) {
			throw new IllegalArgumentException("May not directly define default text at this time.");
		}
		Connection c = null;
		PreparedStatement p1 = null;
		PreparedStatement p2 = null;
		PreparedStatement p3 = null;
		ResultSet r = null;
		try {
			p3 = c.prepareStatement("select t_hash from translations where t_hash=? and t_lang='default'");
			p3.setInt(1, hash);
			r = p3.executeQuery();
			boolean hasDefault = true;
			if(!r.next()) {
				hasDefault = false;
			}
			r.close();
			r = null;
			p3.close();
			p3 = null;
			if(!hasDefault) {
				throw new IllegalArgumentException("Attempting to define a translation for a hash with no default text string.");
			}
			p2 = c.prepareStatement("select t_hash from translations where t_hash=? and t_lang=?");
			p2.setInt(1, hash);
			p2.setString(2, language);
			r = p2.executeQuery();
			if(!r.next()) {
				if(newText != null) {
					p1 = c.prepareStatement("insert into translations (t_hash,t_text,t_lang) values(?,?,?)");
					p1.setInt(1, hash);
					p1.setString(2, newText);
					p1.setString(3, language);
					p1.execute();
				}
else {
				if(newText == null) {
					p1 = c.prepareStatement("delete from translations where t_hash=? and t_lang=?");
					p1.setInt(1, hash);
					p1.setString(2, language);
					p1.execute();
else {
					p1 = c.prepareStatement("update translations set t_text=? where t_hash=? and t_lang=?");
					p1.setString(1, newText);
					p1.setInt(2, hash);
					p1.setString(3, language);
					p1.execute();
				}
			}
			r.close();
			r = null;
finally {
			if(r != null) { r.close(); }
			if(p1 != null) { p1.close(); }
			if(p2 != null) { p2.close(); }
			if(p3 != null) { p3.close(); }
			if(c != null) { c.close(); }
		}
		if(!.containsKey(language)) {
			.put(languagenew Hashtable<IntegerString>());
		}
		if(newText != null) {
			.get(language).put(hashnewText);
else {
			.get(language).remove(hash);
		}
	}

Called on web application startup to trigger loading all available translations from the database.

	private void loadTranslationsFromDatabase() throws IOException {
		Connection c = null;
		PreparedStatement p = null;
		ResultSet r = null;
		try {
			p = c.prepareStatement("select t_hash, t_text, t_lang from translations");
			r = p.executeQuery();
			while(r.next()) {
				int hash = r.getInt(1);
				String text = r.getString(2);
				String language = r.getString(3);
				if(text == null) {
					continue;
				}
				if(language.equalsIgnoreCase("default")) {
					.put(hashtext);
else {
					if(!.containsKey(language)) {
						.put(languagenew Hashtable<IntegerString>());
					}
					.get(language).put(hashtext);
				}
			}
			r.close();
			r = null;
catch(SQLException e) {
			throw new IOException(e);
finally {
			if(r != null) { try { r.close(); } catch(SQLException e) {} }
			if(p != null) { try { p.close(); } catch(SQLException e) {} }
			if(c != null) { try { c.close(); } catch(SQLException e) {} }
		}
	}

	public List<LocalTranslationsearch(String keywordthrows IOException {
		Connection c = null;
		PreparedStatement p = null;
		ResultSet r = null;
		try {
			p = c.prepareStatement("select t_hash, t_text, t_lang from translations where t_text like lower(?) order by t_hash");
			if(keyword == null || keyword.length() == 0 || keyword.equals("%") || keyword.equals("*")) {
				keyword = "%";
else {
				if(!keyword.contains("%")) {
					keyword = "%" + keyword.toLowerCase() + "%";
else {
					keyword = keyword.toLowerCase();
				}
			}
			p.setString(1, keyword);
			r = p.executeQuery();
			while(r.next()) {
				results.add(new LocalTranslation(r.getInt(1), r.getString(3), r.getString(2)));
			}
catch(SQLException e) {
			throw new IOException(e);
finally {
			if(r != null) { try { r.close(); } catch(SQLException e) {} }
			if(p != null) { try { p.close(); } catch(SQLException e) {} }
			if(c != null) { try { c.close(); } catch(SQLException e) {} }
		}
		return results;
	}

Export all translations, including the default translation, groupd by language.

		Connection c = null;
		PreparedStatement p = null;
		ResultSet r = null;
		Map<IntegerLocalTranslationSettranslationSets = new Hashtable<>();
		try {
					"select t_hash, t_text, t_lang from translations where t_lang='default' " +
					"union " +
					"select t_hash, t_text, t_lang from translations where t_lang!='default' "
					);
			r = p.executeQuery();
			while(r.next()) {
				if(r.getString(3).equals("default")) {
					translationSets.put(r.getInt(1), new LocalTranslationSet(r.getInt(1), r.getString(2)));
else {
					LocalTranslationSet i = translationSets.get(r.getInt(1));
					if(i == null) {
						..println("Missing default text for string: " + r.getString(2) + ":" + r.getString(3));
else {
						i.addText(r.getString(3), r.getString(2));
					}
				}
			}
catch(SQLException e) {
			throw new IOException(e);
finally {
			if(r != null) { try { r.close(); } catch(SQLException e) {} }
			if(p != null) { try { p.close(); } catch(SQLException e) {} }
			if(c != null) { try { c.close(); } catch(SQLException e) {} }
		}
		return translationSets.values();
	}

	public List<LocalTranslationsearch(int hashthrows IOException {
		Connection c = null;
		PreparedStatement p = null;
		ResultSet r = null;
		try {
			p = c.prepareStatement("select t_hash, t_text, t_lang from translations where t_hash=? order by t_lang");
			p.setInt(1, hash);
			r = p.executeQuery();
			while(r.next()) {
				results.add(new LocalTranslation(r.getInt(1), r.getString(3), r.getString(2)));
			}
catch(SQLException e) {
			throw new IOException(e);
finally {
			if(r != null) { try { r.close(); } catch(SQLException e) {} }
			if(p != null) { try { p.close(); } catch(SQLException e) {} }
			if(c != null) { try { c.close(); } catch(SQLException e) {} }
		}
		return results;
	}

Wipe all information about translations from memory and from the database. Used by the test cases to reset test data.

	public void wipe() throws SQLException {
		Connection c = null;
		PreparedStatement p = null;
		try {
			p = c.prepareStatement("delete from translations");
			 = new Hashtable<>();
			 = new Hashtable<>();
finally {
			if(p != null) { p.close(); }
			if(c != null) { c.close(); }
		}
	}

Add new strings that require translation.

Parameters:
text
	private synchronized void registerNewTextForTranslation(String text) {
	}

Retrieve the list of recently discovered strings that require translation.

Returns:
List of recently discovered strings that need translation.
	private synchronized Set<StringnewTextForTranslation() {
		return items;
	}

Create the translations database table. Rather than trying to guess which database type we are talking to, just issue create statements for both MySQL and/or Oracle to see which one sticks.

Parameters:
c
	private void createTable(Connection c) {
		PreparedStatement s = null;
		try {
					"create table translations (" +
					"	t_hash integer, "+
					"	t_lang nvarchar2(32), " +
					"	t_text nvarchar2(254), " +
					"	CONSTRAINT translations_pk PRIMARY KEY (t_hash,t_lang)) ");
catch(SQLException e) {
			// Fails if table already exists, or this is not Oracle.
finally {
			if(s != null) { try { s.close(); s = null; } catch(Exception f){} }
		}
		try {
					"create table if not exists translations (" +
					"	t_hash integer, " +
					"	t_lang varchar(32), "+
					"	t_text varchar(254), "+
					"	PRIMARY KEY(t_hash,t_lang)) ENGINE=InnoDB DEFAULT CHARSET=utf8");
catch(SQLException e) {
			// Fails if this is not MySQL
finally {
			if(s != null) { try { s.close(); } catch(Exception f){} }
		}
	}
New to GrepCode? Check out our FAQ X