首页 > 其他分享 >Unity实现一个简单的在线翻译功能,编辑器扩展和运行时

Unity实现一个简单的在线翻译功能,编辑器扩展和运行时

时间:2024-11-14 10:14:36浏览次数:3  
标签:originalText request 编辑器 EditorGUILayout Unity new translateRequest public 在线翻译

前言

在Unity项目开发过程中,经常需要处理多语言文本。本文将介绍如何实现一个简单实用的在线翻译功能,通过调用Google翻译API,帮助开发者快速完成文本翻译工作。既可以在编辑器中使用,也可以在运行时调用,满足不同场景的翻译需求。


一、效果演示(编辑器扩展)

在这里插入图片描述

<iframe allowfullscreen="true" data-mediaembed="csdn" frameborder="0" id="1WxfVKOZ-1731550943254" src="https://live.csdn.net/v/embed/433997"></iframe>

TranslateTest

二、制作过程

简言

主要使用Unity 的网络请求类UnityWebRequest,使用Google翻译的公开接口发送https的POST请求。以下拆分来逐步实现,完整代码在最后。

1.安装依赖包Newtonsoft Json(特别注意以下说明!)

首先说明,不安装此包也是可以的,需要把请求的Json和返回的Json单独写两个类使用Unity的JsonUtility进行序列化和反序列化也可以。本文使用Newtonsoft Json工具,功能更加强大。

安装方式如下
1、打开Unity的Package Manager
2、选择注册表中的包并搜索Newtonsoft Json进行安装
在这里插入图片描述

3、安装后重启代码编辑器Visual Studio或Visual Studio Code等,不然可能出现搜索不到对应的API和命名空间。

2.定义字段和方法

代码如下(示例):

	//Google翻译的API接口
	public const string TranslateUrl = "https://googlet.deno.dev/translate";
    public string originalText;    // 输入内容
    public string translatedText;  // 输出内容
    public int targetLanguage;     // 目标语言
    public bool isTranslating;     // 是否正在翻译
    //翻译目标语言字典,还支持其他常见语言,可自行搜索添加,本处为常用的几种语言
    public Dictionary<string, string> targetLanguages = new Dictionary<string, string>()
    {
        {"auto", "自动"},
        {"zh", "中文"},
        {"en", "英语"},
        {"de", "德语"},
        {"ru", "俄语"},
        {"fr", "法语"},
        {"ja", "日语"},
        {"ko", "韩语"},
    };
    
    //调用协程请求方法
	public void Translate(string originalText, string targetLanguage = "auto", Action<string> onTranslate = null)
    {
        if (isTranslating || string.IsNullOrEmpty(originalText)) return;
        StartCoroutine(TranslateCoroutine(originalText, targetLanguage, onTranslate));
    }

	/// <summary>
    /// 用协程处理翻译请求
    /// </summary>
    /// <param name="originalText">输入内容</param>
    /// <param name="targetLanguage">目标语言</param>
    /// <param name="onTranslate">翻译完成回调</param>
    /// <returns></returns>
    IEnumerator TranslateCoroutine(string originalText, string targetLanguage, Action<string> onTranslate)
    {
        isTranslating = true;
        /* 请求格式,请求方式为POST请求:
        {
            "text": “"test",
            "source_lang": "auto",
            "target lang": "zh"
        }*/
        /* 回复格式:
        {
            "code"”: 200,
            "data":“测试”
        } */
        JObject translateData = new JObject()//这里使用Newtonsoft.Json库来处理json请求数据格式
        {
            ["text"] = originalText,
            ["source_lang"] = "auto",
            ["target_lang"] = targetLanguage,
        };
        UnityWebRequest request = new UnityWebRequest(TranslateUrl, "POST");//创建一个Post请求
        byte[] bodyRaw = Encoding.UTF8.GetBytes(translateData.ToString());
        request.uploadHandler = new UploadHandlerRaw(bodyRaw);
        request.downloadHandler = new DownloadHandlerBuffer();
        request.SetRequestHeader("Content-Type", "application/json");//设置请求头

        yield return request.SendWebRequest();//发送请求
        if (request.isNetworkError || request.isHttpError)
        {
            Debug.LogError(request.error);
        }
        else
        {
            try
            {
                JObject responseData = JObject.Parse(request.downloadHandler.text);//解析回复数据
                onTranslate?.Invoke(responseData["data"].ToString());//获取data字段内容并调用回调函数
            }
            catch (Exception e)
            {
                Debug.LogError(e);
            }
        }
        isTranslating = false;
    }

