如何在SwiftUI中动态更改本地化

8

我如何在SwiftUI中实时更改应用程序的本地化?

我认为我们可以使用下面的代码,但是我们应该找到SwiftUI的方法。

func localized(_ lang:String) -> String {

    let path = Bundle.main.path(forResource: lang, ofType: "lproj")
    let bundle = Bundle(path: path!)

    return NSLocalizedString(self, tableName: nil, bundle: bundle!, value: "", comment: "")
}}
4个回答

7
首先,我们应该创建2个Localizable.strings文件,例如我这里是 enru
然后,我们应该存储当前的语言对象,我选择将其存储在UserSettings属性中,像ObservableObject一样。我们也可以使用@AppStorage初始化lang变量来保留所选语言。
class UserSettings: ObservableObject {
    
    @Published var lang: String = "ru"
    
    var bundle: Bundle? {
        let b = Bundle.main.path(forResource: lang, ofType: "lproj")!
        return Bundle(path: b)
    }
}

我们可以在SceneDelegate.swift中使用这个设置对象,就像使用.environmentObject()一样,这样层次结构中的每个视图都将被更新。
var settings = UserSettings()
// ...
= UIHostingController(rootView: contentView.environmentObject(settings))

在编程中,我们可以通过View来获得期望的行为,需要注意的是,在Text初始化时应该指定bundle
struct ContentView: View {
    
    @EnvironmentObject var settings: UserSettings
    
    var body: some View {
        VStack {
            Text("App", bundle: settings.bundle)
        }
    }
}

现在我可以在应用程序的某个地方更改语言,这里只是一个示例循环示例,您可以在scene(_ scene:将连接到:选项connectionOptions:)willConnectTo:中调用此函数changeLanguage(),并且每3秒钟语言将会更改。
func changeLanguage() {
    print(#function)
    DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
        self.settings.lang = self.settings.lang == "ru" ? "en" : "ru"
        self.changeLanguage()
    }
} 

我无法在 Text() 视图中使用 "bundle:",我得到的错误信息是 => 无法将类型为 'String' 的值转换为预期的参数类型 'LocalizedStringKey'。 - Ahmadreza
对我来说起作用了。最终在SwiftUI上下文中找到了解决方案。 - Shark Deng

4

@Tikhonov Alexander 这是否意味着每个文本元素都必须指定捆绑标识符?是否有一种简单的方法可以为所有文本元素设置此项,或者是否有另一种在运行时更改区域设置标识符的方法?目前我正在通过更改地区设置来测试预览中的其他语言。

    static var previews: some View {
        TestView()
            .environment(\.locale, Locale(identifier: "ru"))
    }

当运行时使用时,这似乎没有任何效果。 - ixany

1

没有一种通用的方法来解决这个问题(即动态本地化)。这只适用于您的代码显示的字符串。

本地化很棘手,它不仅仅是字符串,还涉及本地化图像资产、xibs(例如UIViewRepresentable)、系统图像和系统文本以及来自第三方库的资产。

当开始编写新应用程序时,您首先关心的是本地化文本,但是如果您使用这些“动态本地化”解决方案构建您的应用程序,那么后来您可能无法将其用于需要本地化的所有资产。


0

你可以使用LanguageManager-SwiftUI

它易于使用,只需几个步骤即可让你的应用程序准备就绪。

1- 将Localizable.strings文件添加到你的项目中。

2- 使用LanguageManagerView包装你的主视图,并传递你的应用程序第一次运行时的默认语言。

@main
struct ExampleApp: App {
  var body: some Scene {
    WindowGroup {
      // The default language when the app starts for the first time.
      // it can be the `deviceLanguage`, `ar`, `en`, or any language.
      LanguageManagerView(.deviceLanguage) {
        AppView()
          .transition(.slide) // The animation that will be happening when the language change.
      }
    }
  }
}

3 - 要更改语言,您应该按以下方式更改selectedLanguage

struct LangaugeView: View {
  
  // MARK: - Properties
  
  @EnvironmentObject var languageSettings: LanguageSettings
  
  // MARK: - body
  
  var body: some View {
    VStack {
      Text("Select a language")
        .padding()
      Button("Arabic") {
        withAnimation {
          languageSettings.selectedLanguage = .ar
        }
      }
      .padding()
      Button("English") {
        withAnimation {
          languageSettings.selectedLanguage = .en
        }
      }
    }
  }
}

更多细节请阅读库的自述文件。


2
你的解决方案让我的应用程序进入了无限循环! - Basel
@Basel 你能提供更多关于这个问题的细节吗?我在我的应用程序中使用它,它运行良好。 - undefined
@AbedalkareemOmreyh 我猜withAnimation在低版本上可能有一些问题。你在iOS14上测试过吗? - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接