Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Localization completely broken in IOS apps #17262

Closed
rolfbjarne opened this issue Jan 16, 2023 · 15 comments · Fixed by #18749
Closed

Localization completely broken in IOS apps #17262

rolfbjarne opened this issue Jan 16, 2023 · 15 comments · Fixed by #18749
Labels
bug If an issue is a bug or a pull request a bug fix
Milestone

Comments

@rolfbjarne
Copy link
Member

From @nevse on Mon, 16 Jan 2023 08:09:54 GMT

Description

It's impossible to add more than one additional language to an ios app.

Localization resx files are ignored for 2 and more additional languages when an ios app was built in release and run on device.

I created a simple app, source code available here. It contains three resx files (Resources/MyLocalization.resx, Resources/MyLocalization.de.resx, Resource/MyLocailzation.es.resx) which I use to obtain the localized string "MyString" in the following way:

        Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture = new CultureInfo("de");
        CultureStringLabel.Text = resourceManager.GetString("MyString");

It works fine when I build my app in release for an iphone simulator, but it doesn't work when I build it in release for a real device. It works only for one additional resx file.

Steps to Reproduce

  1. create an app from the default template: dotnet new maui
  2. add three buttons and create handlers for them
 <ScrollView>
      <VerticalStackLayout
          Spacing="25"
          Padding="30,0"
          VerticalOptions="Center">

          <Button Text="Set Eng Culture" Clicked="OnSetEngCulture" />
          <Button Text="Set De Culture" Clicked="OnSetDeCulture" />
          <Button Text="Set Es Culture" Clicked="OnSetEsCulture" />
          <Label x:Name="CultureStringLabel" />
      </VerticalStackLayout>
  </ScrollView>
private void OnSetEngCulture(object sender, EventArgs e)
{
      Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");
      CultureStringLabel.Text = resourceManager.GetString("MyString");
}
private void OnSetDeCulture(object sender, EventArgs e)
{
Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture = new CultureInfo("de");
      CultureStringLabel.Text = resourceManager.GetString("MyString");
  }
  private void OnSetEsCulture(object sender, EventArgs e)
  {
      Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture = new CultureInfo("es");
      CultureStringLabel.Text = resourceManager.GetString("MyString");
  }
  1. build the app in release and run on the real iphone device

Press each button - you should see different strings (string from eng, string from de, string from es).

Press "Set Eng Culture" to see "string from eng".
Press "Set De Culture" you should see the "string from de", but this string is "string from eng". It's wrong behaviour.
Press "Set Es Culture" to see "string from es".

Link to public reproduction project repository

https://github.com/nevse/maui-tests-iosreleaselocalization

Version with bug

7.0 (current)

Last version that worked well

Unknown/Other

Affected platforms

iOS

Affected platform versions

ios 16

Did you find any workaround?

No response

Relevant log output

No response

Copied from original issue dotnet/maui#12684

@rolfbjarne
Copy link
Member Author

From @jfversluis on Mon, 16 Jan 2023 13:02:44 GMT

Is this maybe related or the same as #16847?

@rolfbjarne ?

@rolfbjarne
Copy link
Member Author

From @rolfbjarne on Mon, 16 Jan 2023 13:52:28 GMT

Is this maybe related or the same as xamarin/xamarin-macios#16847?

@rolfbjarne ?

No, this is something different, and I can reproduce it.

Add this to the project file to work around it:

<PropertyGroup>
    <EnableAssemblyILStripping>false</EnableAssemblyILStripping>
</PropertyGroup>

@rolfbjarne rolfbjarne added this to the .NET 8 milestone Jan 16, 2023
@rolfbjarne rolfbjarne added the bug If an issue is a bug or a pull request a bug fix label Jan 16, 2023
@rolfbjarne rolfbjarne added this to Bugs in .NET 8 - Themes Jan 16, 2023
@rolfbjarne
Copy link
Member Author

Something like this might fix it: https://gist.github.com/rolfbjarne/f0d54b7db1f4c402b5605780c2be7452 (needs tests too).

@rolfbjarne
Copy link
Member Author

This might be a dup of #17009 / #14841.

@softlion
Copy link

@rolfbjarne Is this one related too dotnet/maui#13456 ?

@rolfbjarne
Copy link
Member Author

@softlion if the workaround above works, then it is.

@softlion
Copy link

softlion commented Feb 22, 2023

@softlion if the workaround above works, then it is.

The workaround does fix the issue with the translations.
TY !

, but breaks the grouped CollectionView (which is perfectly working without the workaround). The collectionview appears correctly the 1st time it is opened, but after a child page is opened and closed, the main page displays a broken collectionview with tons of funky group headers instead of a few group and a bunch of normal items. Very very curious breaking.

