Contents

nearfri/xcresource

**XCResource** is a tool that allows you to efficiently and safely manage resources (localized strings, fonts, and other files) in Xcode projects.

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.

https://github.com/user-attachments/assets/16073e8f-9ad9-4e9c-b945-d542efd656f7

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 {
    /// \"\\(arg1)\" will be deleted.\
    /// This action cannot be undone.
    static func alertDeleteFile(_ arg1: String) -> Self {
        .init("alert_delete_file",
              defaultValue: """
                \"\(arg1)\" 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.

https://github.com/user-attachments/assets/ae09a571-3ee8-450e-84c2-39341fe203d2

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. |

Example

This repository includes an example of using the plugin.

Architecture

graph TD
    subgraph Plugin
        P["Generate Resource Code<br/><i>plugin</i>"]
    end

    subgraph Executable
        CLI["xcresource<br/><i>executableTarget</i>"]
    end

    subgraph Command
        CMD["XCResourceCommand<br/><i>target</i>"]
    end

    subgraph "Core Modules"
        LOC["LocStringResourceGen"]
        FONT["FontResourceGen"]
        FILE["FileResourceGen"]
        ASSET["AssetResourceGen"]
        UTIL["XCResourceUtil"]
    end

    subgraph "External Dependencies"
        AP["ArgumentParser<br/><i>swift-argument-parser</i>"]
        SS["SwiftSyntax<br/>SwiftParser<br/>SwiftSyntaxBuilder<br/>SwiftRefactor<br/><i>swift-syntax</i>"]
        ST["StrixParsers<br/><i>Strix</i>"]
    end

    P --> CLI
    CLI --> CMD
    CMD --> AP
    CMD --> LOC
    CMD --> FONT
    CMD --> FILE
    CMD --> ASSET
    CMD --> UTIL

    LOC --> SS
    LOC --> ST
    LOC --> UTIL
    FONT --> UTIL
    FILE --> UTIL
    ASSET --> UTIL

    style P fill:#e8f5e9,stroke:#4caf50,color:#000000
    style CLI fill:#fff3e0,stroke:#ff9800,color:#000000
    style CMD fill:#e3f2fd,stroke:#2196f3,color:#000000
    style LOC fill:#fce4ec,stroke:#e91e63,color:#000000
    style FONT fill:#f3e5f5,stroke:#9c27b0,color:#000000
    style FILE fill:#f3e5f5,stroke:#9c27b0,color:#000000
    style ASSET fill:#f3e5f5,stroke:#9c27b0,color:#000000
    style UTIL fill:#fffde7,stroke:#fbc02d,color:#000000
    style AP fill:#eceff1,stroke:#607d8b,color:#000000
    style SS fill:#eceff1,stroke:#607d8b,color:#000000
    style ST fill:#eceff1,stroke:#607d8b,color:#000000

Documentation

For more information about the plugin, check the documentation on Swift Package Index. - XCResource Documentation - Getting Started - Integrating XCResource into a Swift Package - Generating LocalizedStringResource - Generating FontResource - Advanced - Configuration File Format

License

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

Package Metadata

Repository: nearfri/xcresource

Default branch: main

README: README.md