In general, I have never had big problems with localization and Xamarin Forms. Xamarin localization is straightforward to implement and it works.
But, on one of my latest projects, my app was targeting also Brazilian market. I had problems with iOS and Brazilian language (pt-BR or in Apple context pt_BR).
After a quick investigation, I found out that this bug was already reported and at the time of this writing is still open on GitHub: https://github.com/xamarin/Xamarin.Forms/issues/8728.
This issue had been open quite a while now, with no fix. I needed to dig-in and found some solution, fast, because my project deadlines were tight.
After research, I noticed that Xamarin.Forms NuGet package was the problem. First, I noticed that inside extracted NuGet package only Brazilian localization code (pt-br) was lowercase for Xamarin.iOS. Furthermore, some developers reported that this feature worked in versions prior Xamarin Forms 4.0.
After further investigation, I also discovered that change to lowercase pt-br happened between xamarin.forms.18.104.22.168467-pre7 and xamarin.forms.22.214.171.1244370-pre8 release.
Just to confirm my speculation, I simply renamed this folder to uppercase (to be precise, second part of localization code – regional part) in my NuGet cache, cleaned my project, rebuilt everything and all worked as expected. So indeed, the problem was in NuGet being packed wrong.
As said, for the first test, I manually renamed problematic folder in NuGet cache. I changed folder name from pt-br to pt-BR, cleaned solution & rebuilt. And amazingly, everything worked just fine. My iOS phone recognized Brazilian localization, my localization service on my iOS device picked correct localization resource. Hooray.
As always, there are several solutions to the problem. Some solutions are
almost perfect, other just address the problem and fix the problem with minimum effort and problems.
As every pragmatic developer under deadlines, I needed quick solution for this.
Of course, the best solution would be to fix the Xamarin.Forms NuGet packing. I quickly checked Xamarin Forms source code, but there everything looked ok. File .create-stubs.bat which creates NuGet build structure is not the official script which creates official Xamarin.Forms NuGet (first line in this script file). So, I stop bothering to go with ideal solution. Saying that, my other option was to “hack” existing packages and adopt my build process.
This solution is described in the next section.
The dirty path solution
My next idea was to rename folder from pt-br to pt-BR at build time. The most natural way for this was to use MSBuild and insert new MSBuild target just before NuGet restore target.
To summarize my idea: just before my Xamarin Forms iOS project restores NuGet packages and copy references to build folder, I am going to enforce MSBuild to rename problematic pt-br folder inside NuGet cache.
Just one additional note here: there are two way of referencing NuGet packages in the .NET projects: old-way with nuget.config and recommended-way with PackageReference. First approach stores NuGet packages in some local folder – normally packages, the latter approach use global NuGet cache folder to store references. To have agnostic way how to reference NuGet cache folder I used MSBuild $(NugetPackageRoot) variable.
Next code shows my MSBuild target which renames pt-br to pt-BR in Xamairn.Forms NuGet my NuGet cache:
<Target Name="UpdateBrazilianLanguageXfBug" BeforeTargets="_CopyFilesMarkedCopyLocal">
<Message Text="Start Executing updating Brazilian language on iOS NuGet package" />
<!-- props -->
<!-- checks -->
<Error Text="Xamarin Forms version $(XamarinVersion) not found in NuGet cache. Path search: $(XamarinFormsNuGetIosPath). Exiting build."
<!-- copy to temp folder -->
<Message Text="Moving Brazilian-related files to temp..." />
<FilesToMove Include="$(XamarinFormsNuGetIosPath)\pt-br\*.*" />
<Move SourceFiles="@(FilesToMove)" DestinationFolder="$(XamarinFormsNuGetIosPath)\pt-BR-tmp" />
<!-- remove initial folder -->
<Message Text="Removing original pt-br folder..." />
<RemoveDir Directories="$(XamarinFormsNuGetIosPath)\pt-br" />
<!-- copy from temp to final folder -->
<Message Text="Moving pt-br files to final destination (pt-BR)..." />
<FinalDestinationFilesMove Include="$(XamarinFormsNuGetIosPath)\pt-BR-tmp\*.*" />
<Move SourceFiles="@(FinalDestinationFilesMove)" DestinationFolder="$(XamarinFormsNuGetIosPath)\pt-BR" />
<!-- cleaning -->
<Message Text="Cleaning temp folder..." />
<RemoveDir Directories="$(XamarinFormsNuGetIosPath)\pt-BR-tmp" />
Ok, ok, I know! It’s ugly, It’s not perfect, but it does the job. Of course, I could do better ;D.
When I pushed this on my git repository, executed my Azure DevOps build pipeline, pushed output artifacts to my testing Visual Studio App Center channel, everything worked as expected. Brazilian worked on my iOS app, all good.
For now, I am good with this solution. Until this is not fixed in official Xamarin Forms and my my app will be ready to upgrade (I am waiting also on some other bug fixes 😀 ) I am just fine with my walkaround solution.
Xamarin Forms iOS (up until 4.6 version) has problems with Brazilian language. The issue is already on Xamarin team to be addressed. But until then, I urgently needed some quick solution. In this blog post, I presented one quick and dirty solution, but it works for me and for now I am all right with it.
If some have similar problems, feel free to use my hack!
Until the next reading, happy coding!