现在就可以在运行时通过调用Translate方法进行使用了,本文再讲一下实现编辑器扩展在未播放时使用。

3.编写编辑器扩展方法

/// <summary>
/// 编辑器扩展
/// </summary>
#if UNITY_EDITOR    
[CustomEditor(typeof(TranslateRequest))]
public class TranslateRequestEditor : Editor
{
    private TranslateRequest translateRequest;//翻译组件
    private GUIStyle textAreaStyle;//文本区域样式
    private Vector2 inputScrollPos;//输入区域滚动位置

    private void OnEnable()
    {
        translateRequest = (TranslateRequest)target;
        textAreaStyle = new GUIStyle(EditorStyles.textArea)
        {
            wordWrap = true//自动换行
        };
    }

    public override void OnInspectorGUI()
    {
        serializedObject.Update();//更新序列化对象

        // 输入区域
        using (new EditorGUILayout.HorizontalScope())
        {
            EditorGUILayout.LabelField("输入内容", GUILayout.MaxWidth(50));
            using (var scrollView = new EditorGUILayout.ScrollViewScope(inputScrollPos))//绘制输入区域
            {
                inputScrollPos = scrollView.scrollPosition;
                translateRequest.originalText = EditorGUILayout.TextArea(
                    translateRequest.originalText,
                    textAreaStyle,
                    GUILayout.ExpandHeight(true)
                );
            }
        }

        // 输出区域
        using (new EditorGUILayout.HorizontalScope())
        {
            EditorGUILayout.LabelField("翻译结果", GUILayout.MaxWidth(50));
            translateRequest.translatedText = EditorGUILayout.TextArea(
                translateRequest.translatedText,
                textAreaStyle
            );
        }

        using (new EditorGUILayout.HorizontalScope())
        {
            translateRequest.targetLanguage = EditorGUILayout.Popup(translateRequest.targetLanguage, translateRequest.targetLanguages.Values.ToArray(), GUILayout.MaxWidth(100));
            if (GUILayout.Button("清空"))
            {
                translateRequest.translatedText = "";
            }
            if (GUILayout.Button("复制"))
            {
                GUIUtility.systemCopyBuffer = translateRequest.translatedText;
            }
        }

        GUI.enabled = !translateRequest.isTranslating;//翻译时不可编辑
        if (GUILayout.Button(translateRequest.isTranslating ? "翻译中..." : "翻译"))
        {
            translateRequest.Translate(translateRequest.originalText, translateRequest.targetLanguages.Keys.ToArray()[translateRequest.targetLanguage], x =>
            {
                translateRequest.translatedText = x;
            });
        }
        GUI.enabled = true;//恢复编辑
        serializedObject.ApplyModifiedProperties();//应用修改
    }
}
#endif

编写后将脚本挂载在一个空物体身上,检查器面板上效果如下:
在这里插入图片描述

三、完整代码:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Newtonsoft.Json.Linq;
using UnityEditor;
using UnityEngine;
using UnityEngine.Networking;

public class TranslateRequest : MonoBehaviour
{
    public const string TranslateUrl = "https://googlet.deno.dev/translate";//翻译接口
    public string originalText;//输入内容
    public string translatedText;//输出内容
    public int targetLanguage;//目标语言
    public bool isTranslating;//是否正在翻译
    public Dictionary<string, string> targetLanguages = new Dictionary<string, string>()//目标语言
    {
        {"auto", "自动"},
        {"zh", "中文"},
        {"en", "英语"},
        {"de", "德语"},
        {"ru", "俄语"},
        {"fr", "法语"},
        {"ja", "日语"},
        {"ko", "韩语"},
    };

    public void Translate(string originalText, string targetLanguage = "auto", Action<string> onTranslate = null)
    {
        if (isTranslating || string.IsNullOrEmpty(originalText)) return;
        StartCoroutine(TranslateCoroutine(originalText, targetLanguage, onTranslate));
    }

