Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
4e6 committed Aug 12, 2011
0 parents commit 7c3e132
Show file tree
Hide file tree
Showing 6 changed files with 161 additions and 0 deletions.
8 changes: 8 additions & 0 deletions bin/alh.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/bin/sh
#
# Start-up script

L10N_HELPER_HOME=`dirname "$0"`
L10N_HELPER_HOME=`dirname "$L10N_HELPER_HOME"`

java -jar $L10N_HELPER_HOME/lib/l10n-helper.jar $1
1 change: 1 addition & 0 deletions build/MANIFEST.MF
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Main-Class: the4e6.AndroidTranslationsHelper
10 changes: 10 additions & 0 deletions build/build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/bin/sh
#
# Build script. Run from build directory.

cd ../bin

jar -cvmf ../build/MANIFEST.MF ../lib/helper.jar *
cd ../build
java -jar ../lib/proguard.jar @proguard.cfg -verbose
rm ../lib/helper.jar
42 changes: 42 additions & 0 deletions build/proguard.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
-injars ../lib/helper.jar
-injars ../lib/scala-library.jar
-outjars ../lib/l10n-helper.jar
-libraryjars ../lib/rt.jar

-dontwarn **$$anonfun$*
-dontwarn scala.collection.immutable.RedBlack$Empty
-dontwarn scala.tools.**,plugintemplate.**

-keepclasseswithmembers public class * {
public static void main(java.lang.String[]);
}

-keep class * implements org.xml.sax.EntityResolver

-keepclassmembers class * {
** MODULE$;
}

-keepclassmembernames class scala.concurrent.forkjoin.ForkJoinPool {
long eventCount;
int workerCounts;
int runControl;
scala.concurrent.forkjoin.ForkJoinPool$WaitQueueNode syncStack;
scala.concurrent.forkjoin.ForkJoinPool$WaitQueueNode spareStack;
}

-keepclassmembernames class scala.concurrent.forkjoin.ForkJoinWorkerThread {
int base;
int sp;
int runState;
}

-keepclassmembernames class scala.concurrent.forkjoin.ForkJoinTask {
int status;
}

-keepclassmembernames class scala.concurrent.forkjoin.LinkedTransferQueue {
scala.concurrent.forkjoin.LinkedTransferQueue$PaddedAtomicReference head;
scala.concurrent.forkjoin.LinkedTransferQueue$PaddedAtomicReference tail;
scala.concurrent.forkjoin.LinkedTransferQueue$PaddedAtomicReference cleanMe;
}
Binary file added lib/l10n-helper.jar
Binary file not shown.
100 changes: 100 additions & 0 deletions src/the4e6/AndroidTranslationsHelper.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package the4e6

import java.io.File
import scala.xml._

/** Helps to find missing or obsolete translations of localized resources
* in android project. */
object AndroidTranslationsHelper {
def main(args: Array[String]) {
if (args.isEmpty) {
exit(helpMsg)
}

/** Android project root folder. */
val project = new File(args(0))
if (!project.exists) {
exit("folder not exists")
}

/** Try to find original strings.xml file in 'values' folder. */
val stringsOrig = findStrings(project, "values$")
if (stringsOrig.isEmpty) {
exit("res/values/strings.xml not found")
}

/** Try to find localized strings.xml file in 'values*' folders. */
val stringsLocalized =
findStrings(project, "values.") sortWith { _.getParent < _.getParent }
if (stringsLocalized.isEmpty) {
exit("localized resources not found")
}

/** Original XML resources from values/strings.xml */
val rOrig: NodeSeq = XML.loadFile(stringsOrig.head) \\ "resources"

stringsLocalized.foreach(f => {
val r = XML.loadFile(f) \\ "resources"
printNiceName(f)
val extraLine_? =
resTypes.map(t => {
val names = mkNamesSet(r, t)
val namesOrig = mkNamesSet(rOrig, t)
printDiffs(t, namesOrig diff names, names diff namesOrig)
}) contains true
if (extraLine_?) println
})
}

/** Returns array of all string.xml files according to
* 'dir'/res/'regex'/strings.xml pattern. */
def findStrings(dir: File, regex: String): Array[File] =
dir.listFiles
.withFilter { _.getName == "res" }
.flatMap { _.listFiles.filter(f => regex.r.findFirstIn(f.getName).isDefined) }
.flatMap { _.listFiles.filter(_.getName == "strings.xml") }

/** Returns a set of resource names. */
def mkNamesSet(ns: NodeSeq, tag: String): Set[String] =
(ns \ tag) map { _ \ "@name" text } toSet

def printNiceName(f: File) {
println(f.getParentFile.getName + "/" + f.getName)
}

/**
* Print diff section for given resource type.
*
* @return flag, if there is a need for extra blank line after output */
def printDiffs(resType: String, t: Set[String], o: Set[String]): Boolean = {
if (t.nonEmpty || o.nonEmpty) {
println(" " + resType)
t map { " [T] " + _ } foreach println
o map { " [O] " + _ } foreach println
true
} else false
}

def exit(msg: String) {
println(msg)
System.exit(0)
}

/** List of android resource types. */
val resTypes = "string" :: "string-array" :: "plurals" :: Nil

val helpMsg =
"Helps to find missing or obsolete translations for android resources\n" +
"\n" +
"Usage: You must specify android project folder\n" +
"`alh.sh /path/to/android/project'\n" +
"\n" +
"Output:\n" +
"[filename]\n" +
" *[resource type]\n" +
" *[T] [resource name]\n" +
" *[O] [resource name]\n" +
"\n" +
"[T] Resources need to be translated (exists in original xml but not in localized version)\n" +
"[O] Obsolete resources (exists in localized version but not in original one)\n"
}

0 comments on commit 7c3e132

Please sign in to comment.