/// <summary>Extracts localization items from the <c>[KSPAction]</c> annotated fields.</summary>
        /// <param name="info">The type member to extract the strings for.</param>
        /// <returns>All the localization items for the member.</returns>
        static List <LocItem> EmitItemsForKspAction(MemberInfo info)
        {
            var res     = new List <LocItem>();
            var attrObj = info.GetCustomAttributes(false).OfType <KSPAction>().FirstOrDefault();

            if (attrObj == null)
            {
                return(res);
            }
            var          groupKey = "Type: " + info.DeclaringType.FullName;
            const string sortKey  = "KSP Actions";
            // Get guiName localization.
            var guiNameLoc = GetItemFromLocalizableObject(info, groupKey, sortKey);

            if (!guiNameLoc.HasValue && !string.IsNullOrEmpty(attrObj.guiName))
            {
                // Fallback to the KSPAction values.
                guiNameLoc = new LocItem()
                {
                    groupKey        = groupKey,
                    subgroupKey     = sortKey,
                    fullFilePath    = info.DeclaringType.Assembly.Location,
                    locTag          = MakeTypeMemberLocalizationTag(info),
                    locDefaultValue = attrObj.guiName,
                };
            }
            if (guiNameLoc.HasValue)
            {
                res.Add(guiNameLoc.Value);
            }
            return(res);
        }
示例#2
0
        /// <summary>Extracts localization items from the <c>[KSPField]</c> annotated fields.</summary>
        /// <param name="info">The type member to extract the strings for.</param>
        /// <returns>All the localization items for the member.</returns>
        static List <LocItem> EmitItemsForKSPField(MemberInfo info)
        {
            var res     = new List <LocItem>();
            var attrObj = info.GetCustomAttributes(false).OfType <KSPField>().FirstOrDefault();

            if (attrObj == null)
            {
                return(res);
            }

            var          groupKey = "Type: " + info.DeclaringType.FullName;
            const string sortKey  = "KSP Fields";
            // Get guiName localization.
            var guiNameLoc = GetItemFromLocalizableObject(info, groupKey, sortKey);

            if (!guiNameLoc.HasValue && !string.IsNullOrEmpty(attrObj.guiName))
            {
                // Fallback to the KSPField values.
                guiNameLoc = new LocItem()
                {
                    groupKey        = groupKey,
                    sortKey         = sortKey,
                    fullFilePath    = info.DeclaringType.Assembly.Location,
                    locTag          = MakeTypeMemberLocalizationTag(info),
                    locDefaultValue = attrObj.guiName,
                };
            }
            if (guiNameLoc.HasValue)
            {
                res.Add(guiNameLoc.Value);
            }

            // Get localization for the units if present.
            var guiUnitsLoc = GetItemFromLocalizableObject(
                info, groupKey, sortKey, spec: LocalizationLoader.KspFieldUnitsSpec);

            if (!guiUnitsLoc.HasValue && !string.IsNullOrEmpty(attrObj.guiUnits))
            {
                // Fallback to the KSPField values.
                guiUnitsLoc = new LocItem()
                {
                    groupKey        = groupKey,
                    sortKey         = sortKey,
                    fullFilePath    = info.DeclaringType.Assembly.Location,
                    locTag          = MakeTypeMemberLocalizationTag(info, nameSuffix: "_Units"),
                    locDefaultValue = attrObj.guiUnits,
                };
            }
            if (guiUnitsLoc.HasValue)
            {
                res.Add(guiUnitsLoc.Value);
            }

            return(res);
        }
        /// <summary>Extracts the strings that look like the localized tags.</summary>
        /// <remarks>
        /// This methods looks for the values that are localized in way it's done in the stock parts.
        /// </remarks>
        /// <param name="part">The part to extract the items for.</param>
        /// <param name="config">
        /// The config node of the part. It's an extend version with the comments.
        /// </param>
        /// <returns>The list of extracted items.</returns>
        static List <LocItem> EmitItemsForNode(AvailablePart part, ConfigNode config)
        {
            var res = new List <LocItem>();

            // Go through all the fields to detect if there are localized optional fields.
            foreach (var field in config.values.Cast <ConfigNode.Value>())
            {
                if (string.IsNullOrEmpty(field.comment))
                {
                    continue;
                }
                var meta    = MetaBlock.MakeFromString(field.comment);
                var comment = meta.inlineComment ?? "";
                var match   = Regex.Match(comment, @"^(#[a-zA-Z0-9_-]+)\s*=\s*(.+?)$");
                if (!match.Success)
                {
                    continue; // Not localized.
                }
                var locTag   = match.Groups[1].Value;
                var locValue = field.value;
                if (field.value == locTag)
                {
                    // In case of the tag is not get resolved, use the default template.
                    DebugEx.Warning(
                        "Field '{0}' in part {1} looks localized, but the tag '{2}' is not found"
                        + " (suggested default value: '{3}')",
                        field.name, part.name, locTag, match.Groups[2].Value);
                    locValue = match.Groups[2].Value;
                }
                var item = new LocItem()
                {
                    groupKey        = "Part: " + part.name,
                    fullFilePath    = part.configFileFullName,
                    locTag          = locTag,
                    locDefaultValue = locValue,
                };
                res.Add(item);
            }

            // Scan the nested nodes.
            foreach (var nestedNode in config.GetNodes())
            {
                res.AddRange(EmitItemsForNode(part, nestedNode));
            }

            return(res);
        }