    /// <summary>
    /// 用协程处理翻译请求
    /// </summary>
    /// <param name="originalText">输入内容</param>
    /// <param name="targetLanguage">目标语言</param>
    /// <param name="onTranslate">翻译完成回调</param>
    /// <returns></returns>
    IEnumerator TranslateCoroutine(string originalText, string targetLanguage, Action<string> onTranslate)
    {
        isTranslating = true;
        /* 请求格式,请求方式为POST请求:
        {
            "text": “"test",
            "source_lang": "auto",
            "target lang": "zh"
        }*/
        /* 回复格式:
        {
            "code"”: 200,
            "data":“测试”
        } */
        JObject translateData = new JObject()//这里使用Newtonsoft.Json库来处理json请求数据格式
        {
            ["text"] = originalText,
            ["source_lang"] = "auto",
            ["target_lang"] = targetLanguage,
        };
        UnityWebRequest request = new UnityWebRequest(TranslateUrl, "POST");//创建一个Post请求
        byte[] bodyRaw = Encoding.UTF8.GetBytes(translateData.ToString());
        request.uploadHandler = new UploadHandlerRaw(bodyRaw);
        request.downloadHandler = new DownloadHandlerBuffer();
        request.SetRequestHeader("Content-Type", "application/json");//设置请求头

        yield return request.SendWebRequest();//发送请求
        if (request.isNetworkError || request.isHttpError)
        {
            Debug.LogError(request.error);
        }
        else
        {
            try
            {
                JObject responseData = JObject.Parse(request.downloadHandler.text);//解析回复数据
                onTranslate?.Invoke(responseData["data"].ToString());//获取data字段内容并调用回调函数
            }
            catch (Exception e)
            {
                Debug.LogError(e);
            }
        }
        isTranslating = false;
    }
}

/// <summary>
/// 编辑器扩展
/// </summary>
#if UNITY_EDITOR    
[CustomEditor(typeof(TranslateRequest))]
public class TranslateRequestEditor : Editor
{
    private TranslateRequest translateRequest;//翻译组件
    private GUIStyle textAreaStyle;//文本区域样式
    private Vector2 inputScrollPos;//输入区域滚动位置

    private void OnEnable()
    {
        translateRequest = (TranslateRequest)target;
        textAreaStyle = new GUIStyle(EditorStyles.textArea)
        {
            wordWrap = true//自动换行
        };
    }

    public override void OnInspectorGUI()
    {
        serializedObject.Update();//更新序列化对象

        // 输入区域
        using (new EditorGUILayout.HorizontalScope())
        {
            EditorGUILayout.LabelField("输入内容", GUILayout.MaxWidth(50));
            using (var scrollView = new EditorGUILayout.ScrollViewScope(inputScrollPos))//绘制输入区域
            {
                inputScrollPos = scrollView.scrollPosition;
                translateRequest.originalText = EditorGUILayout.TextArea(
                    translateRequest.originalText,
                    textAreaStyle,
                    GUILayout.ExpandHeight(true)
                );
            }
        }

        // 输出区域
        using (new EditorGUILayout.HorizontalScope())
        {
            EditorGUILayout.LabelField("翻译结果", GUILayout.MaxWidth(50));
            translateRequest.translatedText = EditorGUILayout.TextArea(
                translateRequest.translatedText,
                textAreaStyle
            );
        }

        using (new EditorGUILayout.HorizontalScope())
        {
            translateRequest.targetLanguage = EditorGUILayout.Popup(translateRequest.targetLanguage, translateRequest.targetLanguages.Values.ToArray(), GUILayout.MaxWidth(100));
            if (GUILayout.Button("清空"))
            {
                translateRequest.translatedText = "";
            }
            if (GUILayout.Button("复制"))
            {
                GUIUtility.systemCopyBuffer = translateRequest.translatedText;
            }
        }

        GUI.enabled = !translateRequest.isTranslating;//翻译时不可编辑
        if (GUILayout.Button(translateRequest.isTranslating ? "翻译中..." : "翻译"))
        {
            translateRequest.Translate(translateRequest.originalText, translateRequest.targetLanguages.Keys.ToArray()[translateRequest.targetLanguage], x =>
            {
                translateRequest.translatedText = x;
            });
        }
        GUI.enabled = true;//恢复编辑
        serializedObject.ApplyModifiedProperties();//应用修改
    }
}
#endif

四、总结

此功能实现简单,使用方便,能够满足基本的文本翻译需求。通过异步请求和协程的使用,确保了翻译过程不会影响项目的正常运行。开发者可以根据实际需求,在此基础上进行功能扩展。

如果觉得这篇文章对你有帮助,欢迎点赞收藏!如有问题或其他想实现的功能以及技术问题,欢迎在评论区留言交流。

标签:originalText,request,编辑器,EditorGUILayout,Unity,new,translateRequest,public,在线翻译
From: https://blog.csdn.net/weixin_41741510/article/details/143758433

