Xamarin Forms: Brazilian iOS localization (pt-BR) not working


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:

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. and xamarin.forms. 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.

The solution

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:

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!

Leave a Reply

Your email address will not be published. Required fields are marked *

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.