示例#4
0
        /// <summary>Extracts the strings that look like the localized tags.</summary>
        /// <remarks>
        /// This methods looks for the values that are localized in way it's done in the stock parts.
        /// </remarks>
        /// <param name="part">The part to extract the items for.</param>
        /// <param name="config">
        /// The config node of the part. It's an extend version with the comments.
        /// </param>
        /// <returns>The list of extracted items.</returns>
        static List <LocItem> EmitItemsForNode(AvailablePart part, ConfigNode config)
        {
            var res = new List <LocItem>();

            // Go thru all the fields to detect if there are localized optional fields.
            foreach (var field in config.values.Cast <ConfigNode.Value>())
            {
                if (localizablePartFields.Contains(field.name) || string.IsNullOrEmpty(field.comment))
                {
                    continue;
                }
                var match = Regex.Match(field.comment, @"^\s*(#[a-zA-Z0-9_-]+)\s*=\s*(.+?)$");
                if (!match.Success)
                {
                    continue; // Not localized.
                }
                string locTag          = match.Groups[1].Value;
                string locDefaultValue = match.Groups[2].Value;
                if (field.value != locTag)
                {
                    Debug.LogWarningFormat(
                        "A possible localized field has wrong syntax:"
                        + " part={0}, field={1}, value={2}, comment={3}",
                        part.name, field.name, field.value, field.comment);
                }
                var item = new LocItem()
                {
                    groupKey        = "Part: " + part.name,
                    fullFilePath    = part.configFileFullName,
                    locTag          = MakePartFieldLocalizationTag(part.name, field.name),
                    locDefaultValue = locDefaultValue,
                };
                res.Add(item);
            }

            // Scan the nested nodes.
            foreach (var nestedNode in config.GetNodes())
            {
                res.AddRange(EmitItemsForNode(part, nestedNode));
            }

            return(res);
        }
        /// <summary>Extracts the localization items from the part's config.</summary>
        /// <param name="part">The part to extract items for.</param>
        /// <returns>All the localization items for the part.</returns>
        public static List <LocItem> EmitItemsForPart(AvailablePart part)
        {
            var res = new List <LocItem>();
            // The part's config in the AvailablePart doesn't have all the fields and lacks the comments.
            // We do need the comments to resolve the field tag names, so load via a custom method.
            // In case of the custom loading method fails, use the stock one without the comments support.
            var config = (ConfigStore.LoadConfigWithComments(part.configFileFullName)
                          ?? ConfigNode.Load(part.configFileFullName)).GetNode("PART");

            if (config == null)
            {
                DebugEx.Error("Failed to load part's config: partName={0}, configUrl={1}",
                              part.name, part.configFileFullName);
                return(res);
            }

            // Go through the fields we know must be localized.
            foreach (var fieldName in LocalizablePartFields)
            {
                var field = config.values.Cast <ConfigNode.Value>().FirstOrDefault(x => x.name == fieldName);
                if (field == null)
                {
                    DebugEx.Warning("Field '{0}' is not found in the part {1} config", fieldName, part.name);
                    continue;
                }
                config.values.Remove(field); // Don't handle it down the stream.
                string locTag          = null;
                string locDefaultValue = null;
                var    meta            = MetaBlock.MakeFromString(field.comment);
                if (LocalizationManager.IsLocalizationTag(meta.inlineComment, firstWordOnly: true))
                {
                    var match = Regex.Match(meta.inlineComment, @"^(#[a-zA-Z0-9_-]+)\s*=\s*(.+?)$");
                    if (match.Success)
                    {
                        locTag = match.Groups[1].Value;
                        if (field.value == locTag)
                        {
                            // Part's tag localization failed, use the default text.
                            locDefaultValue = match.Groups[2].Value;
                        }
                    }
                    else
                    {
                        DebugEx.Warning("Cannot resolve default localization tag in field {0} for part {1}: {2}",
                                        fieldName, config.GetValue("name"), meta.inlineComment);
                    }
                }
                // ReSharper disable once UseStringInterpolation
                var fieldOrderStr = string.Format(
                    "\0x00_{0:000}_{1}", // Use zero prefix to place it before anything else.
                    Controller.partFieldsSorting.IndexOf(fieldName, StringComparison.Ordinal),
                    fieldName);
                var item = new LocItem()
                {
                    groupKey        = "Part: " + part.name,
                    sortKey         = fieldOrderStr,
                    fullFilePath    = part.configFileFullName,
                    locTag          = locTag ?? MakePartFieldLocalizationTag(config.GetValue("name"), fieldName),
                    locDefaultValue = locDefaultValue ?? field.value,
                };
                res.Add(item);
            }

            res.AddRange(EmitItemsForNode(part, config));

            return(res);
        }
        /// <summary>Extracts localization items from the <c>[KSPField]</c> annotated fields.</summary>
        /// <param name="info">The type member to extract the strings for.</param>
        /// <returns>All the localization items for the member.</returns>
        static List <LocItem> EmitItemsForKspField(MemberInfo info)
        {
            var res     = new List <LocItem>();
            var attrObj = info.GetCustomAttributes(false).OfType <KSPField>().FirstOrDefault();

            if (attrObj == null)
            {
                return(res);
            }

            var          groupKey    = "Type: " + info.DeclaringType.FullName;
            const string subgroupKey = "KSP Fields";
            // Get guiName localization.
            var guiNameLoc = GetItemFromLocalizableObject(info, groupKey, subgroupKey);

            if (!guiNameLoc.HasValue && !string.IsNullOrEmpty(attrObj.guiName))
            {
                // Fallback to the KSPField values.
                guiNameLoc = new LocItem()
                {
                    groupKey        = groupKey,
                    subgroupKey     = subgroupKey,
                    fullFilePath    = info.DeclaringType.Assembly.Location,
                    locTag          = MakeTypeMemberLocalizationTag(info),
                    locDefaultValue = attrObj.guiName,
                };
            }
            if (guiNameLoc.HasValue)
            {
                res.Add(guiNameLoc.Value);
            }

            // Get localization for the units if present.
            var guiUnitsLoc = GetItemFromLocalizableObject(
                info, groupKey, subgroupKey, spec: StdSpecTags.Units);

            if (!guiUnitsLoc.HasValue && !string.IsNullOrEmpty(attrObj.guiUnits))
            {
                // Fallback to the KSPField values.
                guiUnitsLoc = new LocItem()
                {
                    groupKey        = groupKey,
                    subgroupKey     = subgroupKey,
                    fullFilePath    = info.DeclaringType.Assembly.Location,
                    locTag          = MakeTypeMemberLocalizationTag(info, nameSuffix: "_Units"),
                    locDefaultValue = attrObj.guiUnits,
                };
            }
            if (guiUnitsLoc.HasValue)
            {
                res.Add(guiUnitsLoc.Value);
            }

            // Get localizations for UI_Control
            var uiControlAttr = info.GetCustomAttributes(false).OfType <UI_Control>().FirstOrDefault();

            if (uiControlAttr == null)
            {
                return(res);
            }
            var uiToggleAttr = uiControlAttr as UI_Toggle;

            if (uiToggleAttr != null)
            {
                var guiEnabledLoc = GetItemFromLocalizableObject(
                    info, groupKey, subgroupKey, spec: StdSpecTags.ToggleEnabled);
                if (!guiEnabledLoc.HasValue && !string.IsNullOrEmpty(uiToggleAttr.displayEnabledText))
                {
                    guiEnabledLoc = new LocItem()
                    {
                        groupKey        = groupKey,
                        subgroupKey     = subgroupKey,
                        fullFilePath    = info.DeclaringType.Assembly.Location,
                        locTag          = MakeTypeMemberLocalizationTag(info, nameSuffix: "_ToggleEnabled"),
                        locDefaultValue = uiToggleAttr.displayEnabledText,
                    };
                }
                if (guiEnabledLoc.HasValue)
                {
                    res.Add(guiEnabledLoc.Value);
                }

                var guiDisabledLoc = GetItemFromLocalizableObject(
                    info, groupKey, subgroupKey, spec: StdSpecTags.ToggleDisabled);
                if (!guiDisabledLoc.HasValue && !string.IsNullOrEmpty(uiToggleAttr.displayDisabledText))
                {
                    guiDisabledLoc = new LocItem()
                    {
                        groupKey        = groupKey,
                        subgroupKey     = subgroupKey,
                        fullFilePath    = info.DeclaringType.Assembly.Location,
                        locTag          = MakeTypeMemberLocalizationTag(info, nameSuffix: "_ToggleDisabled"),
                        locDefaultValue = uiToggleAttr.displayDisabledText,
                    };
                }
                if (guiDisabledLoc.HasValue)
                {
                    res.Add(guiDisabledLoc.Value);
                }
            }

            return(res);
        }
