o3de / sig-content

8 stars 12 forks source link

Proposed RFC Feature: Internationalization Support #114

Open Shirley-yhm opened 1 year ago

Shirley-yhm commented 1 year ago

Summary:

This feature proposes to implement internationalization in O3DE to support other languages besides English on UI.

What is the relevance of this feature?

O3DE only supports English on UI currently, which is not so friendly to users from other countries. Especially for new users who had never done 3D product development before, support for their native language might help them start with O3DE and understand the terminologies more easily.

The proposed solution implements internationalization support in O3DE. After this work, developers only need to add a new language type and translate strings that have already been extracted to support any other language as they want.

Feature design description:

Mechanism of QT's internationalization support is used in this feature. The basic flow is as follows (Chinese translation for example).

  1. Tag —— Tag all strings to be translated on UI in source code.

    // Before tagged
    AZ_Printf("Editor", "Hello");
    
    // After tagged
    AZ_Printf("Editor", tr("Hello"));
    AZ_Printf("Editor", QObject::tr("Hello"));
    AZ_Printf("Editor", QT_TRANSLATE_NOOP("xxx", "Hello"));
  2. Extract —— Use lupdate in QT to extract tagged strings into translation files with .ts suffix.

    • Directory Structure:

      >Translations
          >en
              >Editor_en.ts
              >qtbase_en.ts
          >zh_CN
              >Editor_zh_CN.ts
              >qtbase_zh_CN.ts
    • Information of the tagged string with file path and line number will be added into TS file.

      <message>
          <location filename="../relative_path/Example.cpp" line="100"/>
          <source>Hello</source>
          <translation type="unfinished"></translation>
      </message>
  3. Translate —— Use Linguist Tool in QT to translate tagged strings in translation files. Developers can also modify TS files directly.
    • Chinese translation will be added, and the type will be marked as finished.
      <message>
          <location filename="../relative_path/Example.cpp" line="100"/>
          <source>Hello</source>
          <translation>你好</translation>
      </message>
  4. Compile —— Use lrelease in QT to compile the translation files with .qm suffix.

    • Directory Structure:

      >Translations
          >en
              >Editor_en.qm
              >qtbase_en.qm
          >zh_CN
              >Editor_zh_CN.qm
              >qtbase_zh_CN.qm
  5. Set Translators —— Set translators for every module needs to be translated.
    • Translations are seperated into different files for every module. In particular, qtbase is added to locate translations for basic Qt modules, such as Qt Core, Qt GUI, Qt Network, and Qt Widgets
      QStringList translatorNames = { 
          "Editor",
          "qtbase",
          // More modules like AssetProcessor, AzToolsFramework, and every Gem...
      };
  6. Load/Unload Translator —— Load translators before UI is initialized, and unload translators before UI exits.

Technical design description:

Internationalization with QT

Internationalization with QT supports most languages in use today, and and will work on all platforms as long as the system has fonts to render these writing systems installed.

Following APIs are mainly used: API description
QTranslator Provides internationalization support for text output.
QLocale Converts between numbers and their string representations in various languages.
QTextCodec Provides conversions between text encodings.

Three tools in QT are used to generate translation files automatically:

Implementation in O3DE

Currently, some strings to be translated have been tagged using Object::tr(). Translators are loaded in EditorQtApplication::Initialize().

void EditorQtApplication::Initialize()
{
    // Install QTranslator
    InstallEditorTranslators();
}

void EditorQtApplication::InstallEditorTranslators()
{
    m_editorTranslator =        CreateAndInitializeTranslator("editor_en-us.qm", ":/Translations");
    m_assetBrowserTranslator =  CreateAndInitializeTranslator("assetbrowser_en-us.qm", ":/Translations");
}

QTranslator* EditorQtApplication::CreateAndInitializeTranslator(const QString& filename, const QString& directory) { }

void EditorQtApplication::UninstallEditorTranslators() { }

However, the current implementation only supports localization in Editor and Asset Browser, and strings not in subclasses of QObject can't be translated.

Step 1. Set Translators

Based on what has been done in O3DE, this proposal uses m_translators with type QVector to store translators.

QVector<QTranslator*> m_translators;

void EditorQtApplication::InstallTranslators()
{
    QTextCodec::setCodecForLocale(QTextCodec::codecForName("utf-8"));

    QStringList translatorNames = { "Editor", "qtbase", "AzToolsFramework" }; // Translators of Editor for example
    // QStringList translatorNames = { "qtbase", "AssetProcessor", "AzToolsFramework", "AzQtComponents" }; // Translators of Asset Processor for example

    for (QString trans : translatorNames)
    {
        m_translators.append(AzToolsFramework::CreateAndLoadTranslator(trans));
    }
}
Step 2. Load & Unload Translators

Since the startup time of each process are actually different, translators are loaded in every module separately.

Step 3. Tag

There are three types of strings to translate:

Step 4. Extract

Strings tagged are extracted into corresponding TS files automatically.

Step 5. Translate

TS files are in type of XML. Translations can be added manually or using Qt Linguist tool.

