返回

Unity iOS 自动化本地化:后处理脚本实现弹窗多语言

IOS

Unity iOS 后处理脚本实现本地化

在 Unity 开发 iOS 应用时,有时需要对一些原生 iOS 弹窗进行本地化。这通常依赖于 Xcode 中的本地化设置。本文将探讨如何利用 Unity iOS 后处理脚本自动管理这部分本地化配置,避免手动操作。

问题背景

已成功将本地化 .lproj 文件添加到 Xcode 项目中,但本地化内容未生效。手动将 plist.strings 文件拖拽到 Unity-iPhone 目录下可以解决问题,但这并非理想的自动化流程。我们需要一个更便捷、可靠的解决方案。

利用后处理脚本自动复制本地化文件

核心思路是在 Unity 构建 iOS 项目后,使用后处理脚本自动将正确的本地化 plist.strings 文件复制到 Xcode 项目的正确位置。

脚本实现

以下是一个示例后处理脚本,可以在构建完成后自动复制本地化文件:

using UnityEngine;
using UnityEditor;
using UnityEditor.Callbacks;
using System.IO;

public class iOSLocalizationPostProcess : MonoBehaviour
{
    [PostProcessBuild(100)] // 执行顺序,数字越大越晚执行
    public static void OnPostprocessBuild(BuildTarget target, string pathToBuiltProject)
    {
        if (target == BuildTarget.iOS)
        {
            string localizationPath = Path.Combine(pathToBuiltProject, "Unity-iPhone/Resources"); // Unity iOS 资源目录

            // 获取当前构建的本地化语言
            string currentLanguage = PlayerSettings.iOS.appleDeveloperTeamID; // 此处需要根据实际情况获取语言代码,例如从 PlayerSettings 中获取

            if (!string.IsNullOrEmpty(currentLanguage)) // 检查语言代码是否有效
            {                
                string sourcePlistPath = Path.Combine(pathToBuiltProject, 
using UnityEngine;
using UnityEditor;
using UnityEditor.Callbacks;
using System.IO;

public class iOSLocalizationPostProcess : MonoBehaviour
{
    [PostProcessBuild(100)] // 执行顺序,数字越大越晚执行
    public static void OnPostprocessBuild(BuildTarget target, string pathToBuiltProject)
    {
        if (target == BuildTarget.iOS)
        {
            string localizationPath = Path.Combine(pathToBuiltProject, "Unity-iPhone/Resources"); // Unity iOS 资源目录

            // 获取当前构建的本地化语言
            string currentLanguage = PlayerSettings.iOS.appleDeveloperTeamID; // 此处需要根据实际情况获取语言代码,例如从 PlayerSettings 中获取

            if (!string.IsNullOrEmpty(currentLanguage)) // 检查语言代码是否有效
            {                
                string sourcePlistPath = Path.Combine(pathToBuiltProject, $"{currentLanguage}.lproj/InfoPlist.strings"); // 源 plist 文件路径
                string destinationPlistPath = Path.Combine(localizationPath, "InfoPlist.strings"); // 目标 plist 文件路径
                if (File.Exists(sourcePlistPath))
                {
                    if (File.Exists(destinationPlistPath))
                    {
                        File.Delete(destinationPlistPath); // 删除旧文件
                    }

                    File.Copy(sourcePlistPath, destinationPlistPath);
                    Debug.Log($"Successfully copied localized InfoPlist.strings for {currentLanguage} to {destinationPlistPath}");
                }
                else
                {
                    Debug.LogError($"Localization file not found: {sourcePlistPath}");
                }

            }

        }
    }

}
quot;{currentLanguage}.lproj/InfoPlist.strings"
); // 源 plist 文件路径 string destinationPlistPath = Path.Combine(localizationPath, "InfoPlist.strings"); // 目标 plist 文件路径 if (File.Exists(sourcePlistPath)) { if (File.Exists(destinationPlistPath)) { File.Delete(destinationPlistPath); // 删除旧文件 } File.Copy(sourcePlistPath, destinationPlistPath); Debug.Log(
using UnityEngine;
using UnityEditor;
using UnityEditor.Callbacks;
using System.IO;

public class iOSLocalizationPostProcess : MonoBehaviour
{
    [PostProcessBuild(100)] // 执行顺序,数字越大越晚执行
    public static void OnPostprocessBuild(BuildTarget target, string pathToBuiltProject)
    {
        if (target == BuildTarget.iOS)
        {
            string localizationPath = Path.Combine(pathToBuiltProject, "Unity-iPhone/Resources"); // Unity iOS 资源目录

            // 获取当前构建的本地化语言
            string currentLanguage = PlayerSettings.iOS.appleDeveloperTeamID; // 此处需要根据实际情况获取语言代码,例如从 PlayerSettings 中获取

            if (!string.IsNullOrEmpty(currentLanguage)) // 检查语言代码是否有效
            {                
                string sourcePlistPath = Path.Combine(pathToBuiltProject, $"{currentLanguage}.lproj/InfoPlist.strings"); // 源 plist 文件路径
                string destinationPlistPath = Path.Combine(localizationPath, "InfoPlist.strings"); // 目标 plist 文件路径
                if (File.Exists(sourcePlistPath))
                {
                    if (File.Exists(destinationPlistPath))
                    {
                        File.Delete(destinationPlistPath); // 删除旧文件
                    }

                    File.Copy(sourcePlistPath, destinationPlistPath);
                    Debug.Log($"Successfully copied localized InfoPlist.strings for {currentLanguage} to {destinationPlistPath}");
                }
                else
                {
                    Debug.LogError($"Localization file not found: {sourcePlistPath}");
                }

            }

        }
    }

}
quot;Successfully copied localized InfoPlist.strings for {currentLanguage} to {destinationPlistPath}"
); } else { Debug.LogError(
using UnityEngine;
using UnityEditor;
using UnityEditor.Callbacks;
using System.IO;

public class iOSLocalizationPostProcess : MonoBehaviour
{
    [PostProcessBuild(100)] // 执行顺序,数字越大越晚执行
    public static void OnPostprocessBuild(BuildTarget target, string pathToBuiltProject)
    {
        if (target == BuildTarget.iOS)
        {
            string localizationPath = Path.Combine(pathToBuiltProject, "Unity-iPhone/Resources"); // Unity iOS 资源目录

            // 获取当前构建的本地化语言
            string currentLanguage = PlayerSettings.iOS.appleDeveloperTeamID; // 此处需要根据实际情况获取语言代码,例如从 PlayerSettings 中获取

            if (!string.IsNullOrEmpty(currentLanguage)) // 检查语言代码是否有效
            {                
                string sourcePlistPath = Path.Combine(pathToBuiltProject, $"{currentLanguage}.lproj/InfoPlist.strings"); // 源 plist 文件路径
                string destinationPlistPath = Path.Combine(localizationPath, "InfoPlist.strings"); // 目标 plist 文件路径
                if (File.Exists(sourcePlistPath))
                {
                    if (File.Exists(destinationPlistPath))
                    {
                        File.Delete(destinationPlistPath); // 删除旧文件
                    }

                    File.Copy(sourcePlistPath, destinationPlistPath);
                    Debug.Log($"Successfully copied localized InfoPlist.strings for {currentLanguage} to {destinationPlistPath}");
                }
                else
                {
                    Debug.LogError($"Localization file not found: {sourcePlistPath}");
                }

            }

        }
    }

}
quot;Localization file not found: {sourcePlistPath}"
); } } } } }