相关文章

  • 【Unity】仓库逻辑:拾取物体进仓库和扔掉物品
    需求说明目标:实现玩家移动过程中,拾取物体,物体被放入仓库;点击仓库中物体,重新扔回3D场景中逻辑。逻辑分析:需要玩家可以移动;需要检测玩家和物体的碰撞,并摧毁物体;需要识别物体的类别;新物体直接新建,已有的物体增加数量;需要记录仓库的物体详情列表,并响应列表的变化;需要仓库的UI......
  • Unity类银河战士恶魔城学习总结(P124 Limit Inventory Slots 限制库存槽位)
    【Unity教程】从0编程制作类银河恶魔城游戏_哔哩哔哩_bilibili教程源地址:https://www.udemy.com/course/2d-rpg-alexdev/本章节实现了仓库满了不能添加物品,而且会摧毁物品的Bug并且增加了背包满了拾取物品的一个小动画ItemObject.csusingSystem.Collections;usingSyst......
  • 【Unity 天气系统插件】Enviro 3 - Sky and Weather 高度可定制的云、雾和光照系统
    Enviro3-SkyandWeather是一款功能强大的Unity插件,专门用于模拟逼真的天空、天气和环境效果。它适用于需要动态天气和日夜循环的游戏或应用,如开放世界RPG、模拟类游戏等。Enviro3提供了大量的设置选项和自定义功能,帮助开发者在Unity中创建沉浸式的自然环境效果。......
  • 【Unity第一人称射击游戏 (FPS) 动画框架】FPS Animation Framework ,提供了 武器动画
    FPSAnimationFramework是一款为Unity提供的专门用于第一人称射击游戏(FPS)的动画框架插件。它旨在帮助开发者快速实现FPS游戏中的角色控制、武器操作、动作与动画等核心功能。通过该框架,开发者可以轻松创建高质量、流畅的动画效果,提高玩家的沉浸感与游戏的打击感......
  • 【Unity怪物角色资源包】Fantasy Monsters Animated [Megapack] 丰富的怪物模型,快速充
    FantasyMonstersAnimated[Megapack]是一款为Unity开发的怪物角色资源包,包含了大量动画怪物模型,特别适合RPG、幻想冒险和动作游戏。该资源包不仅提供了种类丰富的怪物模型,还包括多种动画,帮助开发者快速创建复杂且生动的敌人角色。此资源包非常适合想要打造魔幻或中......
  • 【Unity着色器插件】Better Lit Shader 2021 增强光照和材质表现,在性能和美观度上做出
    BetterLitShader2021是一款在Unity中广受欢迎的着色器插件,主要用于增强光照和材质表现。它在性能和美观度上做出平衡,非常适合希望在Unity中实现高质量视觉效果的开发者,特别是那些想要获得逼真光照效果的项目。主要功能多光照支持:支持多个光源在场景中同时使用,例如主光......
  • 【Unity人群寻路插件】CrowdPath Pathfinding 高效的路径规划算法来模拟群体寻路行为,
    CrowdPathPathfinding是一款专为Unity设计的路径寻找插件,主要用于处理复杂的人群导航问题,特别适合需要大规模虚拟人物群体移动的游戏或应用。它通过高效的路径规划算法来模拟群体行为,如避开障碍、避免拥挤、相互避让等。主要特点:高效的人群路径寻找:插件能够在复杂环境......
  • ubuntu下配置vim插件,实现轻量级代码编辑器
    背景因为需要用虚拟机做实验,然后虚拟机配置的内存很小,如果使用vscode编辑器,内存占用太高,所以放弃,远程使用vscode通过sftp链接也会有很多bug,所以也放弃,鉴于以上。只能考虑使用vimvim的优点轻量级不需要gui的支持,可以在server和desktop版本之间不限制是使用vim插件安装cu......
  • Unity类银河战士恶魔城学习总结(P123 UI)UI创建的开始
    【Unity教程】从0编程制作类银河恶魔城游戏_哔哩哔哩_bilibili教程源地址:https://www.udemy.com/course/2d-rpg-alexdev/本章节实现了UI的初步创建层级的设置UI.cs详细工作原理:1.遍历并隐藏所有子元素:transform.childCount:获取当前对象下所有子对象的数量。transform......
  • 施耐德UNITY下使用ST编程计算最近一小时的均值
    昨晚学习练习了ST语言做最近60秒的分钟均值,今天继续做最近一小时的均值,1秒采集一次数据。在昨晚程序上增加功能,新建一个导出的功能块类型Average_Hour,定义下面的变量:旗下新建一个程序段Average_Hour,使用ST编程Minute1:=BCD_TO_INT(%SW51);Minute:=mod_int(Minute1,100);Second1......