You can try to build something like this:
{"projectName":"locales","licenseText":"Copyright(c) 2006-2011 locales","builds":[
{"name":"af","target":"all.af.min.js","options":{"debug":false},"compress":true,"files":[{"path":"Scripts/Ext/locale/","name":"ext-lang-af.js"}]},
{"name":"bg","target":"all.bg.min.js","options":{"debug":false},"compress":true,"files":[{"path":"Scripts/Ext/locale/","name":"ext-lang-bg.js"}]},
{"name":"ca","target":"all.ca.min.js","options":{"debug":false},"compress":true,"files":[{"path":"Scripts/Ext/locale/","name":"ext-lang-ca.js"}]},
{"name":"cs","target":"all.cs.min.js","options":{"debug":false},"compress":true,"files":[{"path":"Scripts/Ext/locale/","name":"ext-lang-cs.js"}]},
{"name":"da","target":"all.da.min.js","options":{"debug":false},"compress":true,"files":[{"path":"Scripts/Ext/locale/","name":"ext-lang-da.js"}]},
{"name":"de","target":"all.de.min.js","options":{"debug":false},"compress":true,"files":[{"path":"Scripts/Ext/locale/","name":"ext-lang-de.js"}]},
{"name":"el-gr","target":"all.el-gr.min.js","options":{"debug":false},"compress":true,"files":[{"path":"Scripts/Ext/locale/","name":"ext-lang-el_GR.js"}]},
{"name":"en","target":"all.en.min.js","options":{"debug":false},"compress":true,"files":[{"path":"Scripts/Ext/locale/","name":"ext-lang-en.js"}]},
{"name":"en-gb","target":"all.en-gb.min.js","options":{"debug":false},"compress":true,"files":[{"path":"Scripts/Ext/locale/","name":"ext-lang-en_GB.js"}]},
{"name":"es","target":"all.es.min.js","options":{"debug":false},"compress":true,"files":[{"path":"Scripts/Ext/locale/","name":"ext-lang-es.js"}]},
{"name":"fa","target":"all.fa.min.js","options":{"debug":false},"compress":true,"files":[{"path":"Scripts/Ext/locale/","name":"ext-lang-fa.js"}]},
{"name":"fi","target":"all.fi.min.js","options":{"debug":false},"compress":true,"files":[{"path":"Scripts/Ext/locale/","name":"ext-lang-fi.js"}]},
{"name":"fr","target":"all.fr.min.js","options":{"debug":false},"compress":true,"files":[{"path":"Scripts/Ext/locale/","name":"ext-lang-fr.js"}]},
{"name":"fr-ca","target":"all.fr-ca.min.js","options":{"debug":false},"compress":true,"files":[{"path":"Scripts/Ext/locale/","name":"ext-lang-fr_CA.js"}]},
{"name":"el","target":"all.el.min.js","options":{"debug":false},"compress":true,"files":[{"path":"Scripts/Ext/locale/","name":"ext-lang-gr.js"}]},
{"name":"he","target":"all.he.min.js","options":{"debug":false},"compress":true,"files":[{"path":"Scripts/Ext/locale/","name":"ext-lang-he.js"}]},
{"name":"hr","target":"all.hr.min.js","options":{"debug":false},"compress":true,"files":[{"path":"Scripts/Ext/locale/","name":"ext-lang-hr.js"}]},
{"name":"hu","target":"all.hu.min.js","options":{"debug":false},"compress":true,"files":[{"path":"Scripts/Ext/locale/","name":"ext-lang-hu.js"}]},
{"name":"id","target":"all.id.min.js","options":{"debug":false},"compress":true,"files":[{"path":"Scripts/Ext/locale/","name":"ext-lang-id.js"}]},
{"name":"it","target":"all.it.min.js","options":{"debug":false},"compress":true,"files":[{"path":"Scripts/Ext/locale/","name":"ext-lang-it.js"}]},
{"name":"ja","target":"all.ja.min.js","options":{"debug":false},"compress":true,"files":[{"path":"Scripts/Ext/locale/","name":"ext-lang-ja.js"}]},
{"name":"ko","target":"all.ko.min.js","options":{"debug":false},"compress":true,"files":[{"path":"Scripts/Ext/locale/","name":"ext-lang-ko.js"}]},
{"name":"lt","target":"all.lt.min.js","options":{"debug":false},"compress":true,"files":[{"path":"Scripts/Ext/locale/","name":"ext-lang-lt.js"}]},
{"name":"lv","target":"all.lv.min.js","options":{"debug":false},"compress":true,"files":[{"path":"Scripts/Ext/locale/","name":"ext-lang-lv.js"}]},
{"name":"mk","target":"all.mk.min.js","options":{"debug":false},"compress":true,"files":[{"path":"Scripts/Ext/locale/","name":"ext-lang-mk.js"}]},
{"name":"nl","target":"all.nl.min.js","options":{"debug":false},"compress":true,"files":[{"path":"Scripts/Ext/locale/","name":"ext-lang-nl.js"}]},
{"name":"nb-no","target":"all.nb-no.min.js","options":{"debug":false},"compress":true,"files":[{"path":"Scripts/Ext/locale/","name":"ext-lang-no_NB.js"}]},
{"name":"nn-no","target":"all.nn-no.min.js","options":{"debug":false},"compress":true,"files":[{"path":"Scripts/Ext/locale/","name":"ext-lang-no_NN.js"}]},
{"name":"pl","target":"all.pl.min.js","options":{"debug":false},"compress":true,"files":[{"path":"Scripts/Ext/locale/","name":"ext-lang-pl.js"}]},
{"name":"pt","target":"all.pt.min.js","options":{"debug":false},"compress":true,"files":[{"path":"Scripts/Ext/locale/","name":"ext-lang-pt.js"}]},
{"name":"pt-br","target":"all.pt-br.min.js","options":{"debug":false},"compress":true,"files":[{"path":"Scripts/Ext/locale/","name":"ext-lang-pt_BR.js"}]},
{"name":"pt-pt","target":"all.pt-pt.min.js","options":{"debug":false},"compress":true,"files":[{"path":"Scripts/Ext/locale/","name":"ext-lang-pt_PT.js"}]},
{"name":"ro","target":"all.ro.min.js","options":{"debug":false},"compress":true,"files":[{"path":"Scripts/Ext/locale/","name":"ext-lang-ro.js"}]},
{"name":"ru","target":"all.ru.min.js","options":{"debug":false},"compress":true,"files":[{"path":"Scripts/Ext/locale/","name":"ext-lang-ru.js"}]},
{"name":"sk","target":"all.sk.min.js","options":{"debug":false},"compress":true,"files":[{"path":"Scripts/Ext/locale/","name":"ext-lang-sk.js"}]},
{"name":"sl","target":"all.sl.min.js","options":{"debug":false},"compress":true,"files":[{"path":"Scripts/Ext/locale/","name":"ext-lang-sl.js"}]},
{"name":"sr","target":"all.sr.min.js","options":{"debug":false},"compress":true,"files":[{"path":"Scripts/Ext/locale/","name":"ext-lang-sr.js"}]},
{"name":"sv-se","target":"all.sv-se.min.js","options":{"debug":false},"compress":true,"files":[{"path":"Scripts/Ext/locale/","name":"ext-lang-sv_SE.js"}]},
{"name":"th","target":"all.th.min.js","options":{"debug":false},"compress":true,"files":[{"path":"Scripts/Ext/locale/","name":"ext-lang-th.js"}]},
{"name":"tr","target":"all.tr.min.js","options":{"debug":false},"compress":true,"files":[{"path":"Scripts/Ext/locale/","name":"ext-lang-tr.js"}]},
{"name":"vi","target":"all.vi.min.js","options":{"debug":false},"compress":true,"files":[{"path":"Scripts/Ext/locale/","name":"ext-lang-vn.js"}]},
{"name":"zh-cn","target":"all.zh-cn.min.js","options":{"debug":false},"compress":true,"files":[{"path":"Scripts/Ext/locale/","name":"ext-lang-zh_CN.js"}]},
{"name":"zh-tw","target":"all.zh-tw.min.js","options":{"debug":false},"compress":true,"files":[{"path":"Scripts/Ext/locale/","name":"ext-lang-zh_TW.js"}]}]}
On my super fast machine it takes > 90 seconds. Compare that to this tool that I build in less than an hour to do the exact same thing, but it can do it in 8 seconds:
class Combine{
public static void CombineAndOptimize(string jsbPath)
{
Directory.SetCurrentDirectory(Path.GetDirectoryName(jsbPath));
var json = File.ReadAllText(jsbPath);
var serializer = new JavaScriptSerializer();
var obj = serializer.Deserialize<JBuilder>(json);
Stopwatch sw = Stopwatch.StartNew();
List<JavaProcess> process = new List<JavaProcess>();
foreach (var build in obj.builds)
{
var jFiles = build.files.Select(x => new FileInfo((x.path + x.name).Replace('/', '\\'))).ToList();
var p = GenerateNewFile(jFiles, new FileInfo(build.target.Replace("min", "debug")), new FileInfo(build.target), build.options.debug);
process.Add(p);
}
foreach (var javaProcess in process)
javaProcess.Finalize();
Console.WriteLine("Took {0} ms", sw.ElapsedMilliseconds);
Console.ReadKey();
}
private static JavaProcess GenerateNewFile(List<FileInfo> input, FileInfo outputfiDebug, FileInfo outputfiOpt, bool debug)
{
if (outputfiDebug.Exists)
outputfiDebug.Delete();
foreach (var fi in input)
{
string readAllText = File.ReadAllText(fi.FullName);
if (!debug)
readAllText = Regex.Replace(readAllText, "//<debug>.*?//</debug>", "",
RegexOptions.Compiled | RegexOptions.Singleline);
File.AppendAllText(outputfiDebug.FullName, readAllText, Encoding.UTF8);
}
ProcessStartInfo si =
//new ProcessStartInfo( //google compiler
// @"c:\Program Files (x86)\Java\jre6\bin\java.exe",
// "-jar \"" + Path.GetDirectoryName(typeof(Program).Assembly.Location) + "\\compiler.jar\"" +
// " --charset=UTF-8 --compilation_level=SIMPLE_OPTIMIZATIONS" +
// " --js=\"" + outputfiDebug.FullName + "\"" +
// " --js_output_file=\"" + outputfiOpt.FullName + "tmp\"" +
// " --summary_detail_level=3 --formatting=pretty_print --jscomp_off=uselessCode"
// )
new ProcessStartInfo( //ycompress
@"c:\Program Files (x86)\Java\jre6\bin\java.exe",
"-jar \"" + Path.GetDirectoryName(typeof(Program).Assembly.Location) + "\\ycompressor.jar\"" +
" --type js --charset UTF-8" +
" -o \"" + outputfiOpt.FullName + "tmp\"" +
" \"" + outputfiDebug.FullName + "\""
)
{
CreateNoWindow = true,
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true
};
var p = Process.Start(si);
StringBuilder err = new StringBuilder();
StringBuilder output = new StringBuilder();
p.OutputDataReceived += (a, b) => output.Append(b.Data);
p.ErrorDataReceived += (a, b) => err.Append(b.Data);
p.BeginOutputReadLine();
p.BeginErrorReadLine();
return new JavaProcess(p, err, output, outputfiOpt);
}
private class JavaProcess
{
private readonly Process _process;
private readonly StringBuilder _err;
private readonly StringBuilder _output;
private readonly FileInfo _outputfiOpt;
public JavaProcess(Process process, StringBuilder err, StringBuilder output, FileInfo outputfiOpt)
{
_process = process;
_err = err;
_output = output;
_outputfiOpt = outputfiOpt;
}
public void Finalize()
{
_process.WaitForExit();
Console.WriteLine(_err);
Console.WriteLine(_output);
_process.Close();
if (_outputfiOpt.Exists)
File.Delete(_outputfiOpt.FullName);
File.Move(_outputfiOpt.FullName + "tmp", _outputfiOpt.FullName);
Console.WriteLine(_outputfiOpt.FullName + " combined. Optimizing ... ");
if (_err.Length > 0)
Console.WriteLine(@"check (c:\Program Files (x86)\Java\jre6\bin\java.exe)");
}
}
internal class JBuilder
{
public string projectName;
public string licenseText;
public List<JBuild> builds;
}
internal class JBuild
{
public string name;
public string target;
public JOptions options;
public bool compress;
public List<JFile> files;
}
internal class JOptions
{
public bool debug;
}
internal class JFile
{
public string path;
public string name;
}
}
btw. That locale dir is so ****ed up, doesn't anyone care about globalization at sencha?
case "gr": return "el";
case "no-nb": return "nb-no";
case "no-nn": return "nn-no";
case "vn": return "vi";
case "ukr": return NOSUCHISO;
case "sr-rs": return NOSUCHISO;
And isnt there some way to actually keep track of translation status or tooling that the rest of use can use for our translations?
And the full source.
It is a bit specific for my needs, in that it takes the original jsb3 file from the "create jsb" and then locates translated files (in the form of originalfile.js -> originalfile.iso.js) and includes those with the sencha translations. and then builds min and debug version of all.
Also checks for altered file dates, doing the compile in milliseconds if you didnt change anything.
Sorry about my ranting, just a bit annoyed having to do it myself, when there is a nice SDK, just lacking some features and working rather slow.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Web.Script.Serialization;
namespace FixupJsBuild
{
class Program
{
static void Main(string[] args)
{
Stopwatch sw = Stopwatch.StartNew();
if (args.Length != 1)
Usage();
string jsbPath = args[0];
var jsb = ReadJsb(jsbPath);
FixupJsbFile(jsb);
CombineAndOptimize(jsb);
Console.WriteLine("Took {0} ms", sw.ElapsedMilliseconds);
}
private static JBuilder ReadJsb(string jsbPath)
{
Directory.SetCurrentDirectory(Path.GetDirectoryName(jsbPath));
var json = File.ReadAllText(jsbPath);
var serializer = new JavaScriptSerializer();
return serializer.Deserialize<JBuilder>(json);
}
private static void CombineAndOptimize(JBuilder jsb)
{
List<JavaProcess> process = (from build in jsb.builds
let jFiles = build.files.Select(x => new FileInfo((x.path + x.name).Replace('/', '\\'))).ToList()
select GenerateNewFile(jFiles, new FileInfo(build.target.Replace("min", "debug")), new FileInfo(build.target), build.options.debug))
.ToList();
foreach (var javaProcess in process)
if (javaProcess != null) javaProcess.Finalize();
}
private static DateTime GetLastModified(List<FileInfo> fileInfos)
{
DateTime lastModified = DateTime.MinValue;
foreach (var fi in fileInfos)
{
if (!fi.Exists)
{
Console.WriteLine("Input file not found : " + fi.FullName);
Usage();
}
if (fi.LastWriteTimeUtc > lastModified)
lastModified = fi.LastWriteTimeUtc;
}
return lastModified;
}
private static void Usage()
{
Console.WriteLine("Usage: jsbfile");
Environment.Exit(1);
}
private static JavaProcess GenerateNewFile(List<FileInfo> input, FileInfo outputfiDebug, FileInfo outputfiOpt, bool debug)
{
DateTime lastModified = GetLastModified(input);
if (outputfiDebug.Exists && outputfiOpt.Exists &&
outputfiDebug.LastWriteTimeUtc >= lastModified &&
outputfiOpt.LastWriteTimeUtc >= lastModified)
{
Console.WriteLine("{0} is up to date - not modified", outputfiOpt.FullName);
return null;
}
if (outputfiDebug.Exists)
outputfiDebug.Delete();
foreach (var fi in input)
{
string readAllText = File.ReadAllText(fi.FullName);
if (!debug)
readAllText = Regex.Replace(readAllText, "//<debug>.*?//</debug>", "",
RegexOptions.Compiled | RegexOptions.Singleline);
File.AppendAllText(outputfiDebug.FullName, readAllText, Encoding.UTF8);
}
ProcessStartInfo si =
//new ProcessStartInfo( //google compiler
// @"c:\Program Files (x86)\Java\jre6\bin\java.exe",
// "-jar \"" + Path.GetDirectoryName(typeof(Program).Assembly.Location) + "\\compiler.jar\"" +
// " --charset=UTF-8 --compilation_level=SIMPLE_OPTIMIZATIONS" +
// " --js=\"" + outputfiDebug.FullName + "\"" +
// " --js_output_file=\"" + outputfiOpt.FullName + "tmp\"" +
// " --summary_detail_level=3 --formatting=pretty_print --jscomp_off=uselessCode"
// )
new ProcessStartInfo( //ycompress
@"c:\Program Files (x86)\Java\jre6\bin\java.exe",
"-jar \"" + Path.GetDirectoryName(typeof(Program).Assembly.Location) + "\\ycompressor.jar\"" +
" --type js --charset UTF-8" +
" -o \"" + outputfiOpt.FullName + "tmp\"" +
" \"" + outputfiDebug.FullName + "\""
)
{
CreateNoWindow = true,
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true
};
var p = Process.Start(si);
StringBuilder err = new StringBuilder();
StringBuilder output = new StringBuilder();
p.OutputDataReceived += (a, b) => output.Append(b.Data);
p.ErrorDataReceived += (a, b) => err.Append(b.Data);
p.BeginOutputReadLine();
p.BeginErrorReadLine();
return new JavaProcess(p, err, output, outputfiOpt);
}
private class JavaProcess
{
private readonly Process _process;
private readonly StringBuilder _err;
private readonly StringBuilder _output;
private readonly FileInfo _outputfiOpt;
public JavaProcess(Process process, StringBuilder err, StringBuilder output, FileInfo outputfiOpt)
{
_process = process;
_err = err;
_output = output;
_outputfiOpt = outputfiOpt;
}
public void Finalize()
{
_process.WaitForExit();
Console.WriteLine(_err);
Console.WriteLine(_output);
_process.Close();
if (_outputfiOpt.Exists)
File.Delete(_outputfiOpt.FullName);
File.Move(_outputfiOpt.FullName + "tmp", _outputfiOpt.FullName);
Console.WriteLine(_outputfiOpt.FullName + " combined. Optimizing ... ");
if (_err.Length > 0)
Console.WriteLine(@"check (c:\Program Files (x86)\Java\jre6\bin\java.exe)");
}
}
private static void FixupJsbFile(JBuilder jsb)
{
jsb.projectName = "Catglobe";
jsb.licenseText = "Copyright(c) 2006-2011 Catglobe";
//remove non existing file, it always wants to add
jsb.builds = new List<JBuild> {jsb.builds[0]};
jsb.builds[0].target = "all.min.js";
jsb.builds[0].options.debug = false;
//jsb.builds.Add(new JBuild
// {
// compress = true,
// name = "optim",
// options = new JOptions {debug = false},
// target = "all.min.js",
// files = new List<JFile>
// {
// new JFile {name = "all.debug.js", path = string.Empty}
// }
// });
var translateableFiles = jsb.builds[0].files.Where(x => !x.path.StartsWith("Scripts/Ext/src")).ToList();
var pathswithpossibletranslations = translateableFiles.Select(x => x.path).Distinct();
var translatedFiles = new Dictionary<string, List<JFile>>();
const string scriptsExtLocale = "Scripts/Ext/locale";
foreach (var extlocale in Directory.EnumerateFiles(scriptsExtLocale, "*.js"))
{
var split = extlocale.Replace(".js", "").Split('-');
var locale = FindCorrectlocale(split[split.Length - 1]);
try
{
CultureInfo.GetCultureInfo(locale);
}
catch (CultureNotFoundException)
{
continue;
}
translatedFiles[locale] = new List<JFile>
{
new JFile
{
name = Path.GetFileName(extlocale),
path = Path.GetDirectoryName(extlocale).Replace('\\', '/') + '/',
}
};
}
foreach (var pathwithpossibletranslations in pathswithpossibletranslations)
{
var filecollection = Directory.EnumerateFiles(pathwithpossibletranslations, "*.js")
.Select(x => x.ToLowerInvariant()).ToList();
//we should now have a list of files named something like hest.da.js
foreach (var file in filecollection)
{
var split = file.Split('.');
if (split.Length < 2) continue;
var locale = split[split.Length - 2];
List<JFile> d;
if (!translatedFiles.TryGetValue(locale, out d))
continue;
d.Add(new JFile
{
name = Path.GetFileName(file),
path = Path.GetDirectoryName(file).Replace('\\', '/'),
});
}
}
foreach (var translatedFile in translatedFiles)
{
string locale = translatedFile.Key;
jsb.builds.Add(new JBuild
{
compress = true,
name = locale,
target = "all." + locale + ".min.js",
options = new JOptions(),
files = translatedFile.Value
});
}
//json = serializer.Serialize(obj);
//File.WriteAllText(jsbPath, json);
}
private static string FindCorrectlocale(string locale)
{
string correctlocale = locale.Replace("_", "-").ToLowerInvariant();
switch (correctlocale)
{
case "gr": return "el";
case "no-nb": return "nb-no";
case "no-nn": return "nn-no";
case "vn": return "vi";
}
return correctlocale;
}
// ReSharper disable InconsistentNaming
// ReSharper disable NotAccessedField.Local
// ReSharper disable ClassNeverInstantiated.Local
private class JBuilder
{
public string projectName;
public string licenseText;
public List<JBuild> builds;
}
private class JBuild
{
public string name;
public string target;
public JOptions options;
public bool compress;
public List<JFile> files;
}
private class JOptions
{
public bool debug;
}
private class JFile
{
public string path;
public string name;
}
// ReSharper restore ClassNeverInstantiated.Local
// ReSharper restore NotAccessedField.Local
// ReSharper restore InconsistentNaming
}
}
Powered by vBulletin® Version 4.1.5 Copyright © 2013 vBulletin Solutions, Inc. All rights reserved.