Localization export order

I’m trying to export certain texts for localization. The texts are located in an array in some asset. I run GatherText and then export to .PO file. The problem is that the texts are not gathered the way it stored in an array, but alphabetically! This would be a nightmare to translate, because the context of text (surrounding dialog lines) are lost.

How can I affect an order in which texts are gathered or exported? Any solution would do, even changes in the engine code.

The sorting happens in FPortableObjectFormatDOM::SortEntries.

Generally we find order to be unimportant since once the PO is imported into a translation provider the entries will be sorted however there system wants them to be anyway (although it sounds like you’re editing the POs directly, which is also fine).

If you’re using our dialogue waves for your audio, then these have the ability to provide translation notes that appear as comments in the PO file. If you’re not, then string tables (defined from CSV or in code) have the ability to provide meta-data that appears as comments in the PO file.

Thank you for the answer.

The translation software I’ve encountered (poedit) only provided sorting by translation, and by source text. If you know any PO editor that can sort by reference, we would appreciate a link :slight_smile:

Thank you for the information on string tables, I’ll look into it. For now, I made a simple predicate to sort entries by reference and it does what we need at the moment.

This is an old thread, but I’m stuck with the same problem!

It’s possible somehow to get the text from the localization in order? Dialogs have a lot of context to be able to translate…

I’m sure this is a very basic question, but this is a completely a new world for me. Any solution is valid.

The default sorting method UE is using is by keys, which are essentially random. A nightmare for translators.

However, the default sorting method for PO files seems to be by source references, which makes much more sense.

You could alter the sorting in C++ like Jamie suggested but if you’re not into it, I can offer another solution:

  1. Install Python: https://www.python.org/
  2. Install polib: polib · PyPI
  3. Save this script as a .py file in your game’s Content/Python/ folder:

    import polib
    target_name = “Game”
    locale = “en-US”
    file_name = f"…/Localization/{target_name}/{locale}/{target_name}.po"
    po = polib.pofile(file_name, wrapwidth=0, encoding=‘utf-8-sig’)
    po.sort()
    po.save(file_name)

    Where the locale variable is the locale you want to sort, and the target_name variable is the target you want it sorted in.
  4. Run this script. It’ll sort the PO file you specified via variables by source reference.

Yeah, it’s that simple: it opens the PO file from ‘…/Localization/TargetName/Locale/TargetName.po’ (e.g., ‘…/Localization/Game/en-US/Game.po’ which resolves to ‘/Content/Localization/Game/en-US/Game.po’ if the script is in /Content/Python where it should be) and uses the sort() method… That’s it. As I said, the default sort method for POs is by source reference, which is exactly what you want here. It’ll group together strings that belong together and sit in the same asset, in the same array, etc. Helps a ton.

And Unreal doesn’t care about the order of entries in POs it imports, it just identifies them by namespaces and IDs, so it’s working like a charm.

(One minor annoyance is that it sorts numbers incorrectly since they’re part of a string, e.g., so array[100] comes before array[2]. Might be critical to you but you can fix this by iterating over PO entries and, say, adding zero-padding to indexes in source references (array[0002] will come before array[0100]). See polib docs or ping me later: I’ll be doing that for another project in a week or two.)

Hey, see the answer I posted below. It might do what you want if your dialogs are exported along with other text entries into a PO file.

Hi, thanks for explaining your process.
Unfortunately, I get these errors :

Traceback (most recent call last):
  File "C:\Users\johng\Documents\Unreal Projects\SVZ_427\Content\Python\LocTest_AnswerHubScript_fixed.py", line 9, in <module>
    po = polib.pofile(file_name, wrapwidth=0, encoding='utf-8-sig')
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\johng\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.12_qbz5n2kfra8p0\LocalCache\local-packages\Python312\site-packages\polib.py", line 130, in pofile
    return _pofile_or_mofile(pofile, 'pofile', **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\johng\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.12_qbz5n2kfra8p0\LocalCache\local-packages\Python312\site-packages\polib.py", line 78, in _pofile_or_mofile
    instance = parser.parse()
               ^^^^^^^^^^^^^^
  File "C:\Users\johng\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.12_qbz5n2kfra8p0\LocalCache\local-packages\Python312\site-packages\polib.py", line 1456, in parse
    raise IOError('Syntax error in po file %s(line %s)' %
OSError: Syntax error in po file (line 1)