// Generated using SwiftGen, by O.Halligon — https://github.com/AliSoftware/SwiftGen

{% if structuredStrings %}
import Foundation

private class RingStringsBundleToken {}

// swiftlint:disable file_length
// swiftlint:disable line_length

// swiftlint:disable type_body_length
// swiftlint:disable nesting
// swiftlint:disable variable_name
// swiftlint:disable valid_docs
{% macro parametersBlock params %}{% for type in params.types %}_ p{{forloop.counter}}: {{type}}{% if not forloop.last %}, {% endif %}{% endfor %}{% endmacro %}
{% macro argumentsBlock params %}{% for type in params.types %}p{{forloop.counter}}{% if not forloop.last %}, {% endif %}{% endfor %}{% endmacro %}
{% macro recursiveBlock strings sp %}
{{sp}}  {% for string in strings.strings %}
{{sp}}  /// {{string.translation}}
{{sp}}  {% if string.params %}
{{sp}}  static func {{string.keytail|swiftIdentifier|snakeToCamelCase|lowerFirstWord|escapeReservedKeywords}}({% call parametersBlock string.params %}) -> LocalizableString {
{{sp}}    return {{enumName}}.tr("{{string.key}}", {% call argumentsBlock string.params %})
{{sp}}  }
{{sp}}  {% else %}
{{sp}}  static let {{string.keytail|swiftIdentifier|snakeToCamelCase|lowerFirstWord|escapeReservedKeywords}} = {{enumName}}.tr("{{string.key}}")
{{sp}}  {% endif %}
{{sp}}  {% endfor %}
{{sp}}  {% if strings.subenums %}
{{sp}}  {% for subenum in strings.subenums %}

{{sp}}  enum {{subenum.name|swiftIdentifier|snakeToCamelCase}} {
{{sp}}    {% set sp2 %}{{sp}}  {% endset %}
{{sp}}    {% call recursiveBlock subenum sp2 %}
{{sp}}  }
{{sp}}  {% endfor %}
{{sp}}  {% endif %}
{% endmacro %}

enum {{enumName}} {
  {% call recursiveBlock structuredStrings sp %}
}

	struct LocalizableString {
        let key: String
        let args: [CVarArg]

        /**
         Returns String from Current Bundle
         */
        public var string: String {
            let format: String = NSLocalizedString(key, tableName: nil, bundle: Bundle(for: RingStringsBundleToken.self), value: "", comment: "")
            return String(format: format, locale: Locale.current, arguments: args)
        }

        /**
         Returns String translated from App's Bundle is found, otherwise from Current Bundle
         */
        public var smartString: String {
            // Load from App's Bundle first
            var format: String = NSLocalizedString(key, tableName: nil, bundle: Bundle.main, value: "", comment: "")
            if format != "" && format != key {
                return String(format: format, locale: Locale.current, arguments: args)
            }
            // Load from Current Bundle
            format = NSLocalizedString(key, tableName: nil, bundle: Bundle(for: RingStringsBundleToken.self), value: "", comment: "")

            return String(format: format, locale: Locale.current, arguments: args)
        }
    }

extension {{enumName}} {
  fileprivate static func tr(_ key: String, _ args: CVarArg...) -> LocalizableString {
    return LocalizableString(key: key, args: args)
  }
}

// swiftlint:enable type_body_length
// swiftlint:enable nesting
// swiftlint:enable variable_name
// swiftlint:enable valid_docs
{% else %}
// No string found
{% endif %}