示例#7
0
        /// <summary>Extracts the localization items from the part's config.</summary>
        /// <param name="part">The part to extract items for.</param>
        /// <returns>All the localization items for the part.</returns>
        public static List <LocItem> EmitItemsForPart(AvailablePart part)
        {
            var res = new List <LocItem>();
            // The part's config in the AvailablePart doesn't have all the fields and lacks the comments.
            // We do need the comments to resolve the field tag names, so load via a custom method.
            // In case of the custom loading method fails, use the stock one without the comments support.
            var config = (ConfigStore.LoadConfigWithComments(part.configFileFullName)
                          ?? ConfigNode.Load(part.configFileFullName)).GetNode("PART");

            if (config == null)
            {
                Debug.LogErrorFormat("Failed to load part's config: partName={0}, configUrl={1}",
                                     part.name, part.configFileFullName);
                return(res);
            }

            // Go thru the fields we know must be localized.
            foreach (var fieldName in localizablePartFields)
            {
                var field = config.values.Cast <ConfigNode.Value>()
                            .FirstOrDefault(x => x.name == fieldName);
                if (field == null)
                {
                    Debug.LogWarningFormat("Field '{0}' is not found in the part {1} config",
                                           fieldName, part.name);
                    continue;
                }
                string locTag          = null;
                string locDefaultValue = null;
                if (!string.IsNullOrEmpty(field.comment) &&
                    field.comment.StartsWith("#", StringComparison.Ordinal))
                {
                    var match = Regex.Match(field.comment, @"^(#[a-zA-Z0-9_-]+)\s*=\s*(.+?)$");
                    if (match.Success)
                    {
                        locTag = match.Groups[1].Value;
                        if (field.value == locTag)
                        {
                            // Part's tag localization failed, use the default text.
                            locDefaultValue = match.Groups[2].Value;
                        }
                    }
                    else
                    {
                        Debug.LogWarningFormat(
                            "Cannot resolve defult localization tag in field {0} for part {1}: {2}",
                            fieldName, config.GetValue("name"), field.comment);
                    }
                }
                var item = new LocItem()
                {
                    groupKey        = "Part: " + part.name,
                    fullFilePath    = part.configFileFullName,
                    locTag          = locTag ?? MakePartFieldLocalizationTag(config.GetValue("name"), fieldName),
                    locDefaultValue = locDefaultValue ?? field.value,
                };
                res.Add(item);
            }

            res.AddRange(EmitItemsForNode(part, config));

            return(res);
        }