Example #1
0
    public bool Process(string[] allFiles, string outputFile, out string error)
    {
        error = null;

        // 0) set up the LauretteTree, which will hold the hierarchy of our key-value pairs
        LauretteTree tree = new LauretteTree();

        // 1) run through all files and process each one
        foreach (string file in allFiles)
        {
            if (!ProcessFile(file, tree, out error))
            {
                return(false);
            }
        }



        // Generate the source code
        StringBuilder sb = new StringBuilder();

        AppendTabFormat(sb, 0, "// Autogenerated by Laurette ( https://github.com/KittyMac/laurette )\n\n");
        AppendTabFormat(sb, 0, "using System.Collections.Generic;\n\n");

        if (tree.AllLanguageCodes.Count == 0)
        {
            // where there no .strings files?
            AppendTabFormat(sb, 0, "// Laurette was not provided with any valid .strings files; please ensure your\n");
            AppendTabFormat(sb, 0, "// project contains .strings files in the correct format and try again\n\n\n");

            AppendTabFormat(sb, 0, "public struct Localizations {{\n");

            AppendTabFormat(sb, 1, "public static string GetLanguageCode() {{ return null; }}\n\n");

            AppendTabFormat(sb, 1, "public static string TranslateKey(string key) {{\n");
            AppendTabFormat(sb, 2, "return null;\n");
            AppendTabFormat(sb, 1, "}}\n");

            AppendTabFormat(sb, 0, "}}\n");

            File.WriteAllText(outputFile, sb.ToString());

            return(true);
        }

        tree.Traverse((branch, isStart, isLeaf, depth) => {
            if (isLeaf)
            {
                bool isFormatString = false;
                int numArguments    = 0;

                foreach (string languageCode in tree.AllLanguageCodes)
                {
                    string value = branch.Translate(languageCode);
                    if (value.Contains("{0}"))
                    {
                        isFormatString = true;

                        while (value.Contains("{" + numArguments + "}"))
                        {
                            numArguments++;
                        }

                        break;
                    }
                }

                if (isFormatString)
                {
                    StringBuilder formatString = new StringBuilder();
                    StringBuilder argsString   = new StringBuilder();
                    for (int i = 0; i < numArguments; i++)
                    {
                        formatString.Append(string.Format("object arg{0}, ", i));
                        argsString.Append(string.Format("arg{0}, ", i));
                    }
                    formatString.Length = formatString.Length - 2;
                    argsString.Length   = argsString.Length - 2;

                    AppendTabFormat(sb, depth, "/// <summary>English: \"{0}\"</summary>\n", branch.Translate("en").Replace("\n", "\\n").Replace("\r", "\\r"));
                    AppendTabFormat(sb, depth, "public static string {0}({1}) {{\n", branch.Name, formatString.ToString());

                    depth++;
                    AppendTabFormat(sb, depth, "return string.Format({0}[(int)currentLanguage], {1});\n", branch.Path, argsString.ToString());

                    depth--;
                    AppendTabFormat(sb, depth, "}}\n");
                }
                else
                {
                    AppendTabFormat(sb, depth, "/// <summary>English: \"{0}\"</summary>\n", branch.Translate("en").Replace("\n", "\\n").Replace("\r", "\\r"));
                    AppendTabFormat(sb, depth, "public static string {0} {{\n", branch.Name);

                    depth++;
                    AppendTabFormat(sb, depth, "get {{\n");

                    depth++;
                    AppendTabFormat(sb, depth, "return {0}[(int)currentLanguage];\n", branch.Path);

                    depth--;
                    AppendTabFormat(sb, depth, "}}\n");

                    depth--;
                    AppendTabFormat(sb, depth, "}}\n");
                }
            }
            else
            {
                if (isStart)
                {
                    AppendTabFormat(sb, depth, "public struct {0} {{\n", branch.Name);

                    // Create the LanguageCode enum
                    if (depth == 0)
                    {
                        depth++;

                        AppendTabFormat(sb, depth, "public enum LanguageCode {{\n");

                        depth++;
                        foreach (string languageCode in tree.AllLanguageCodes)
                        {
                            AppendTabFormat(sb, depth, "{0},\n", languageCode);
                        }
                        depth--;

                        AppendTabFormat(sb, depth, "}}\n\n");

                        AppendTabFormat(sb, depth, "private static LanguageCode currentLanguage = LanguageCode.{0};\n\n", tree.AllLanguageCodes[0]);

                        AppendTabFormat(sb, depth, "public static string GetLanguageCode() {{ return currentLanguage.ToString(); }}\n\n");

                        AppendTabFormat(sb, depth, "public static void SetLanguageCode(LanguageCode code) {{ currentLanguage = code; }}\n\n");

                        AppendTabFormat(sb, depth, "public static void SetLanguageCode(string codeAsString) {{ currentLanguage = (LanguageCode)System.Enum.Parse(typeof(LanguageCode), codeAsString); }}\n\n");

                        depth--;
                    }
                    else
                    {
                        AppendTabFormat(sb, depth + 1, "/// <summary>{0}</summary>\n", branch.KeyPath);
                        AppendTabFormat(sb, depth + 1, "public static string KeyPath {{ get {{ return \"{0}\"; }} }}\n", branch.KeyPath);
                    }
                }
                else
                {
                    AppendTabFormat(sb, depth, "}}\n");
                }
            }
        });



        sb.Length = sb.Length - 2;
        sb.AppendFormat("\n\n\n");


        AppendTabFormat(sb, 1, "private static Dictionary<string,string[]> keyLUT = new Dictionary<string,string[]>();\n\n");
        AppendTabFormat(sb, 1, "public static string TranslateKey(string key) {{\n");
        AppendTabFormat(sb, 2, "if(keyLUT.Count == 0) {{\n");

        tree.Traverse((branch3, isStart3, isLeaf3, depth3) => {
            if (isLeaf3)
            {
                AppendTabFormat(sb, 3, "keyLUT[\"{0}\"] = {1};\n", branch3.OriginalKey, branch3.Path);
            }
        });

        AppendTabFormat(sb, 2, "}}\n");
        AppendTabFormat(sb, 2, "if(keyLUT.ContainsKey(key) == false) {{ return null; }};\n");
        AppendTabFormat(sb, 2, "return keyLUT[key][(int)currentLanguage];\n");
        AppendTabFormat(sb, 1, "}}\n");

        tree.Traverse((branch2, isStart2, isLeaf2, depth2) => {
            if (isLeaf2)
            {
                AppendTabFormat(sb, 1, "static readonly string[] {0} = new string[] {{\n", branch2.Path);

                foreach (string languageCode in tree.AllLanguageCodes)
                {
                    string value = branch2.Translate(languageCode).Replace("\n", "\\n").Replace("\r", "\\r");
                    AppendTabFormat(sb, 2, "\"{0}\",\n", value);
                }

                AppendTabFormat(sb, 1, "}};\n");
            }
        });

        sb.AppendFormat("}}");

        File.WriteAllText(outputFile, sb.ToString());

        return(true);
    }
