void EndInitTextLocalization() { DECLARE_SCOPE_CYCLE_COUNTER(TEXT("EndInitTextLocalization"), STAT_EndInitTextLocalization, STATGROUP_LoadTime); const bool ShouldLoadEditor = WITH_EDITOR; const bool ShouldLoadGame = FApp::IsGame(); FInternationalization& I18N = FInternationalization::Get(); // Set culture according to configuration now that configs are available. #if ENABLE_LOC_TESTING if( FCommandLine::IsInitialized() && FParse::Param(FCommandLine::Get(), TEXT("LEET")) ) { I18N.SetCurrentCulture(TEXT("LEET")); } else #endif { FString RequestedCultureName; if (FParse::Value(FCommandLine::Get(), TEXT("CULTUREFORCOOKING="), RequestedCultureName)) { // Write the culture passed in if first install... if (FParse::Param(FCommandLine::Get(), TEXT("firstinstall"))) { GConfig->SetString(TEXT("Internationalization"), TEXT("Culture"), *RequestedCultureName, GEngineIni); } } else #if !UE_BUILD_SHIPPING // Use culture override specified on commandline. if (FParse::Value(FCommandLine::Get(), TEXT("CULTURE="), RequestedCultureName)) { //UE_LOG(LogInit, Log, TEXT("Overriding culture %s w/ command-line option".), *CultureName); } else #endif // !UE_BUILD_SHIPPING #if WITH_EDITOR // See if we've been provided a culture override in the editor if(GConfig->GetString( TEXT("Internationalization"), TEXT("Culture"), RequestedCultureName, GEditorGameAgnosticIni )) { //UE_LOG(LogInit, Log, TEXT("Overriding culture %s w/ editor configuration."), *CultureName); } else #endif // WITH_EDITOR // Use culture specified in engine configuration. if(GConfig->GetString( TEXT("Internationalization"), TEXT("Culture"), RequestedCultureName, GEngineIni )) { //UE_LOG(LogInit, Log, TEXT("Overriding culture %s w/ engine configuration."), *CultureName); } else { RequestedCultureName = I18N.GetDefaultCulture()->GetName(); } FString TargetCultureName = RequestedCultureName; { TArray<FString> LocalizationPaths; if(ShouldLoadEditor) { LocalizationPaths += FPaths::GetEditorLocalizationPaths(); } if(ShouldLoadGame) { LocalizationPaths += FPaths::GetGameLocalizationPaths(); } LocalizationPaths += FPaths::GetEngineLocalizationPaths(); // Validate the locale has data or fallback to one that does. TArray< FCultureRef > AvailableCultures; I18N.GetCulturesWithAvailableLocalization(LocalizationPaths, AvailableCultures, false); TArray<FString> PrioritizedParentCultureNames = I18N.GetCurrentCulture()->GetPrioritizedParentCultureNames(); FString ValidCultureName; for (const FString& CultureName : PrioritizedParentCultureNames) { FCulturePtr ValidCulture = I18N.GetCulture(CultureName); if (ValidCulture.IsValid() && AvailableCultures.Contains(ValidCulture.ToSharedRef())) { ValidCultureName = CultureName; break; } } if(!ValidCultureName.IsEmpty()) { if(RequestedCultureName != ValidCultureName) { // Make the user aware that the localization data belongs to a parent culture. UE_LOG(LogTextLocalizationManager, Log, TEXT("The requested culture ('%s') has no localization data; parent culture's ('%s') localization data will be used."), *RequestedCultureName, *ValidCultureName); } } else { // Fallback to English. UE_LOG(LogTextLocalizationManager, Log, TEXT("The requested culture ('%s') has no localization data; falling back to 'en' for localization and internationalization data."), *RequestedCultureName); TargetCultureName = "en"; } } I18N.SetCurrentCulture(TargetCultureName); } FTextLocalizationManager::Get().LoadResources(ShouldLoadEditor, ShouldLoadGame); FTextLocalizationManager::Get().bIsInitialized = true; }
void FInternationalization::GetCulturesWithAvailableLocalization(const TArray<FString>& InLocalizationPaths, TArray< FCultureRef >& OutAvailableCultures, const bool bIncludeDerivedCultures) { OutAvailableCultures.Reset(); TArray<FString> AllLocalizationFolders; IFileManager& FileManager = IFileManager::Get(); for(const auto& LocalizationPath : InLocalizationPaths) { /* Visitor class used to enumerate directories of culture */ class FCultureEnumeratorVistor : public IPlatformFile::FDirectoryVisitor { public: FCultureEnumeratorVistor( TArray<FString>& OutLocalizationFolders ) : LocalizationFolders(OutLocalizationFolders) { } virtual bool Visit(const TCHAR* FilenameOrDirectory, bool bIsDirectory) override { if(bIsDirectory) { // UE localization resource folders use "en-US" style while ICU uses "en_US" const FString LocalizationFolder = FPaths::GetCleanFilename(FilenameOrDirectory); const FString CanonicalName = FCulture::GetCanonicalName(LocalizationFolder); LocalizationFolders.AddUnique(CanonicalName); } return true; } /** Array to fill with the names of the UE localization folders available at the given path */ TArray<FString>& LocalizationFolders; }; FCultureEnumeratorVistor CultureEnumeratorVistor(AllLocalizationFolders); FileManager.IterateDirectory(*LocalizationPath, CultureEnumeratorVistor); } // Find any cultures that are a partial match for those we have translations for. if(bIncludeDerivedCultures) { TArray<FString> CultureNames; GetCultureNames(CultureNames); for(const FString& CultureName : CultureNames) { FCulturePtr Culture = GetCulture(CultureName); if (Culture.IsValid()) { TArray<FString> PrioritizedParentCultureNames = Culture->GetPrioritizedParentCultureNames(); for (const FString& PrioritizedParentCultureName : PrioritizedParentCultureNames) { if(AllLocalizationFolders.Contains(PrioritizedParentCultureName)) { OutAvailableCultures.AddUnique(Culture.ToSharedRef()); break; } } } } } // Find any cultures that are a complete match for those we have translations for. else { for(const FString& LocalizationFolder : AllLocalizationFolders) { FCulturePtr Culture = GetCulture(LocalizationFolder); if(Culture.IsValid()) { OutAvailableCultures.AddUnique(Culture.ToSharedRef()); } } } // Remove any cultures that were explicitly disabled OutAvailableCultures.RemoveAll([&](const FCultureRef& InCulture) -> bool { return Implementation->IsCultureDisabled(InCulture->GetName()); }); }