forked from upstream-mirrors/OpenTracks
merge messages
This commit is contained in:
@@ -5,3 +5,5 @@ syntax:glob
|
|||||||
*/proguard/**
|
*/proguard/**
|
||||||
.metadata
|
.metadata
|
||||||
MyTracksTest/annotations.log
|
MyTracksTest/annotations.log
|
||||||
|
**/*.pyc
|
||||||
|
**/*.pyo
|
||||||
|
|||||||
@@ -96,6 +96,7 @@ limitations under the License.
|
|||||||
<!-- Common -->
|
<!-- Common -->
|
||||||
<string name="no">Não</string>
|
<string name="no">Não</string>
|
||||||
<string name="yes">Sim</string>
|
<string name="yes">Sim</string>
|
||||||
|
<!-- KEEP_PARENT name="ok" rev="7cbb95c69f35" -->
|
||||||
<string name="error">Erro</string>
|
<string name="error">Erro</string>
|
||||||
<string name="success">Successo</string>
|
<string name="success">Successo</string>
|
||||||
<string name="waypoint">Ponto de passagem</string>
|
<string name="waypoint">Ponto de passagem</string>
|
||||||
|
|||||||
@@ -362,6 +362,12 @@ public class MyTracks extends TabActivity implements OnTouchListener,
|
|||||||
Log.d(TAG, "MyTracks.onStart");
|
Log.d(TAG, "MyTracks.onStart");
|
||||||
super.onStart();
|
super.onStart();
|
||||||
dataHub.start();
|
dataHub.start();
|
||||||
|
|
||||||
|
// Ensure that service is running if we're supposed to be recording
|
||||||
|
if (dataHub.isRecording()) {
|
||||||
|
Intent startIntent = new Intent(this, TrackRecordingService.class);
|
||||||
|
startService(startIntent);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ import com.google.android.apps.mytracks.content.TrackPointsColumns;
|
|||||||
import com.google.android.apps.mytracks.content.TracksColumns;
|
import com.google.android.apps.mytracks.content.TracksColumns;
|
||||||
import com.google.android.apps.mytracks.content.Waypoint;
|
import com.google.android.apps.mytracks.content.Waypoint;
|
||||||
import com.google.android.apps.mytracks.content.WaypointsColumns;
|
import com.google.android.apps.mytracks.content.WaypointsColumns;
|
||||||
import com.google.android.apps.mytracks.services.TrackRecordingService;
|
|
||||||
import com.google.android.apps.mytracks.util.ApiFeatures;
|
import com.google.android.apps.mytracks.util.ApiFeatures;
|
||||||
import com.google.android.apps.mytracks.util.LocationUtils;
|
import com.google.android.apps.mytracks.util.LocationUtils;
|
||||||
import com.google.android.maps.mytracks.R;
|
import com.google.android.maps.mytracks.R;
|
||||||
@@ -281,17 +280,7 @@ public class TrackDataHub {
|
|||||||
started = true;
|
started = true;
|
||||||
|
|
||||||
sharedPreferences.registerOnSharedPreferenceChangeListener(preferenceListener);
|
sharedPreferences.registerOnSharedPreferenceChangeListener(preferenceListener);
|
||||||
selectedTrackId = sharedPreferences.getLong(SELECTED_TRACK_KEY, -1);
|
loadSharedPreferences();
|
||||||
recordingTrackId = sharedPreferences.getLong(RECORDING_TRACK_KEY, -1);
|
|
||||||
useMetricUnits = sharedPreferences.getBoolean(METRIC_UNITS_KEY, true);
|
|
||||||
reportSpeed = sharedPreferences.getBoolean(SPEED_REPORTING_KEY, true);
|
|
||||||
minRequiredAccuracy = sharedPreferences.getInt(MIN_REQUIRED_ACCURACY_KEY,
|
|
||||||
Constants.DEFAULT_MIN_REQUIRED_ACCURACY);
|
|
||||||
|
|
||||||
if (recordingTrackId > 0) {
|
|
||||||
Intent startIntent = new Intent(context, TrackRecordingService.class);
|
|
||||||
context.startService(startIntent);
|
|
||||||
}
|
|
||||||
|
|
||||||
// This may or may not register internal listeners, depending on whether
|
// This may or may not register internal listeners, depending on whether
|
||||||
// we already had external listeners.
|
// we already had external listeners.
|
||||||
@@ -302,6 +291,15 @@ public class TrackDataHub {
|
|||||||
reloadDataFor(getRegisteredListenerArray());
|
reloadDataFor(getRegisteredListenerArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void loadSharedPreferences() {
|
||||||
|
selectedTrackId = sharedPreferences.getLong(SELECTED_TRACK_KEY, -1);
|
||||||
|
recordingTrackId = sharedPreferences.getLong(RECORDING_TRACK_KEY, -1);
|
||||||
|
useMetricUnits = sharedPreferences.getBoolean(METRIC_UNITS_KEY, true);
|
||||||
|
reportSpeed = sharedPreferences.getBoolean(SPEED_REPORTING_KEY, true);
|
||||||
|
minRequiredAccuracy = sharedPreferences.getInt(MIN_REQUIRED_ACCURACY_KEY,
|
||||||
|
Constants.DEFAULT_MIN_REQUIRED_ACCURACY);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stops listening to data sources and reporting the data to external
|
* Stops listening to data sources and reporting the data to external
|
||||||
* listeners.
|
* listeners.
|
||||||
@@ -396,26 +394,31 @@ public class TrackDataHub {
|
|||||||
|
|
||||||
/** Returns the ID of the currently-selected track. */
|
/** Returns the ID of the currently-selected track. */
|
||||||
public long getSelectedTrackId() {
|
public long getSelectedTrackId() {
|
||||||
checkStarted();
|
if (!started) {
|
||||||
|
loadSharedPreferences();
|
||||||
|
}
|
||||||
return selectedTrackId;
|
return selectedTrackId;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns whether there's a track currently selected. */
|
/** Returns whether there's a track currently selected. */
|
||||||
public boolean isATrackSelected() {
|
public boolean isATrackSelected() {
|
||||||
checkStarted();
|
return getSelectedTrackId() > 0;
|
||||||
return selectedTrackId > 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns whether we're currently recording a track. */
|
/** Returns whether we're currently recording a track. */
|
||||||
public boolean isRecording() {
|
public boolean isRecording() {
|
||||||
checkStarted();
|
if (!started) {
|
||||||
|
loadSharedPreferences();
|
||||||
|
}
|
||||||
return recordingTrackId > 0;
|
return recordingTrackId > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns whether the selected track is still being recorded. */
|
/** Returns whether the selected track is still being recorded. */
|
||||||
public boolean isRecordingSelected() {
|
public boolean isRecordingSelected() {
|
||||||
checkStarted();
|
if (!started) {
|
||||||
return isRecording() && recordingTrackId == selectedTrackId;
|
loadSharedPreferences();
|
||||||
|
}
|
||||||
|
return recordingTrackId > 0 && recordingTrackId == selectedTrackId;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<projectDescription>
|
||||||
|
<name>i18n</name>
|
||||||
|
<comment></comment>
|
||||||
|
<projects>
|
||||||
|
</projects>
|
||||||
|
<buildSpec>
|
||||||
|
<buildCommand>
|
||||||
|
<name>org.python.pydev.PyDevBuilder</name>
|
||||||
|
<arguments>
|
||||||
|
</arguments>
|
||||||
|
</buildCommand>
|
||||||
|
</buildSpec>
|
||||||
|
<natures>
|
||||||
|
<nature>org.python.pydev.pythonNature</nature>
|
||||||
|
</natures>
|
||||||
|
</projectDescription>
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<?eclipse-pydev version="1.0"?>
|
||||||
|
|
||||||
|
<pydev_project>
|
||||||
|
<pydev_property name="org.python.pydev.PYTHON_PROJECT_INTERPRETER">Default</pydev_property>
|
||||||
|
<pydev_property name="org.python.pydev.PYTHON_PROJECT_VERSION">python 2.6</pydev_property>
|
||||||
|
<pydev_pathproperty name="org.python.pydev.PROJECT_SOURCE_PATH">
|
||||||
|
<path>/i18n/src</path>
|
||||||
|
</pydev_pathproperty>
|
||||||
|
</pydev_project>
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
'''
|
||||||
|
Module for dealing with resource files (but not their contents).
|
||||||
|
|
||||||
|
@author: Rodrigo Damazio
|
||||||
|
'''
|
||||||
|
import os.path
|
||||||
|
from glob import glob
|
||||||
|
import re
|
||||||
|
|
||||||
|
MYTRACKS_RES_DIR = 'MyTracks/res'
|
||||||
|
ANDROID_MASTER_VALUES = 'values'
|
||||||
|
ANDROID_VALUES_MASK = 'values-*'
|
||||||
|
|
||||||
|
|
||||||
|
def GetMyTracksDir():
|
||||||
|
'''
|
||||||
|
Returns the directory in which the MyTracks directory is located.
|
||||||
|
'''
|
||||||
|
path = os.getcwd()
|
||||||
|
while not os.path.isdir(os.path.join(path, MYTRACKS_RES_DIR)):
|
||||||
|
if path == '/':
|
||||||
|
raise 'Not in My Tracks project'
|
||||||
|
|
||||||
|
# Go up one level
|
||||||
|
path = os.path.split(path)[0]
|
||||||
|
|
||||||
|
return path
|
||||||
|
|
||||||
|
|
||||||
|
def GetAllLanguageFiles():
|
||||||
|
'''
|
||||||
|
Returns a mapping from all found languages to their respective directories.
|
||||||
|
'''
|
||||||
|
mytracks_path = GetMyTracksDir()
|
||||||
|
res_dir = os.path.join(mytracks_path, MYTRACKS_RES_DIR, ANDROID_VALUES_MASK)
|
||||||
|
language_dirs = glob(res_dir)
|
||||||
|
master_dir = os.path.join(mytracks_path, MYTRACKS_RES_DIR, ANDROID_MASTER_VALUES)
|
||||||
|
if len(language_dirs) == 0:
|
||||||
|
raise 'No languages found!'
|
||||||
|
if not os.path.isdir(master_dir):
|
||||||
|
raise 'Couldn\'t find master file'
|
||||||
|
|
||||||
|
language_tuples = [(re.findall(r'.*values-([A-Za-z-]+)', dir)[0],dir) for dir in language_dirs]
|
||||||
|
language_tuples.append(('en', master_dir))
|
||||||
|
return dict(language_tuples)
|
||||||
@@ -0,0 +1,94 @@
|
|||||||
|
'''
|
||||||
|
Module which brings history information about files from Mercurial.
|
||||||
|
|
||||||
|
@author: Rodrigo Damazio
|
||||||
|
'''
|
||||||
|
|
||||||
|
import re
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
REVISION_REGEX = re.compile(r'(?P<hash>[0-9a-f]{12}):.*')
|
||||||
|
|
||||||
|
def _GetOutputLines(args):
|
||||||
|
'''
|
||||||
|
Runs an external process and returns its output as a list of lines.
|
||||||
|
|
||||||
|
@param args: the arguments to run
|
||||||
|
'''
|
||||||
|
process = subprocess.Popen(args,
|
||||||
|
stdout=subprocess.PIPE,
|
||||||
|
universal_newlines = True,
|
||||||
|
shell = False)
|
||||||
|
output = process.communicate()[0]
|
||||||
|
return output.splitlines()
|
||||||
|
|
||||||
|
|
||||||
|
def FillMercurialRevisions(filename, parsed_file):
|
||||||
|
'''
|
||||||
|
Fills the revs attribute of all strings in the given parsed file with
|
||||||
|
a list of revisions that touched the lines corresponding to that string.
|
||||||
|
|
||||||
|
@param filename: the name of the file to get history for
|
||||||
|
@param parsed_file: the parsed file to modify
|
||||||
|
'''
|
||||||
|
# Take output of hg annotate to get revision of each line
|
||||||
|
output_lines = _GetOutputLines(['hg', 'annotate', '-c', filename])
|
||||||
|
|
||||||
|
# Create a map of line -> revision (key is list index, line 0 doesn't exist)
|
||||||
|
line_revs = ['dummy']
|
||||||
|
for line in output_lines:
|
||||||
|
rev_match = REVISION_REGEX.match(line)
|
||||||
|
if not rev_match:
|
||||||
|
raise 'Unexpected line of output from hg: %s' % line
|
||||||
|
rev_hash = rev_match.group('hash')
|
||||||
|
line_revs.append(rev_hash)
|
||||||
|
|
||||||
|
for str in parsed_file.itervalues():
|
||||||
|
# Get the lines that correspond to each string
|
||||||
|
start_line = str['startLine']
|
||||||
|
end_line = str['endLine']
|
||||||
|
|
||||||
|
# Get the revisions that touched those lines
|
||||||
|
revs = []
|
||||||
|
for line_number in range(start_line, end_line + 1):
|
||||||
|
revs.append(line_revs[line_number])
|
||||||
|
|
||||||
|
# Merge with any revisions that were already there
|
||||||
|
# (for explict revision specification)
|
||||||
|
if 'revs' in str:
|
||||||
|
revs += str['revs']
|
||||||
|
|
||||||
|
# Assign the revisions to the string
|
||||||
|
str['revs'] = frozenset(revs)
|
||||||
|
|
||||||
|
def DoesRevisionSuperceed(filename, rev1, rev2):
|
||||||
|
'''
|
||||||
|
Tells whether a revision superceeds another.
|
||||||
|
This essentially means that the older revision is an ancestor of the newer
|
||||||
|
one.
|
||||||
|
This also returns True if the two revisions are the same.
|
||||||
|
|
||||||
|
@param rev1: the revision that may be superceeding the other
|
||||||
|
@param rev2: the revision that may be superceeded
|
||||||
|
@return: True if rev1 superceeds rev2 or they're the same
|
||||||
|
'''
|
||||||
|
if rev1 == rev2:
|
||||||
|
return True
|
||||||
|
|
||||||
|
# TODO: Add filename
|
||||||
|
args = ['hg', 'log', '-r', 'ancestors(%s)' % rev1, '--template', '{node|short}\n', filename]
|
||||||
|
output_lines = _GetOutputLines(args)
|
||||||
|
|
||||||
|
return rev2 in output_lines
|
||||||
|
|
||||||
|
def NewestRevision(filename, rev1, rev2):
|
||||||
|
'''
|
||||||
|
Returns which of two revisions is closest to the head of the repository.
|
||||||
|
If none of them is the ancestor of the other, then we return either one.
|
||||||
|
|
||||||
|
@param rev1: the first revision
|
||||||
|
@param rev2: the second revision
|
||||||
|
'''
|
||||||
|
if DoesRevisionSuperceed(filename, rev1, rev2):
|
||||||
|
return rev1
|
||||||
|
return rev2
|
||||||
Executable
+96
@@ -0,0 +1,96 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
'''
|
||||||
|
Entry point for My Tracks i18n tool.
|
||||||
|
|
||||||
|
@author: Rodrigo Damazio
|
||||||
|
'''
|
||||||
|
|
||||||
|
import mytracks.files
|
||||||
|
import mytracks.translate
|
||||||
|
import mytracks.validate
|
||||||
|
import sys
|
||||||
|
|
||||||
|
def Usage():
|
||||||
|
print 'Usage: %s <command> [<language> ...]\n' % sys.argv[0]
|
||||||
|
print 'Commands are:'
|
||||||
|
print ' cleanup'
|
||||||
|
print ' translate'
|
||||||
|
print ' validate'
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
def Translate(languages):
|
||||||
|
'''
|
||||||
|
Asks the user to interactively translate any missing or oudated strings from
|
||||||
|
the files for the given languages.
|
||||||
|
|
||||||
|
@param languages: the languages to translate
|
||||||
|
'''
|
||||||
|
validator = mytracks.validate.Validator(languages)
|
||||||
|
validator.Validate()
|
||||||
|
missing = validator.missing_in_lang()
|
||||||
|
outdated = validator.outdated_in_lang()
|
||||||
|
|
||||||
|
for lang in languages:
|
||||||
|
untranslated = missing[lang] + outdated[lang]
|
||||||
|
|
||||||
|
if len(untranslated) == 0:
|
||||||
|
continue
|
||||||
|
|
||||||
|
translator = mytracks.translate.Translator(lang)
|
||||||
|
translator.Translate(untranslated)
|
||||||
|
|
||||||
|
|
||||||
|
def Validate(languages):
|
||||||
|
'''
|
||||||
|
Computes and displays errors in the string files for the given languages.
|
||||||
|
|
||||||
|
@param languages: the languages to compute for
|
||||||
|
'''
|
||||||
|
validator = mytracks.validate.Validator(languages)
|
||||||
|
validator.Validate()
|
||||||
|
|
||||||
|
error_count = 0
|
||||||
|
if (validator.valid()):
|
||||||
|
print 'All files OK'
|
||||||
|
else:
|
||||||
|
for lang, missing in validator.missing_in_master().iteritems():
|
||||||
|
print 'Missing in master, present in %s: %s:' % (lang, str(missing))
|
||||||
|
error_count = error_count + len(missing)
|
||||||
|
for lang, missing in validator.missing_in_lang().iteritems():
|
||||||
|
print 'Missing in %s, present in master: %s:' % (lang, str(missing))
|
||||||
|
error_count = error_count + len(missing)
|
||||||
|
for lang, outdated in validator.outdated_in_lang().iteritems():
|
||||||
|
print 'Outdated in %s: %s:' % (lang, str(outdated))
|
||||||
|
error_count = error_count + len(outdated)
|
||||||
|
|
||||||
|
return error_count
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
argv = sys.argv
|
||||||
|
argc = len(argv)
|
||||||
|
if argc < 2:
|
||||||
|
Usage()
|
||||||
|
|
||||||
|
languages = mytracks.files.GetAllLanguageFiles()
|
||||||
|
if argc == 3:
|
||||||
|
langs = set(argv[2:])
|
||||||
|
if not langs.issubset(languages):
|
||||||
|
raise 'Language(s) not found'
|
||||||
|
|
||||||
|
# Filter just to the languages specified
|
||||||
|
languages = dict((lang, lang_file)
|
||||||
|
for lang, lang_file in languages.iteritems()
|
||||||
|
if lang in langs or lang == 'en' )
|
||||||
|
|
||||||
|
cmd = argv[1]
|
||||||
|
if cmd == 'translate':
|
||||||
|
Translate(languages)
|
||||||
|
elif cmd == 'validate':
|
||||||
|
error_count = Validate(languages)
|
||||||
|
else:
|
||||||
|
Usage()
|
||||||
|
error_count = 0
|
||||||
|
|
||||||
|
print '%d errors found.' % error_count
|
||||||
@@ -0,0 +1,115 @@
|
|||||||
|
'''
|
||||||
|
Module which parses a string XML file.
|
||||||
|
|
||||||
|
@author: Rodrigo Damazio
|
||||||
|
'''
|
||||||
|
|
||||||
|
from xml.parsers.expat import ParserCreate
|
||||||
|
import re
|
||||||
|
#import xml.etree.ElementTree as ET
|
||||||
|
|
||||||
|
class StringsParser(object):
|
||||||
|
'''
|
||||||
|
Parser for string XML files.
|
||||||
|
|
||||||
|
This object is not thread-safe and should be used for parsing a single file at
|
||||||
|
a time, only.
|
||||||
|
'''
|
||||||
|
|
||||||
|
def Parse(self, file):
|
||||||
|
'''
|
||||||
|
Parses the given file and returns a dictionary mapping keys to an object
|
||||||
|
with attributes for that key, such as the value, start/end line and explicit
|
||||||
|
revisions.
|
||||||
|
|
||||||
|
In addition to the standard XML format of the strings file, this parser
|
||||||
|
supports an annotation inside comments, in one of these formats:
|
||||||
|
|
||||||
|
<!-- KEEP_PARENT name="bla" -->
|
||||||
|
<!-- KEEP_PARENT name="bla" rev="123456789012" -->
|
||||||
|
|
||||||
|
Such an annotation indicates that we're explicitly inheriting form the
|
||||||
|
master file (and the optional revision says that this decision is compatible
|
||||||
|
with the master file up to that revision).
|
||||||
|
|
||||||
|
@param file: the name of the file to parse
|
||||||
|
'''
|
||||||
|
self._Reset()
|
||||||
|
|
||||||
|
# Unfortunately expat is the only parser that will give us line numbers
|
||||||
|
self._xml_parser = ParserCreate()
|
||||||
|
self._xml_parser.StartElementHandler = self._StartElementHandler
|
||||||
|
self._xml_parser.EndElementHandler = self._EndElementHandler
|
||||||
|
self._xml_parser.CharacterDataHandler = self._CharacterDataHandler
|
||||||
|
self._xml_parser.CommentHandler = self._CommentHandler
|
||||||
|
|
||||||
|
file_obj = open(file)
|
||||||
|
self._xml_parser.ParseFile(file_obj)
|
||||||
|
file_obj.close()
|
||||||
|
|
||||||
|
return self._all_strings
|
||||||
|
|
||||||
|
def _Reset(self):
|
||||||
|
self._currentString = None
|
||||||
|
self._currentStringName = None
|
||||||
|
self._currentStringValue = None
|
||||||
|
self._all_strings = {}
|
||||||
|
|
||||||
|
def _StartElementHandler(self, name, attrs):
|
||||||
|
if name != 'string':
|
||||||
|
return
|
||||||
|
|
||||||
|
if 'name' not in attrs:
|
||||||
|
return
|
||||||
|
|
||||||
|
assert not self._currentString
|
||||||
|
assert not self._currentStringName
|
||||||
|
self._currentString = {
|
||||||
|
'startLine' : self._xml_parser.CurrentLineNumber,
|
||||||
|
}
|
||||||
|
|
||||||
|
if 'rev' in attrs:
|
||||||
|
self._currentString['revs'] = [attrs['rev']]
|
||||||
|
|
||||||
|
self._currentStringName = attrs['name']
|
||||||
|
self._currentStringValue = ''
|
||||||
|
|
||||||
|
def _EndElementHandler(self, name):
|
||||||
|
if name != 'string':
|
||||||
|
return
|
||||||
|
|
||||||
|
assert self._currentString
|
||||||
|
assert self._currentStringName
|
||||||
|
self._currentString['value'] = self._currentStringValue
|
||||||
|
self._currentString['endLine'] = self._xml_parser.CurrentLineNumber
|
||||||
|
self._all_strings[self._currentStringName] = self._currentString
|
||||||
|
|
||||||
|
self._currentString = None
|
||||||
|
self._currentStringName = None
|
||||||
|
self._currentStringValue = None
|
||||||
|
|
||||||
|
def _CharacterDataHandler(self, data):
|
||||||
|
if not self._currentString:
|
||||||
|
return
|
||||||
|
|
||||||
|
self._currentStringValue += data
|
||||||
|
|
||||||
|
_KEEP_PARENT_REGEX = re.compile(r'\s*KEEP_PARENT\s+'
|
||||||
|
r'name\s*=\s*[\'"]?(?P<name>[a-z0-9_]+)[\'"]?'
|
||||||
|
r'(?:\s+rev=[\'"]?(?P<rev>[0-9a-f]{12})[\'"]?)?\s*',
|
||||||
|
re.MULTILINE | re.DOTALL)
|
||||||
|
|
||||||
|
def _CommentHandler(self, data):
|
||||||
|
keep_parent_match = self._KEEP_PARENT_REGEX.match(data)
|
||||||
|
if not keep_parent_match:
|
||||||
|
return
|
||||||
|
|
||||||
|
name = keep_parent_match.group('name')
|
||||||
|
self._all_strings[name] = {
|
||||||
|
'keepParent' : True,
|
||||||
|
'startLine' : self._xml_parser.CurrentLineNumber,
|
||||||
|
'endLine' : self._xml_parser.CurrentLineNumber
|
||||||
|
}
|
||||||
|
rev = keep_parent_match.group('rev')
|
||||||
|
if rev:
|
||||||
|
self._all_strings[name]['revs'] = [rev]
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
'''
|
||||||
|
Module which prompts the user for translations and saves them.
|
||||||
|
|
||||||
|
TODO: implement
|
||||||
|
|
||||||
|
@author: Rodrigo Damazio
|
||||||
|
'''
|
||||||
|
|
||||||
|
class Translator(object):
|
||||||
|
'''
|
||||||
|
classdocs
|
||||||
|
'''
|
||||||
|
|
||||||
|
def __init__(self, language):
|
||||||
|
'''
|
||||||
|
Constructor
|
||||||
|
'''
|
||||||
|
self._language = language
|
||||||
|
|
||||||
|
def Translate(self, string_names):
|
||||||
|
print string_names
|
||||||
@@ -0,0 +1,115 @@
|
|||||||
|
'''
|
||||||
|
Module which compares languague files to the master file and detects
|
||||||
|
issues.
|
||||||
|
|
||||||
|
@author: Rodrigo Damazio
|
||||||
|
'''
|
||||||
|
|
||||||
|
import os
|
||||||
|
from mytracks.parser import StringsParser
|
||||||
|
import mytracks.history
|
||||||
|
|
||||||
|
class Validator(object):
|
||||||
|
|
||||||
|
def __init__(self, languages):
|
||||||
|
'''
|
||||||
|
Builds a strings file validator.
|
||||||
|
|
||||||
|
Params:
|
||||||
|
@param languages: a dictionary mapping each language to its corresponding directory
|
||||||
|
'''
|
||||||
|
self._langs = {}
|
||||||
|
self._master = None
|
||||||
|
self._language_paths = languages
|
||||||
|
|
||||||
|
parser = StringsParser()
|
||||||
|
for lang, lang_dir in languages.iteritems():
|
||||||
|
filename = os.path.join(lang_dir, 'strings.xml')
|
||||||
|
parsed_file = parser.Parse(filename)
|
||||||
|
mytracks.history.FillMercurialRevisions(filename, parsed_file)
|
||||||
|
|
||||||
|
if lang == 'en':
|
||||||
|
self._master = parsed_file
|
||||||
|
else:
|
||||||
|
self._langs[lang] = parsed_file
|
||||||
|
|
||||||
|
self._Reset()
|
||||||
|
|
||||||
|
def Validate(self):
|
||||||
|
'''
|
||||||
|
Computes whether all the data in the files for the given languages is valid.
|
||||||
|
'''
|
||||||
|
self._Reset()
|
||||||
|
self._ValidateMissingKeys()
|
||||||
|
self._ValidateOutdatedKeys()
|
||||||
|
|
||||||
|
def valid(self):
|
||||||
|
return (len(self._missing_in_master) == 0 and
|
||||||
|
len(self._missing_in_lang) == 0 and
|
||||||
|
len(self._outdated_in_lang) == 0)
|
||||||
|
|
||||||
|
def missing_in_master(self):
|
||||||
|
return self._missing_in_master
|
||||||
|
|
||||||
|
def missing_in_lang(self):
|
||||||
|
return self._missing_in_lang
|
||||||
|
|
||||||
|
def outdated_in_lang(self):
|
||||||
|
return self._outdated_in_lang
|
||||||
|
|
||||||
|
def _Reset(self):
|
||||||
|
# These are maps from language to string name list
|
||||||
|
self._missing_in_master = {}
|
||||||
|
self._missing_in_lang = {}
|
||||||
|
self._outdated_in_lang = {}
|
||||||
|
|
||||||
|
def _ValidateMissingKeys(self):
|
||||||
|
'''
|
||||||
|
Computes whether there are missing keys on either side.
|
||||||
|
'''
|
||||||
|
master_keys = frozenset(self._master.iterkeys())
|
||||||
|
for lang, file in self._langs.iteritems():
|
||||||
|
keys = frozenset(file.iterkeys())
|
||||||
|
missing_in_master = keys - master_keys
|
||||||
|
missing_in_lang = master_keys - keys
|
||||||
|
|
||||||
|
if len(missing_in_master) > 0:
|
||||||
|
self._missing_in_master[lang] = missing_in_master
|
||||||
|
if len(missing_in_lang) > 0:
|
||||||
|
self._missing_in_lang[lang] = missing_in_lang
|
||||||
|
|
||||||
|
def _ValidateOutdatedKeys(self):
|
||||||
|
'''
|
||||||
|
Computers whether any of the language keys are outdated with relation to the
|
||||||
|
master keys.
|
||||||
|
'''
|
||||||
|
for lang, file in self._langs.iteritems():
|
||||||
|
outdated = []
|
||||||
|
for key, str in file.iteritems():
|
||||||
|
# Get all revisions that touched master and language files for this
|
||||||
|
# string.
|
||||||
|
master_str = self._master[key]
|
||||||
|
master_revs = master_str['revs']
|
||||||
|
lang_revs = str['revs']
|
||||||
|
if not master_revs or not lang_revs:
|
||||||
|
print 'WARNING: No revision for %s in %s' % (key, lang)
|
||||||
|
continue
|
||||||
|
|
||||||
|
master_file = os.path.join(self._language_paths['en'], 'strings.xml')
|
||||||
|
lang_file = os.path.join(self._language_paths[lang], 'strings.xml')
|
||||||
|
|
||||||
|
# Assume that the repository has a single head (TODO: check that),
|
||||||
|
# and as such there is always one revision which superceeds all others.
|
||||||
|
master_rev = reduce(
|
||||||
|
lambda r1, r2: mytracks.history.NewestRevision(master_file, r1, r2),
|
||||||
|
master_revs)
|
||||||
|
lang_rev = reduce(
|
||||||
|
lambda r1, r2: mytracks.history.NewestRevision(lang_file, r1, r2),
|
||||||
|
lang_revs)
|
||||||
|
|
||||||
|
# If the master version is newer than the lang version
|
||||||
|
if mytracks.history.DoesRevisionSuperceed(lang_file, master_rev, lang_rev):
|
||||||
|
outdated.append(key)
|
||||||
|
|
||||||
|
if len(outdated) > 0:
|
||||||
|
self._outdated_in_lang[lang] = outdated
|
||||||
Reference in New Issue
Block a user