Current Culture

I am trying to get my head around changing culture and seeing changes in localization, but it is rather confusing. Basically, I added two blueprint library functions that allow me to query and set CurrentCulture. I try to set the current culture at begin play. These are the results:

  1. first of all, the SetCurrentCulture does not seem to permanently change anything, because if I immediately do a GetCurrentCulture after setting, I still get the old default one.
  2. When I run in PIE, nothing seems to change.
  3. When I run ‘Standalone Game’, text localization kicks in using correct culture, but GetCurrentCulture still returns the old default one.

So it seems that even though SetCurrentCulture does not seem to have a lasting effect, it still manages to kick in the localization system when running in Standalone Game.

I also tried adding

in DefaultGame.ini, but that doesn’t seem to have any effect in any of the scenarios above.

Could anyone help me with this? It all seems very undocumented and vague.


Hi Kjartan,

SetCurrentCulture should persist once set, however for it to work in a standalone game you need to have packaged the correct internationalization data for the cultures you want to support. You can check this in your Project Settings (Edit → Project Settings → Packaging → (advanced under Packaging section) → Internationalization Support), and if you want to support French, you’ll need that set to at least include EFIGS. Should this already be the case, you’re going to want to take a look at FICUInternationalization::SetCurrentCulture to make sure that; a) the culture change is actually working correctly, and b) that nothing is setting the culture back again afterwards.

With regard to setting the culture via a config file, that should work, however it needs to be in DefaultEngine.ini rather than DefaultGame.ini. You can also override it with -culture={culture} as a commandline argument, or in non-shipping builds by issuing the culture={culture} command from the debug console. You can find this logic in EndInitTextLocalization.

With regard to the game localization not loading in PIE, that is deliberate. We don’t currently load any non-native game texts in an editor build as it may cause authoring issues should someone accidentally save out a package with those translations set as the source text, however this restriction doesn’t apply when running the editor with -game.


I am wondering how I can move this forward. I can send you a very simple project that replicates the strange behavior that I am seeing with asset localization.

Thanks for your input. I got the SetCurrentCulture function to work. I also moved to EFIGS configuration. When I now play standalone game I can toggle culture correctly, and localized text changes accordingly.

I also tried localizing assets using the L10N folder (I am running 4.11.2 so I just created it manually in explorer, as the Editor didn’t allow me to create it in Editor). I tried having a localized version of a texture I was using but it doesn’t seem to pick it up correctly. so the surface ended up without any material. I then tried to localize the material rather than the texture and it also resulted in uncorrect behavior (I reload the level after having changed the culture). So there is clearly something happening, but I am not getting my localized texture to show up.

I also tried the same thing with an audio asset, but in that case it didn’t seem to work at all, i.e. the default audio asset was always used.

I know that 4.12 added some UI support for the L10N localized assets system, but isn’t it supposed to work also in 4.11?

Is there some specific way that assets needs to be copied in the L10N folder to work besides mirroring the content folder paths?

It is picking up the folder correctly, because if I remove it or rename it randomly, the asset defaults to the default culture. It is just not picking it up correctly (for textures and/or materials) and not at all with audio files.

There is localized package support in 4.11, but it definitely has some major issues compared to the version in 4.12. The main issue is that it doesn’t use the culture hierarchy at all, so if you set your culture to “fr-FR” and your assets are localized for “fr”, it won’t consider those assets to be suitable and will load the default instead… that said, it should always load something, so it’s strange you’re seeing missing assets.

With regard to making them work, you shouldn’t need to do anything other than create an asset in the correct place, so if your non-localized asset is /Game/MyFolder/MyAsset, you’d create /Game/L10N/fr/MyFolder/MyAsset for French.

If you want to take a look at where this redirection happens, you can open up PackageName.cpp and search for ShouldGetLocalizedPackage. This was all stripped out again for 4.12 as the way we deal with localized packages now is completely different in order to solve the issues I mentioned before.

