You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iOS运行时自定义本地化:如何加载图片与颜色资源?

运行时本地化图片与颜色资源的解决方案

问题核心

你无法通过lproj对应的Bundle加载图片和颜色资源,原因是Xcode的资源打包规则:

  • 字符串文件会被单独存放在各语言的lproj文件夹中
  • 本地化的图片、颜色资源会被合并打包进主Bundle的Assets.car文件,而非lproj目录

所以直接加载lproj的Bundle自然找不到这些资源。


正确实现方式

1. 先配置Asset资源的本地化

在Assets.xcassets中完成以下操作:

  • 选中目标图片/颜色资源,打开右侧检查器
  • 点击「Localize...」,勾选需要支持的语言
  • 为每个语言版本导入对应的资源文件

2. 封装资源加载代码

基于选中的语言标识,构造对应Locale来加载资源:

图片加载扩展
extension Image {
    init(localizedName name: String, language: String) {
        let targetLocale = Locale(identifier: language)
        // 从主Bundle加载对应语言的图片
        let uiImage = UIImage(named: name, in: .main, with: UITraitCollection(traitsFrom: [
            UITraitCollection(locale: targetLocale)
        ])) ?? UIImage(named: name)!
        self.init(uiImage: uiImage)
    }
}
颜色加载扩展
extension Color {
    init(localizedName name: String, language: String) {
        let targetLocale = Locale(identifier: language)
        self.init(name, bundle: .main, locale: targetLocale)
    }
}

3. 优化ViewModel管理语言状态

final class ContentViewModel: ObservableObject {
    @Published var currentLanguage: String = "en" // 默认语言
    
    init() {
        let targetLanguage = "he" // 这里替换成你的目标语言
        currentLanguage = targetLanguage
        
        // 初始化字符串本地化用的Bundle
        guard let bundlePath = Bundle.main.path(forResource: targetLanguage, ofType: "lproj"),
              let url = URL(filePath: bundlePath),
              let bundle = Bundle(url: url) else { return }
        Bundle.bundleForLocalization = bundle
    }
}

4. 在View中使用本地化资源

struct ContentView: View {
    @State var helloWorld = LocalizedStringKey("")
    @StateObject var vm = ContentViewModel() // 用@StateObject正确管理ObservableObject
    
    var body: some View {
        VStack {
            Text(helloWorld)
            Image(localizedName: "LocalizedImage", language: vm.currentLanguage)
                .resizable()
                .frame(width: 50, height: 50)
            Color(localizedName: "LocalizedColor", language: vm.currentLanguage)
                .frame(width: 50, height: 50)
        }
        .padding()
        .onAppear {
            helloWorld = LocalizedStringKey(String(localized: "Hello, world!"))
        }
    }
}

全局生效的进阶方案

如果希望所有资源(字符串、图片、颜色)自动跟随选中的语言,无需单独指定Locale,可以通过修改Bundle的preferredLocalizations实现:

import ObjectiveC

var bundleLocalizationKey: UInt8 = 0

extension Bundle {
    static var bundleForLocalization: Bundle? {
        get {
            objc_getAssociatedObject(self, &bundleLocalizationKey) as? Bundle
        }
        set {
            objc_setAssociatedObject(self, &bundleLocalizationKey, newValue, .OBJC_ASSOCIATION_RETAIN)
        }
    }
    
    static func setPreferredLanguage(_ language: String) {
        object_setClass(Bundle.main, DynamicLocalizedBundle.self)
        DynamicLocalizedBundle.preferredLanguage = language
    }
}

class DynamicLocalizedBundle: Bundle {
    static var preferredLanguage: String?
    
    override var preferredLocalizations: [String] {
        guard let lang = preferredLanguage else { return super.preferredLocalizations }
        return [lang]
    }
}

在ViewModel中调用:

Bundle.setPreferredLanguage(targetLanguage)

之后所有资源加载都会自动使用指定的语言,无需在每个加载方法中单独处理。


内容的提问来源于stack exchange,提问作者StackOverflowEnjoyer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 13:47:04