mirror of
git://xwords.git.sourceforge.net/gitroot/xwords/xwords
synced 2025-01-29 08:34:37 +01:00
Because loc: strings can't be supplied for all Views, don't do
that. Instead use the English strings themselves as keys. Generate a java array of all R.string.whatever contants at build time, and use that at runtime to build a hashmap of localizable strings that may be found in UI widgets. When one is found and there's a translation, substitute.
This commit is contained in:
parent
b4016eaec3
commit
67bca0dd4e
48 changed files with 156 additions and 105 deletions
|
@ -85,10 +85,12 @@
|
|||
/>
|
||||
|
||||
<exec dir="." executable="../scripts/mk_xml.py"
|
||||
failonerror="true" output="/dev/null"
|
||||
failonerror="true"
|
||||
>
|
||||
<arg value="-o"/>
|
||||
<arg value="src/org/eehouse/android/xw4/loc/LocIDsData.java"/>
|
||||
<arg value="-t"/>
|
||||
<arg value="${build.target}"/>
|
||||
</exec>
|
||||
|
||||
<exec dir="." executable="../scripts/gen_gcmid.sh"
|
||||
|
|
|
@ -1489,7 +1489,7 @@
|
|||
device, and the body that appears when you pull the notifications
|
||||
down. -->
|
||||
<string name="notify_title">Moves made</string>
|
||||
<string name="notify_body_fmt">Activity in game "%1$s"</string>
|
||||
<string name="notify_body_fmt">Activity in game \"%1$s\"</string>
|
||||
|
||||
<!--
|
||||
############################################################
|
||||
|
|
|
@ -20,6 +20,8 @@
|
|||
|
||||
package org.eehouse.android.xw4.loc;
|
||||
|
||||
import android.content.Context;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
|
@ -29,11 +31,12 @@ import org.eehouse.android.xw4.DbgUtils;
|
|||
|
||||
public class LocIDs extends LocIDsData {
|
||||
private static String[] s_keys;
|
||||
private static HashMap<String, Integer> S_MAP = null;
|
||||
|
||||
protected static String getNthKey( int indx )
|
||||
protected static String getNthKey( Context context, int indx )
|
||||
{
|
||||
if ( null == s_keys ) {
|
||||
Map<String, Integer> map = LocIDsData.S_MAP;
|
||||
Map<String, Integer> map = getS_MAP( context );
|
||||
s_keys = new String[map.size()];
|
||||
Iterator<String> iter = map.keySet().iterator();
|
||||
for ( int ii = 0; iter.hasNext(); ++ii ) {
|
||||
|
@ -44,19 +47,33 @@ public class LocIDs extends LocIDsData {
|
|||
return s_keys[indx];
|
||||
}
|
||||
|
||||
protected static int getID( String key )
|
||||
protected static int getID( Context context, String key )
|
||||
{
|
||||
int result = LocIDsData.NOT_FOUND;
|
||||
if ( null != key && LocIDsData.S_MAP.containsKey( key ) ) {
|
||||
Assert.assertNotNull( LocIDsData.S_MAP );
|
||||
if ( null != key && getS_MAP(context).containsKey( key ) ) {
|
||||
// Assert.assertNotNull( LocIDsData.S_MAP );
|
||||
DbgUtils.logf( "calling get with key %s", key );
|
||||
result = LocIDsData.S_MAP.get( key ); // NPE
|
||||
result = getS_MAP( context ).get( key ); // NPE
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
protected static int size()
|
||||
{
|
||||
return LocIDsData.S_MAP.size();
|
||||
return S_IDS.length;
|
||||
}
|
||||
|
||||
protected static HashMap<String, Integer> getS_MAP( Context context )
|
||||
{
|
||||
if ( null == S_MAP ) {
|
||||
S_MAP = new HashMap<String, Integer>(S_IDS.length);
|
||||
for ( int id : S_IDS ) {
|
||||
String str = context.getString( id );
|
||||
S_MAP.put( str, id );
|
||||
}
|
||||
|
||||
LocIDsData.checkStrings( context );
|
||||
}
|
||||
return S_MAP;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,11 +58,8 @@ public class LocListItem extends LinearLayout implements OnFocusChangeListener {
|
|||
|
||||
private void setEnglish()
|
||||
{
|
||||
int id = LocIDs.getID( m_pair.getKey() );
|
||||
String str = m_context.getString( id );
|
||||
TextView tv = (TextView)findViewById( R.id.english_view );
|
||||
tv.setText( str );
|
||||
DbgUtils.logf( "setEnglish: set to %s", str );
|
||||
tv.setText( m_pair.getKey() );
|
||||
}
|
||||
|
||||
private void setXlated()
|
||||
|
|
|
@ -32,6 +32,7 @@ import android.view.ViewGroup;
|
|||
import android.widget.Button;
|
||||
import android.widget.TextView;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.Spinner;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.HashMap;
|
||||
|
@ -49,7 +50,6 @@ import org.eehouse.android.xw4.XWPrefs;
|
|||
public class LocUtils {
|
||||
// Keep this in sync with gen_loc_ids.py and what's used in the menu.xml
|
||||
// files to mark me-localized strings.
|
||||
private static final String LOC_PREFIX = "loc:";
|
||||
private static HashMap<String, String>s_xlations = null;
|
||||
private static HashMap<Integer, String> s_idsToKeys = null;
|
||||
private static Boolean s_enabled = null;
|
||||
|
@ -58,21 +58,21 @@ public class LocUtils {
|
|||
void setText( CharSequence text );
|
||||
}
|
||||
|
||||
public static void loadStrings( Context context, AttributeSet as, LocIface view )
|
||||
{
|
||||
// There should be a way to look up the index of "strid" but I don't
|
||||
// have it yet. This got things working.
|
||||
int count = as.getAttributeCount();
|
||||
for ( int ii = 0; ii < count; ++ii ) {
|
||||
if ( "strid".equals( as.getAttributeName(ii) ) ) {
|
||||
String value = as.getAttributeValue(ii);
|
||||
Assert.assertTrue( '@' == value.charAt(0) );
|
||||
int id = Integer.parseInt( value.substring(1) );
|
||||
view.setText( getString( context, id ) );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// public static void loadStrings( Context context, AttributeSet as, LocIface view )
|
||||
// {
|
||||
// // There should be a way to look up the index of "strid" but I don't
|
||||
// // have it yet. This got things working.
|
||||
// int count = as.getAttributeCount();
|
||||
// for ( int ii = 0; ii < count; ++ii ) {
|
||||
// if ( "strid".equals( as.getAttributeName(ii) ) ) {
|
||||
// String value = as.getAttributeValue(ii);
|
||||
// Assert.assertTrue( '@' == value.charAt(0) );
|
||||
// int id = Integer.parseInt( value.substring(1) );
|
||||
// view.setText( getString( context, id ) );
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
public static View inflate( Context context, int resID )
|
||||
{
|
||||
|
@ -90,15 +90,7 @@ public class LocUtils {
|
|||
public static void xlateView( Context context, View view )
|
||||
{
|
||||
DbgUtils.logf( "xlateView() top level" );
|
||||
HashSet<String> seenClasses = new HashSet<String>();
|
||||
HashSet<String> missedClasses = new HashSet<String>();
|
||||
xlateView( context, view, seenClasses, missedClasses );
|
||||
int ii = 0;
|
||||
for ( Iterator<String> iter = seenClasses.iterator();
|
||||
iter.hasNext(); ) {
|
||||
DbgUtils.logf( "xlateView: seen class[%d]: %s", ii++, iter.next() );
|
||||
}
|
||||
DbgUtils.logf( "xlateView() top level DONE" );
|
||||
xlateView( context, view, 0 );
|
||||
}
|
||||
|
||||
public static void xlateMenu( Activity activity, Menu menu )
|
||||
|
@ -108,13 +100,10 @@ public class LocUtils {
|
|||
|
||||
public static String xlateString( Context context, String str )
|
||||
{
|
||||
if ( str.startsWith( LOC_PREFIX ) ) {
|
||||
str = str.substring( LOC_PREFIX.length() );
|
||||
int id = LocIDs.getID( str );
|
||||
if ( LocIDs.NOT_FOUND != id ) {
|
||||
str = getString( context, id );
|
||||
} else {
|
||||
DbgUtils.logf( "nothing for %s", str );
|
||||
if ( LocIDs.getS_MAP( context ).containsKey( str ) ) {
|
||||
String xlation = getXlation( context, str );
|
||||
if ( null != xlation ) {
|
||||
str = xlation;
|
||||
}
|
||||
}
|
||||
return str;
|
||||
|
@ -137,7 +126,7 @@ public class LocUtils {
|
|||
public static String getString( Context context, int id, Object... params )
|
||||
{
|
||||
String result = null;
|
||||
String key = keyForID( id );
|
||||
String key = keyForID( context, id );
|
||||
if ( null != key ) {
|
||||
result = getXlation( context, key );
|
||||
}
|
||||
|
@ -175,7 +164,7 @@ public class LocUtils {
|
|||
{
|
||||
loadXlations( context );
|
||||
|
||||
Map<String,Integer> map = LocIDsData.S_MAP;
|
||||
Map<String,Integer> map = LocIDs.getS_MAP( context );
|
||||
int siz = map.size();
|
||||
LocSearcher.Pair[] result = new LocSearcher.Pair[siz];
|
||||
Iterator<String> iter = map.keySet().iterator();
|
||||
|
@ -198,15 +187,9 @@ public class LocUtils {
|
|||
CharSequence ts = item.getTitle();
|
||||
if ( null != ts ) {
|
||||
String title = ts.toString();
|
||||
if ( title.startsWith( LOC_PREFIX ) ) {
|
||||
String asKey = title.substring( LOC_PREFIX.length() );
|
||||
int id = LocIDs.getID( asKey );
|
||||
if ( LocIDs.NOT_FOUND != id ) {
|
||||
asKey = getString( activity, id );
|
||||
} else {
|
||||
DbgUtils.logf( "nothing for %s", asKey );
|
||||
}
|
||||
item.setTitle( asKey );
|
||||
if ( LocIDs.getS_MAP( activity ).containsKey(title) ) {
|
||||
title = xlateString( activity, title );
|
||||
item.setTitle( title );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -237,10 +220,10 @@ public class LocUtils {
|
|||
}
|
||||
}
|
||||
|
||||
private static String keyForID( int id )
|
||||
private static String keyForID( Context context, int id )
|
||||
{
|
||||
if ( null == s_idsToKeys ) {
|
||||
Map<String,Integer> map = LocIDsData.S_MAP;
|
||||
Map<String,Integer> map = LocIDs.getS_MAP( context );
|
||||
HashMap<Integer, String> idsToKeys =
|
||||
new HashMap<Integer, String>( map.size() );
|
||||
|
||||
|
@ -264,37 +247,34 @@ public class LocUtils {
|
|||
return s_enabled;
|
||||
}
|
||||
|
||||
private static void xlateView( Context context, View view,
|
||||
HashSet<String> seen,
|
||||
HashSet<String> missed )
|
||||
private static void xlateView( Context context, View view, int depth )
|
||||
{
|
||||
String name = view.getClass().getName();
|
||||
seen.add( name );
|
||||
if ( view instanceof Button ) {
|
||||
Button button = (Button)view;
|
||||
String str = xlateString( context, button.getText().toString() );
|
||||
button.setText( str );
|
||||
} else if ( view instanceof TextView ) {
|
||||
TextView tv = (TextView)view;
|
||||
tv.setText( xlateString( context, tv.getText().toString() ) );
|
||||
// } else if ( view instanceof CheckBox ) {
|
||||
// CheckBox box = (CheckBox)view;
|
||||
// String str = box.getText().toString();
|
||||
// str = xlateString( context, str );
|
||||
// box.setText( str );
|
||||
} else if ( view instanceof Spinner ) {
|
||||
Spinner sp = (Spinner)view;
|
||||
String str = sp.getPrompt().toString();
|
||||
sp.setPrompt( xlateString( context, str ) );
|
||||
}
|
||||
|
||||
// A Spinner, for instance, ISA ViewGroup, so this is a separate test.
|
||||
if ( view instanceof ViewGroup ) {
|
||||
DbgUtils.logf( "xlateView recursing on %s", name );
|
||||
ViewGroup asGroup = (ViewGroup)view;
|
||||
int count = asGroup.getChildCount();
|
||||
for ( int ii = 0; ii < count; ++ii ) {
|
||||
View child = asGroup.getChildAt( ii );
|
||||
xlateView( context, child, seen, missed );
|
||||
xlateView( context, child, depth + 1 );
|
||||
}
|
||||
} else if ( view instanceof Button ) {
|
||||
Button button = (Button)view;
|
||||
String str = button.getText().toString();
|
||||
str = xlateString( context, str );
|
||||
button.setText( str );
|
||||
} else if ( view instanceof TextView ) {
|
||||
TextView tv = (TextView)view;
|
||||
String str = tv.getText().toString();
|
||||
str = xlateString( context, str );
|
||||
tv.setText( str );
|
||||
} else if ( view instanceof CheckBox ) {
|
||||
CheckBox box = (CheckBox)view;
|
||||
String str = box.getText().toString();
|
||||
str = xlateString( context, str );
|
||||
box.setText( str );
|
||||
} else {
|
||||
missed.add( view.getClass().getName() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#!/usr/bin/python
|
||||
|
||||
import glob, sys, re, os, getopt
|
||||
import glob, sys, re, os, getopt, codecs
|
||||
|
||||
from lxml import etree
|
||||
|
||||
|
@ -28,6 +28,7 @@ g_xmlTypes = [
|
|||
g_pairs = {}
|
||||
|
||||
STR_REF = re.compile('@string/(.*)$')
|
||||
CLASS_NAME = re.compile('.*/([^/*]+).java')
|
||||
|
||||
def xform(src, dest):
|
||||
doc = etree.parse(src)
|
||||
|
@ -47,37 +48,87 @@ def xform(src, dest):
|
|||
if not os.path.exists(dir): os.makedirs(dir)
|
||||
doc.write( dest, pretty_print=True )
|
||||
|
||||
def printStrings( pairs, outfile ):
|
||||
fil = open( outfile, "w" )
|
||||
# For my records: you CAN harvest a comment!!!
|
||||
# def loadAndPrint(file):
|
||||
# prevComment = None
|
||||
# doc = etree.parse(file)
|
||||
# for elem in doc.getroot().iter():
|
||||
# if not isinstance( elem.tag, basestring ):
|
||||
# prevComment = elem.text
|
||||
# else:
|
||||
# print "elem:", elem,
|
||||
# if prevComment:
|
||||
# print '//', prevComment
|
||||
# prevComment = None
|
||||
# else:
|
||||
# print
|
||||
# # doc.write( sys.stdout, pretty_print=True )
|
||||
|
||||
def checkText( text ):
|
||||
text = " ".join(re.split('\s+', text)).replace('"', '\"')
|
||||
seen = set()
|
||||
split = re.split( '(%\d\$[sd])', text )
|
||||
for part in split:
|
||||
if 4 <= len(part) and '%' == part[0]:
|
||||
digit = int(part[1:2])
|
||||
if digit in seen:
|
||||
print "ERROR: has duplicate format digit %d (text = %s)" % (digit, text)
|
||||
print "This might not be what you want"
|
||||
seen.add( digit )
|
||||
return text
|
||||
|
||||
def printStrings( pairs, outfile, target ):
|
||||
match = CLASS_NAME.match(outfile)
|
||||
if not match:
|
||||
print "did you give me a java file?:", outfile
|
||||
sys.exit(0)
|
||||
name = match.group(1)
|
||||
fil = codecs.open( outfile, "w", "utf-8" )
|
||||
|
||||
# beginning of the class file
|
||||
lines = """
|
||||
/***********************************************************************
|
||||
* Generated file; do not edit!!!
|
||||
***********************************************************************/
|
||||
|
||||
package org.eehouse.android.xw4.loc;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import android.content.Context;
|
||||
|
||||
import org.eehouse.android.xw4.R;
|
||||
import org.eehouse.android.xw4.DbgUtils;
|
||||
|
||||
public class LocIDsData {
|
||||
public class %s {
|
||||
public static final int NOT_FOUND = -1;
|
||||
|
||||
protected static final Map<String, Integer> S_MAP =
|
||||
Collections.unmodifiableMap(new HashMap<String, Integer>() {{
|
||||
protected static final int[] S_IDS = {
|
||||
"""
|
||||
fil.write( lines )
|
||||
fil.write( lines % name )
|
||||
|
||||
for key in pairs.keys():
|
||||
fil.write( " put(\"%s\", R.string.%s);\n" % (key, key) )
|
||||
fil.write( " R.string.%s,\n" % (key) )
|
||||
|
||||
fil.write( " };\n\n" )
|
||||
|
||||
if "debug" == target:
|
||||
fil.write( " static final String[] strs = {\n")
|
||||
for key in pairs.keys():
|
||||
fil.write( " \"%s\",\n" % pairs[key] )
|
||||
fil.write( " };\n" );
|
||||
|
||||
lines = """
|
||||
protected static void checkStrings( Context context )
|
||||
{
|
||||
for ( int ii = 0; ii < strs.length; ++ii ) {
|
||||
if ( ! strs[ii].equals( context.getString( S_IDS[ii] ) ) ) {
|
||||
DbgUtils.logf( "unequal strings: \\"%s\\" vs \\"%s\\"",
|
||||
strs[ii], S_IDS[ii] );
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
fil.write( lines )
|
||||
|
||||
# Now the end of the class
|
||||
lines = """
|
||||
}});
|
||||
}
|
||||
/* end generated file */
|
||||
"""
|
||||
|
@ -85,23 +136,27 @@ public class LocIDsData {
|
|||
|
||||
def main():
|
||||
outfile = ''
|
||||
pairs, rest = getopt.getopt(sys.argv[1:], "o:")
|
||||
outfileDbg = ''
|
||||
target=''
|
||||
pairs, rest = getopt.getopt(sys.argv[1:], "o:t:d:")
|
||||
for option, value in pairs:
|
||||
if option == '-o': outfile = value
|
||||
elif option == '-t': target = value
|
||||
|
||||
# Gather all localizable strings
|
||||
for path in glob.iglob( "res/values/strings.xml" ):
|
||||
for action, elem in etree.iterparse(path):
|
||||
if "end" == action and 'string' == elem.tag:
|
||||
g_pairs[elem.get('name')] = True
|
||||
if "end" == action and 'string' == elem.tag and elem.text:
|
||||
text = checkText( elem.text )
|
||||
g_pairs[elem.get('name')] = text
|
||||
|
||||
for subdir, dirs, files in os.walk('res_src'):
|
||||
for file in files:
|
||||
src = subdir + '/' + file
|
||||
dest = src.replace( 'res_src', 'res', 1 )
|
||||
xform( src, dest )
|
||||
# for subdir, dirs, files in os.walk('res_src'):
|
||||
# for file in files:
|
||||
# src = subdir + '/' + file
|
||||
# dest = src.replace( 'res_src', 'res', 1 )
|
||||
# xform( src, dest )
|
||||
|
||||
if outfile: printStrings( g_pairs, outfile )
|
||||
if outfile: printStrings( g_pairs, outfile, target )
|
||||
|
||||
|
||||
main()
|
||||
|
|
Loading…
Add table
Reference in a new issue