Without the workaround the collectionview has no such issue.

@rolfbjarne
Copy link
Member Author

@softlion if the workaround above works, then it is.

The workaround does fix the issue with the translations, but breaks the grouped CollectionView (which is perfectly working without the workaround). The collectionview appears correctly the 1st time it is opened, but after a child page is opened and closed, the main page displays a broken collectionview with tons of funky group headers instead of a few group and a bunch of normal items. Very very curious breaking.

Without the workaround the collectionview has no such issue.

That's indeed a very strange break, because the work around turns off an optimization only done in release builds (this means that the workaround is effectively in place for debug builds, which I assume are working fine?).

I'm inclined to believe something else is going on.

@softlion
Copy link

@softlion if the workaround above works, then it is.

The workaround does fix the issue with the translations, but breaks the grouped CollectionView (which is perfectly working without the workaround). The collectionview appears correctly the 1st time it is opened, but after a child page is opened and closed, the main page displays a broken collectionview with tons of funky group headers instead of a few group and a bunch of normal items. Very very curious breaking.
Without the workaround the collectionview has no such issue.

That's indeed a very strange break, because the work around turns off an optimization only done in release builds (this means that the workaround is effectively in place for debug builds, which I assume are working fine?).

I'm inclined to believe something else is going on.

You are right. It's something else.

@SoftArea-srl
Copy link

I have the same issue described by @nevse
The work around mentioned here does not work for me. Tested with real device iPhone 12 iOS 16.4.

@rolfbjarne
Copy link
Member Author

I have the same issue described by @nevse The work around mentioned here does not work for me. Tested with real device iPhone 12 iOS 16.4.

If the workaround doesn't work, something else is happening. Please file a new issue with a test project and we'll figure out what's going on.

@divil5000
Copy link

It is unbelievable that this isn't the highest-priority item on Microsoft's agenda right now. They are basically saying that localised apps cannot be built using the latest and greatest .net 6/7 for iOS. Localised apps includes all major international apps.

@softlion
Copy link

It is unbelievable that this isn't the highest-priority item on Microsoft's agenda right now. They are basically saying that localised apps cannot be built using the latest and greatest .net 6/7 for iOS. Localised apps includes all major international apps.

Fixed in .net8, not backported to the "legacy" .net7 because of fear of breaking changes.
I don't know who is in charge of those rules, but it is time to switch minds.

rolfbjarne added a commit to rolfbjarne/xamarin-macios that referenced this issue Aug 16, 2023
…#17262.

* Don't strip resource assemblies, there's no code in them to strip anyways.
* Use the relative path inside the app bundle when computing the intermediate
  location for stripped assemblies, so that if we were to find two identically
  named assemblies in different directories, they're handled correctly (by
  putting them in different intermediate locations, instead of overwriting
  eachother).

Fixes xamarin#17262.
rolfbjarne added a commit that referenced this issue Aug 17, 2023
…#18749)

* Don't strip resource assemblies, there's no code in them to strip anyways.
* Use the relative path inside the app bundle when computing the intermediate
  location for stripped assemblies, so that if we were to find two identically
  named assemblies in different directories, they're handled correctly (by
  putting them in different intermediate locations, instead of overwriting
  eachother).

Fixes #17262.
.NET 8 - Themes automation moved this from Bugs to Done Aug 17, 2023
vs-mobiletools-engineering-service2 pushed a commit to vs-mobiletools-engineering-service2/xamarin-macios that referenced this issue Aug 17, 2023
…#17262.

* Don't strip resource assemblies, there's no code in them to strip anyways.
* Use the relative path inside the app bundle when computing the intermediate
  location for stripped assemblies, so that if we were to find two identically
  named assemblies in different directories, they're handled correctly (by
  putting them in different intermediate locations, instead of overwriting
  eachother).

Fixes xamarin#17262.
rolfbjarne pushed a commit that referenced this issue Sep 13, 2023
…ies. Fixes #17262. (#18752)

* Don't strip resource assemblies, there's no code in them to strip anyways.
* Use the relative path inside the app bundle when computing the intermediate
  location for stripped assemblies, so that if we were to find two identically
  named assemblies in different directories, they're handled correctly (by
  putting them in different intermediate locations, instead of overwriting
  eachother).

Fixes #17262.

Backport of #18749
@marwalsch
Copy link

System.Globalization.CultureInfo.DefaultThreadCurrentCulture still doesn't work properly on .NET 8. Is this a separate issue?

@rolfbjarne
Copy link
Member Author

@marwalsch yes, that's a separate issue. Please file it in the dotnet/runtime repository.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug If an issue is a bug or a pull request a bug fix
Projects
No open projects
Development

Successfully merging a pull request may close this issue.

5 participants