After translation, TS files will be simplified and compiled into QM files with suffix .qm automatically. QM files are fast compact versions of TS files.

Step 6. Read

Language Setting

A new setting for language is also needed in Editor Settings for users to switch language. It's designed like the setting named Console Background.

Work Plan

  1. Firt PR: Basic architeture of localization & Chinese translation of Editor and Asset Processor
    • Tag strings in Editor and Asset Processor.
    • Add cmake files to generate translation files (TS and QM) automatically.
    • Translate tagged strings into Chinese.
    • Provide back-end code to load the translation files at startup and unload them at teardown.
    • Add a setting for language in Editor Settings.
  2. Follow-up documentation: Documents about how to use and how to contribute to this feature.
  3. Incremental PRs: Chinese translations of other modules like Gems.
  4. Translations in other languages contributed by the community.

What are the advantages of the feature?

How will this be implemented or integrated into the O3DE environment?

CMake build files will be added in the first PR. No additional processing is required by developers.

How will users learn this feature?

Once this proposal is passed, documents will be provided for users and developers to learn this feature.

Are there any open questions?

Potential User Experience Improvements

According to the user experience we have collected, there are two questions worth considered.

  1. Editor needs to restart to change the display language currently. Since it takes a long time to launch Editor and Asset Processor, restarting may lead to poor user experience.

    • Is there any way to achieve hot reload in O3DE to avoid restart when change genaral settings?
  2. It's hard to translate some terminologies accurately for developers, and inappropriate translations may confuse users.

    • Once hot reload is achieved, users wil be able to switch language to understand terminologies easily. But if not, is there any way to simplify users' operations when they want to know the meaning of the terminologies in other languages?
    • Some experiment has been done in this scenario: Add description in English into tooltips when the display language is set to Chinese. However, this may lead to overly long tooltips and poor user experience. This will also increase the burden on developers who add translations.

      // tooltip in English
      Hello, O3DE
      
      // tooltip in Chinese
      Hello, O3DE
      你好,ODE
    • Another option is to add a button in every component which allows users to change the language partially.

    Both of the above two questions need UX design and technical support.

  3. Title of window's name is used as the key to store its layout. When the display language changed, key of the window will also change and information of its layout will become invalid.

    // Information of layout in English
    ["Asset Browser", struct_of_layout]
    
    // Information of layout in English
    ["资产浏览器", struct_of_layout]
    • Is it possible to decouple the identifier and title of every module?
Shirley-yhm commented 1 year ago

We've had some discussions in https://github.com/o3de/o3de/discussions/14287

Ulrick28 commented 1 year ago

Awesome feature, thanks for the rfc! An option for terminology that doesn't translate well is to just not translate that particular item until an appropriate translation is determined. Many products follow this model.

Ideally I would want to see testing against at least 3 languages (english, chinese, and ???) but understand that may not be feasible. Also, there will be considerations for button sizing and alignment in the editor. Example german is known for long translations, japanese fonts tend to be taller. We will also need to test what kind of performance and memory impact this will have.

nick-l-o3de commented 1 year ago

I still think its a great idea to get the architecture in place and start making steps towards doing this. No reason not to start just because the road is long.

The only point I'd like to try to make here is that we have a bunch of code that isn't necessarily based on Qt and still emits english errors and other text (such as the runtime, other tools potentially, python scripts). in which case we'd need to think of whether we want a separate mechanism for translating those, since putting Qt in them would probably not be okay from a license (GPL-3 vs Apache) situation.

Its possible we could still use the same tags and macros, tooling (Lupdate, qt linguist) but use them without linking to qt.

Shirley-yhm commented 1 year ago

Thanks for your feedback :)

  1. Test against at least 3 languages

    • I'm sorry that no one in my team knowns other languages besides English and Chinese. We have tested other languages like Japanese in some modules, it can be added successfully like Chinese.
  2. UI adaptation

    • UI adaptation and UX are worth considering. I'm afraid we need professionals to help design it and it may take a lot of time. However, I don't think this problem should hinder our progress in this RFC, cause we have added Chinese translations in our branch and everything goes well. After the first PR, developers from other countries can follow the guidance to add translations of other languages, from which we can gather advices on UI and UX.
  3. Performance and Memory impact

    • We have added translations on our branch for every modules, including Editor, Asset Processor and Gems. The total size of TS files is around 4 MB, and the total size of QM files is around 1 MB. The built from our branch has been used in my team for a long time, and the impact on performance is also not obvious.
  4. License of QT

    • We have thought about it before. The tools (lupdate, Linguist, lrelease) are only used to generate QM files by developers when they add translations, and they won't link to the engine.
Shirley-yhm commented 1 year ago

I had some discussion with @yuyihsu, @bhanuja-s(from UX team) and @AMZN-daimini recently. Combined with the above in this RFC, here are some conclusion related.

Should I edit this RFC directly? What should I do once the above 3 points are finished? Please let me know asap if there is any other suggestions. Thanks!


For the sake of future discussion, I put the main contents of our discussion here.