Example #2
0
    private bool ProcessFile(string filePath, LauretteTree tree, out string error)
    {
        error = null;

        // 0) Read in the .strings file
        string stringsFileAsString = File.ReadAllText(filePath);

        if (stringsFileAsString == null)
        {
            error = string.Format("Unable to read file: {0}", filePath);
            return(false);
        }


        // extract the two-character language code from the path; it should be the directory the .strings file it in
        string languageCode = Path.GetFileName(Path.GetDirectoryName(filePath));


        // 1) Process the strings file, pulling out all of the key-value pairs
        // old, doesn't handle escaped quotes: "\"([^\"]+)\"\\s*=\\s*\"([^\"]+)\""
        // new, handles escaped quotes: "([^"]+)"\s*=\s((?<![\\])['"])((?:.(?!(?<![\\])\2))*.?)\2;
        MatchCollection matches = Regex.Matches(stringsFileAsString, "\"([^\"]+)\"\\s*=\\s((?<![\\\\])['\"])((?:.(?!(?<![\\\\])\\2))*.?)\\2;", RegexOptions.Singleline);

        foreach (Match match in matches)
        {
            string value       = match.Groups [3].Value;
            string key         = match.Groups [1].Value;
            string originalKey = key;

            // handle special cases for the value before processing:
            key = key.Trim(".".ToCharArray());

            while (key.Contains(" "))
            {
                key = key.Replace(" ", "_");
            }
            while (key.Contains(".."))
            {
                key = key.Replace("..", ".");
            }

            for (char i = (char)0; i < (char)128; i++)
            {
                if (Char.IsLetter(i) == false && i != '.')
                {
                    key = key.Replace("" + i, "_");
                }
            }

            string[] parts = key.Split(".".ToCharArray());
            for (int i = 0; i < parts.Length; i++)
            {
                string part = parts [i];
                if (Char.IsLetter(part, 0) == false)
                {
                    part = "_" + part;
                }

                if (Array.IndexOf(invalidKeywords, part) >= 0)
                {
                    part = "_" + part;
                }

                parts [i] = part;
            }
            key = string.Join(".", parts);

            tree.Add(originalKey, key, value, languageCode);
        }

        return(true);
    }