UE4 从无到有纯 C++ & Slate 开发沙盒游戏(六) 语言切换功能的实现

时间:2024-03-04 14:36:19

实现游戏的中英文对应

由于界面标题中有中文乱码,这个可以通过修改编译器的编码为UTF-8解决,也可以通过UE4自带的本地化方法解决,自带方法包括:

1. TEXT() 创建一个通用的 String 类型,  TEXT("Hello");

2. LOCTEXT() 创建一个本地化文字,  LOCTEXT ("ID" "String");

3. NSLOCTEXT() 在一个域名空间内的本地化,  NSLOCTEXT (Namespace"," "Name","Hello"); 

 

以下为使用2、3两种方法来实现的本地化

新建一个类 SlAiInternation

只需要头文件就好,将项目下的.cpp文件移除,资源文件夹中的文件删除

 

 

编辑文件

D:\UE4 Project\UE26.2\CourseProject\SlAiCourse\Source\SlAiCourse\Public\Date\SlAiInternation.h

#include "CoreMinimal.h"

class SLAICOURSE_API SlAiInternation
{
public:

    static void Register(FText, Value)
        [
            return;
        ]
};

#define LOCTEXT_NAMESPACE "SlAiMenu"

/**
*主菜单
*/
SlAiInternation::Register(LOCTEXT("Menu", "Menu"));
SlAiInternation::Register(LOCTEXT("startGame", "startGame"));                  //开始游戏
SlAiInternation::Register(LOCTEXT("Gameoption", "Gameoption"));                //游戏设置
SlAiInternation::Register(LOCTEXT("QuitGame", "QuitGame"));                    //退出游戏
SlAiInternation::Register(LOCTEXT("NewGame", "NewGame"));                      //新游戏
SlAiInternation::Register(LOCTEXT("LoadRecord", "LoadRecord"));                //加载存档
SlAiInternation::Register(LOCTEXT("ChooseRecord", "ChooseRecord"));            //选择存档

/**
*进入游戏界面
*/
SlAiInternation::Register(LOCTEXT("RecordName", "RecordName"));                         //存档名
SlAiInternation::Register(LOCTEXT("EnterGame", "EnterGame"));                           //进入游戏
SlAiInternation::Register(LOCTEXT("EnterRecord", "EnterRecord"));                       //进入存档
SlAiInternation::Register(LOCTEXT("RecordNameHint", "Input Record Name!"));             //输入存档名
SlAiInternation::Register(LOCTEXT("NameRepeatedHint", "Record Name Repeated!"));        //输入存档名

/**
*游戏设置界面
*/
SlAiInternation::Register(LOCTEXT("Chinese", "Chinese"));                //中文
SlAiInternation::Register(LOCTEXT("English", "English"));                //英文
SlAiInternation::Register(LOCTEXT("Music", "Music"));                    //音乐
SlAiInternation::Register(LOCTEXT("Sound", "Sound"));                    //音效

/**
*公用
*/
SlAiInternation::Register(LOCTEXT("GoBack", "GoBack"));                 //返回
#undef LOCTEXT_NAMESPACE
/************************************************************************************************ * SlAiInternation::Register(NSLOCTEXT("SlAiMenu", "Menu", "Menu")) * *上方三行代码与这一行代码作用是一样的,区别在于上方三行是将域名放到外面,而NSLOCTEXT是将域名放到里面 * 其他文件中想要调用该本地化文字的时候,可以直接通过 NSLOCTEXT 调用,不用很麻烦的先去声明域名再去调用 LOCTEXT *************************************************************************************************/

 

NSLOCTEXT 的调用方式

D:\UE4 Project\UE26.2\CourseProject\SlAiCourse\Source\SlAiCourse\Private\UI\Widget\SSlAiMenuWidget.cpp

#include "UI/Widget/SSlAiMenuWidget.h"
#include "SlateOptMacros.h"
#include "UI/Style/SlAiStyle.h"
#include "UI/Style/SlAiMenuWidgetStyle.h"
#include "Widgets/Layout/SBox.h" 
#include "Widgets/Images/SImage.h"
#include "Widgets/Text/STextBlock.h"

BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
void SSlAiMenuWidget::Construct(const FArguments& InArgs)
{

    MenuStyle = &SlAiStyle::Get().GetWidgetStyle<FSlAiMenuStyle>("BPSlAiMenuStyle");
    
    ChildSlot
    [

        SAssignNew(RootSizeBox, SBox)
        [
            SNew(SOverlay)

            +SOverlay::Slot()
                .HAlign(HAlign_Fill)
                .VAlign(VAlign_Fill)
                .Padding(FMargin(0.f, 50.f, 0.f, 0.f)) 
                [
                    SNew(SImage)
                    .Image(&MenuStyle->MenuBackgroundBrush)
                ]

            +SOverlay::Slot()
                .HAlign(HAlign_Left)
                .VAlign(VAlign_Center)
                .Padding(FMargin(0.f, 25.f, 0.f, 0.f))
                [
                    SNew(SImage).Image(&MenuStyle->LeftIconBrush)
                ]

            + SOverlay::Slot()
                .HAlign(HAlign_Right)
                .VAlign(VAlign_Center)
                .Padding(FMargin(0.f, 25.f, 0.f, 0.f))
                [
                    SNew(SImage).Image(&MenuStyle->RightIconBrush)
                ]

            + SOverlay::Slot()
                .HAlign(HAlign_Center)
                .VAlign(VAlign_Top)
                [
                    SNew(SBox)
                    .WidthOverride(400.f)
                    .HeightOverride(100.f)
                    [
                        SNew(SBorder)
                        .BorderImage(&MenuStyle->TitleBorderBrush)
                        .HAlign(HAlign_Center)
                        .VAlign(VAlign_Center)
                        [
                            SAssignNew(TitleText, STextBlock)
                            .Font(SlAiStyle::Get().GetFontStyle("MenuItemFort")
                            .Text(NSLOCTEXT("SlAiMenu", "Menu", "Menu"))          //使用 NSLOCTEXT 宏插入的本地化文字,三个参数为:域名 Key Value
                        ]
                    ]
                ]
        ]
    ];

    RootSizeBox->SetWidthOverride(600.f);
    RootSizeBox->SetHeightOverride(510.f);

}
END_SLATE_FUNCTION_BUILD_OPTIMIZATION

 

在UE4中的菜单,Window ->  Localization Dashboard

打开本地化设置

我的 Source 文件下包含了所有的头文件,UE4会从该目录下搜索所有有关于 LOCTEXT 以及 NSLOCTEXT 两个宏的本地化文字

 

Add New Culture 新增中文,并点击 English 前方圆钮将英文设置为默认选项

点击Gather Text寻找本地化文字,下图为寻找结果,找到21个英文语言,有1个中文翻译(这一个是我之前加的,如果从未添加过这里应该是0)

 

 点击添加中文翻译

 

 写入对应的中文,然后保存

 

 点击 Count Words 刷新进度

 

然后再点击 Compile Text 进行编译,让UE4将这个文件拷贝到 Cultures 本地化文件夹的格式文件中

它会在本地生成两个文件夹 en ch 这里放置翻译的一些内容

 

 

 

这时候在运行游戏,便不会再显示中文乱码

 

 

代码控制UI界面的文字显示:


#include "Internationalization/Internationalization.h"                        //一个关于本地化的头文件
/**
 *切换语言
 */
 FInternationalization::Get().SetCurrentCulture(TEXT("en"));
 //FInternationalization::Get().SetCurrentCulture(TEXT("ch"));

 

 

游戏中实现中英文切换

接下来写两个类,来标记游戏中目前是中文还是英文

SlAiTypes 存放基础的数据结构

SlAiDataDandle 来实现切换中英文的方法

 

SlAiTypes 也不要 .cpp 文件,留一个 .h 文件便可,将其删除,并移出项目

d:\ue4 project\ue26.2\courseproject\slaicourse\Source\SlAiCourse\Public\Data\SlAiTypes.h

#include "CoreMinimal.h"

UENUM()
enum class ECultrueTeam : uint8
{
    EN = 0,
    ZH
};

 

 

d:\ue4 project\ue26.2\courseproject\slaicourse\Source\SlAiCourse\Public\Data\SlAiDataHandle.h

#include "SlAiTypes.h"
#include "CoreMinimal.h"


class SLAICOURSE_API SlAiDataHandle
{
public:
    SlAiDataHandle();

    static void Initialize();

    static TSharedPtr<SlAiDataHandle> Get();

    //修改中英文
    void ChangeLocalizationCultrue(ECultrueTeam Culture);

public:
    /**
    * 当前语言状态,保存后转换场景后还会用到
    * 这里没有使用UE4 GamePlay 框架的 GameInstance,变量直接写到C++类中除非你主动销毁,否则他会一直存在
    */
    ECultrueTeam CurrentCulture;

private:
    //创建单例
    static TSharedRef<SlAiDataHandle> Create();

private:
    static TSharedPtr<SlAiDataHandle> DataInstance;

};

 

 

D:\UE4 Project\UE26.2\CourseProject\SlAiCourse\Source\SlAiCourse\Private\Data\SlAiDataHandle.cpp

#include "Data/SlAiDataHandle.h"


TSharedPtr<SlAiDataHandle> SlAiDataHandle::DataInstance = NULL;

void SlAiDataHandle::Initialize()
{
    if (!DataInstance.IsValid())
    {
        DataInstance = Create();
    }
}

TSharedPtr<SlAiDataHandle> SlAiDataHandle::Get()
{
    Initialize();
    return DataInstance;
}

TSharedRef<SlAiDataHandle> SlAiDataHandle::Create()
{
    /**
    *MakeShareable 可以用来创建共享指针和共享引用
    */
    TSharedRef<SlAiDataHandle> DataRef = MakeShareable(new SlAiDataHandle());
  return DataRef; } SlAiDataHandle::SlAiDataHandle() { }
void SlAiDataHandle::ChangeLocalizationCultrue(ECultrueTeam Culture) { switch (Culture) { case ECultrueTeam::EN: FInternationalization::Get().SetCurrentCulture(TEXT("en")); break; case ECultrueTeam::ZH: FInternationalization::Get().SetCurrentCulture(TEXT("zh")); break; } //赋值 CurrentCulture = Culture; }