操作步骤

  1. 在 Unity 项目的 Editor 文件夹下创建一个 C# 脚本 (例如 iOSLocalizationPostProcess.cs)。
  2. 将以上代码复制到脚本中,并根据项目实际情况修改 currentLanguage 的获取方式。 获取方式可能包括自定义的构建参数、PlayerSettings中的设置,或从外部配置文件读取等。 确保 currentLanguage 的值与 Xcode 中的 .lproj 文件夹名称匹配(例如 "zh-Hans", "en", "fr" 等)。
  3. 构建 iOS 项目。构建完成后,脚本会自动将对应语言的 InfoPlist.strings 复制到 Unity-iPhone/Resources 目录下。

安全性建议

  • 确保路径正确:仔细检查脚本中使用的路径,特别是 sourcePlistPathdestinationPlistPath,避免错误的复制操作。 使用 Path.Combine 拼接路径更安全,可以避免平台相关的路径分隔符问题。
  • 错误处理:添加错误处理机制,例如检查文件是否存在,并在出现错误时输出日志信息。
  • 版本控制:将 InfoPlist.strings 文件添加到版本控制系统中,方便团队协作和版本管理。

获取语言代码

实际项目中,获取 currentLanguage 的值可能需要根据项目的具体配置方式进行调整。如果使用命令行构建,可以通过命令行参数传入;如果使用 Unity 编辑器构建,可以从 PlayerSettings 或其他自定义设置中获取。 以下示例展示了如何通过 PlayerSettings 获取语言代码(假设你已经将语言代码存储在 PlayerSettings 的一个自定义字段中):

// 获取 PlayerSettings 中自定义的语言代码
string currentLanguage = PlayerSettings.GetString("iOSLocalizationLanguage", ""); // 第二个参数是默认值,如果找不到指定的 key 就返回默认值

通过上述步骤,可以利用 Unity iOS 后处理脚本实现 iOS 本地化的自动化,提高开发效率,避免手动操作带来的风险。 通过灵活的脚本配置,可以更好地适应不同的项目需求,实现精细化的本地化控制。