Skip to content

nearfri/XCResource

Repository files navigation

XCResource

Swift Swift Version Compatibility Platform Compatibility codecov

XCResource is a tool that allows you to efficiently and safely manage resources (localized strings, fonts, and other files) in Xcode projects. By automating code generation, it reduces typos and runtime errors.

Features

1. Type-Safe Resource Code Generation

  • Generates type-safe Swift code for localized strings, fonts, and other files.

2. Flexible Configuration and Integration

  • Supports Swift Package Manager for easy integration.
  • Enables customized code generation using configuration files.
  • Easily executable via Swift Package Plugin.

Getting Started

1. Adding XCResource to Your Project

Add to Package.swift

dependencies: [
    .package(url: "https://github.com/nearfri/XCResource.git", from: "<version>"),
    // OR
    .package(url: "https://github.com/nearfri/XCResource-plugin.git", from: "<version>"),
],

Recommendation: Use XCResource-plugin to take advantage of the precompiled binary executable.

Create a Configuration File (xcresource.json)

Add an xcresource.json file to your project. The plugin reads this file and generates Swift code every time it runs.

Supported paths for the configuration file:

  • ${PROJECT_DIR}/xcresource.json
  • ${PROJECT_DIR}/.xcresource.json
  • ${PROJECT_DIR}/Configs/xcresource.json
  • ${PROJECT_DIR}/Scripts/xcresource.json

2. Managing Localized Strings

xcresource provides multiple subcommands. Among them, xcstrings2swift parses a String Catalog (.xcstrings) and generates LocalizedStringResource constants.

xcstrings2swift.mp4

Configuration (xcresource.json)

{
    "commands": [
        {
            "commandName": "xcstrings2swift",
            "catalogPath": "Sources/Resources/Resources/Localizable.xcstrings",
            "bundle": "atURL:Bundle.module.bundleURL",
            "swiftFilePath": "Sources/Resources/ResourceAccess/LocalizedStringResource+.swift"
        }
    ]
}

Generated Code

public extension LocalizedStringResource {
    /// \"\\(param1)\" will be deleted.\
    /// This action cannot be undone.
    static func alertDeleteFile(_ param1: String) -> Self {
        .init("alert_delete_file",
              defaultValue: """
                \"\(param1)\" will be deleted.
                This action cannot be undone.
                """,
              bundle: .atURL(Bundle.module.bundleURL))
    }
    
    /// Done
    static var commonDone: Self {
        .init("common_done",
              defaultValue: "Done",
              bundle: .atURL(Bundle.module.bundleURL))
    }
}

(Function names and parameter names can be customized if they match the localization key and function signature.)

Usage

Text(.commonDone)

3. Font Code Generation

fonts2swift generates Swift code for fonts.

fonts2swift.mp4

Configuration (xcresource.json)

{
    "commands": [
        {
            "commandName": "fonts2swift",
            "resourcesPath": "Sources/Resources/Resources",
            "swiftFilePath": "Sources/Resources/ResourceAccess/FontResource.swift",
            "resourceTypeName": "FontResource",
            "resourceListName": "all",
            "transformsToLatin": true,
            "stripsCombiningMarks": true,
            "preservesRelativePath": true,
            "bundle": "Bundle.module",
            "accessLevel": "public"
        }
    ]
}

Generated Code

public struct FontResource: Hashable, Sendable {
    public let fontName: String
    public let familyName: String
    public let style: String
    public let relativePath: String
    public let bundle: Bundle
    ...
}

public extension FontResource {
    static let all: [FontResource] = [
        // Cambria
        .cambriaRegular,
        
        // Open Sans
        .openSansBold,
    ]
}

public extension FontResource {
    // MARK: Cambria
    
    static let cambriaRegular: FontResource = .init(
        fontName: "Cambria",
        familyName: "Cambria",
        style: "Regular",
        relativePath: "Fonts/Cambria.ttc",
        bundle: Bundle.module)
    
    // MARK: Open Sans
    
    static let openSansBold: FontResource = .init(
        fontName: "OpenSans-Bold",
        familyName: "Open Sans",
        style: "Bold",
        relativePath: "Fonts/OpenSans/OpenSans-Bold.ttf",
        bundle: Bundle.module)
}

Usage

Font.custom(.openSansBold, size: 16)

4. File Code Generation

files2swift generates Swift code for files such as JSON.

Configuration (xcresource.json)

{
    "commands": [
        {
            "commandName": "files2swift",
            "resourcesPath": "Sources/Resources/Resources/Lotties",
            "filePattern": "(?i)\\.json$",
            "swiftFilePath": "Sources/Resources/ResourceAccess/LottieResource.swift",
            "resourceTypeName": "LottieResource",
            "preservesRelativePath": true,
            "relativePathPrefix": "Lotties",
            "bundle": "Bundle.module",
            "accessLevel": "public"
        }
    ]
}

Generated Code

public struct LottieResource: Hashable, Sendable {
    public let relativePath: String
    public let bundle: Bundle
    ...
}

extension LottieResource {
    public static let hello: LottieResource = .init(
        relativePath: "Lotties/hello.json",
        bundle: Bundle.module)
}

Usage

LottieView(.hello)

Commands

Command Description
xcstrings2swift Scans .xcstrings file and generates code.
fonts2swift Scans font directory and generates code.
files2swift Scans directory for matching files and generates code.
xcassets2swift Scans .xcassets directory and generates code.

Documentation

For more information about the plugin, check the documentation on Swift Package Index.

Example

This repository includes an example of using the plugin.

License

XCResource is distributed under the MIT license. For more details, see the LICENSE file.