I also tried breaking into the functions that have ShouldGetLocalizedPackage in them but they don’t seem to be called when I dynamically change culture.

I’ve tested the project you sent me and I’ve managed to find the issue. The good news is that it was already fixed by the changes made for 4.12, and the fix for 4.11 is small (also shelved in CL# 3101518).

In FAsyncPackage::CreateLinker, the following:

FString PackageFileName;
if (Desc.NameToLoad == NAME_None || 
	(!GetConvertedDynamicPackageNameToTypeName().Contains(Desc.Name) &&
	 !FPackageName::DoesPackageExist(Desc.NameToLoad.ToString(), Desc.Guid.IsValid() ? &Desc.Guid : nullptr, &PackageFileName)))
	UE_LOG(LogStreaming, Error, TEXT("Couldn't find file for package %s requested by async loading code."), *Desc.Name.ToString());
	bLoadHasFailed = true;
	return EAsyncPackageState::TimeOut;

Needs to be replaced with this:

FString NativePackageFileName;
FString LocalizedPackageFileName;
if (Desc.NameToLoad == NAME_None ||
	(!GetConvertedDynamicPackageNameToTypeName().Contains(Desc.Name) &&
	 !FPackageName::DoesPackageExistWithLocalization(Desc.NameToLoad.ToString(), Desc.Guid.IsValid() ? &Desc.Guid : nullptr, &NativePackageFileName, &LocalizedPackageFileName)))
	UE_LOG(LogStreaming, Error, TEXT("Couldn't find file for package %s requested by async loading code."), *Desc.Name.ToString());
	bLoadHasFailed = true;
	return EAsyncPackageState::TimeOut;

// If we are the editor, we must have a native package. If we are the game, we must have a localized package or a native package.
FString PackageFileName;
if (GIsEditor)
	PackageFileName = NativePackageFileName;
	PackageFileName = (LocalizedPackageFileName.Len() > 0) ? LocalizedPackageFileName : NativePackageFileName;

Based on this, and the lack of Content Browser integration, it seems that the released version of 4.11 didn’t quite have full localized package support. I don’t know whether you’re planning to upgrade past 4.11, but I’d recommend at least 4.12 for fully functional localized package support, as although the above fix will solve your redirection issue, it doesn’t do anything to solve the other culture hierarchy issues I mentioned before.

As an aside, the GetLocalizedSound function in your LocalizedAudio blueprint is quite odd. I appreciate it may have just been you testing, but you shouldn’t need to branch on a culture like that; you’d just use a fixed asset name and then use package localization to handle the redirection.

We don’t yet support reloading assets when the culture is changed on-the-fly, so you’ll be stuck with the old asset until it gets unloaded and reloaded with the new culture active.

Have you only tested with dynamic culture changes, or have you also tested with a culture overload during initialization (eg, setting it in the config or passing -culture=)?

I have tried running with culture set in the ini file, and it does pick the right culture for the text, but results in the same erroneous asset for textures (and audio assets stuck in default culture) as I get when dynamically changing culture.

cool. just sent you a mail.

I did these source code changes (along with another to fix the hierarchical issue you mentioned) and it all works fine…in editor. When I run a packaged build it didn’t work. I made a non-pak build and saw that the L10N directory wasn’t picked up, so I added that directory as additional directory to cook. It does show up now, but audio is still not correctly redirected, even though it works when running standalone from editor.

Is there some additional packaging settings that I need to do such that the L10N redirection works in packaged builds?

It does look like the cooker changes to cook and package localised content wasn’t made in 4.11 either. This was since fixed, but your solution of adding the L10N folder to the additional asset directories to cook is fine for now.

I’ve tried to repro your audio issue using the sample project you gave me before, but everything seems to be working fine in both a cooked and packaged build. Are you able to repro the issue using that project?

Ok I found out you need to add the L10N directory to additional directories to cook, not copy, then it works for me. Thanks!.