How to manage app localization ?

Hi,

What are the guidelines to manage apps localization using Xamarin.Forms ?
Each platform has its own localization process (RESX on WP, XML on Android, etc.) so how to do that localization part on the main Xamarin.Forms project of a solution?

Thanks!

«1

Posts

  • ThomasLEBRUNThomasLEBRUN FRMember

    Nobody is doing localization for now ? :)

  • rmarinhormarinho PTMember, Insider, Beta Xamurai
    edited June 2014

    sorry my post was wrong thought you were talking about Gps localization :p

  • CraigDunnCraigDunn USXamarin Team Xamurai

    We haven't got anything specific for Xamarin.Forms localization right now, but check out this code...

    https://gist.github.com/conceptdev/47986fd40c2f9a8b390a

    ...if you want to try translating strings in Xamarin.Forms Xaml. I used Vernacular to manage the localization process.

  • FabioCozzolinoFabioCozzolino ITBeta, University ✭✭✭

    Nice!

  • ThomasLEBRUNThomasLEBRUN FRMember

    I'll check that, thanks !

  • PooranPrasadRajannaPooranPrasadRajanna INMember ✭✭
    edited June 2014

    @CraigDunn‌ Can you please share steps on how to go about getting Vernacular working.

  • StephaneDelcroixStephaneDelcroix USInsider, Beta ✭✭✭✭

    I merged a patch to vernacular yesterday allowing it to work with X.F. docs follows.

  • DiogoDiogo USMember

    Hi @StephaneDelcroix‌, there is any advance in that documentation to work with Vernacular and Xamarin Forms?

  • DirkWeltzDirkWeltz DEMember ✭✭✭

    I'm interested in this documatation too.

  • ChrisMillerChrisMiller USBeta, Developer Group Leader ✭✭

    Are there any plans for Xamarin to provide a translation extension for X.Forms that works directly with the native resource file formats?

  • CraigDunnCraigDunn USXamarin Team Xamurai
    edited July 2014

    @anotherlab‌ Vernacular by rdio does just that (uses native storage but exposes a nice C# API). The gist I posted earlier shows how to expose the catalog Vernacular creates to Xaml using a custom markup extension. Vernacular does work with Xamarin.Forms though, which is a great start.

    At some point we'd love to formalize & document how this works - it is in the queue but there is a lot to do!

  • ChrisMillerChrisMiller USBeta, Developer Group Leader ✭✭

    @CraigDunn, I looked at your gist and I saw how it works with Vernacular's string formats, but if you are using a tool like MAT to manage your resource strings, you now need a mechanism for translating the RESX or XLIFF files to the Vernacular format. Are there any documentation or examples for Vernacular?

  • CraigDunnCraigDunn USXamarin Team Xamurai

    The Vernacular.Tool command line app provides a few conversions between common file formats. Vernacular uses a standard format - POT/PO - so it shouldn't be a big deal to convert.

    There's not much official documentation on Vernacular, though you will find examples on the web. It is open-source, so there is always the code to look at. It's a powerful tool that does a nice job with L10n problems like plurals, gender, ordinals, etc. so worthwhile understanding.

  • CraigDunnCraigDunn USXamarin Team Xamurai

    Update: here's a working Xamarin.Forms app using Vernacular for localization.

    Key points:

    • TranslateExtension enables the localization to occur in the Xaml.

    • If you build UI in C# you just need to use Catalog.GetString (someText) to populate user interface elements' Text properties. Vernacular also supports other methods like GetGenderString and GetPluralString.

    • All projects reference Vernacular.Catalog.XamarinForms assembly and the Android project additionally references Vernacular.Catalog.XamarinForms.Android

    • Android is configured in the MainActivity.cs with this line: Catalog.Implementation = new AndroidCatalog (this.Resources, typeof(TodoXaml.Resource.String) );

    • iOS is configured in AppDelegate.cs with this:

      Catalog.Implementation = new ResourceCatalog { GetResourceById = id => {
              var resource =
                  NSBundle.MainBundle.LocalizedString(id, null);
              return resource == id ? null : resource;
          },
      };
      

    Check these slides and this MonkeySpace talk video by @AaronBockover‌ for info on Vernacular.

  • CraigDunnCraigDunn USXamarin Team Xamurai

    Update: here's a working Xamarin.Forms app using RESX for localization.

    Key points:

    Note that you could implement the Xaml TranslateExtension just as easily with the RESX method as you can with the Vernacular example.

  • MatF_DevolisMatF_Devolis USMember

    Hi Craig,

    I'm currently testing Xamarin.Forms and want to localize my app. I'm not using MVVMCross or something like this : only plain .Forms.
    I saw Vernacular, but for now, we don't want to rely/use other third party library other than Xamarin.

    I've followed your example to use the RESX as source for localized texts, but I've come to a problem: it works on Android (myabe on iOS, nothing to test with for now), but it does not works on WP... Your example does not works on WP either.

    I've also followed these instructions http://nnhiu.blogspot.fr/2014/07/resx-xamarin-forms.html (found here: http://forums.xamarin.com/discussion/19711/resx-localization-for-xamarin-forms )

    What I have:

    • 3 UI projects: Android, iOS, WP
    • 2 PCL projects: one with my UI logic, one with my business logic
    • my resource files (.resx, .fr.resx and .it.resx) are in the "UI logic" project, marked as Embeded Resource and Custom tool set to PublicResXFileCodeGenerator

    For what I see:

    • CultureInfo.CurrentCulture gives me the right culture, either on Android or WP, so no need to use the ILocale
    • using MyResources.Resource_Name (with a MyResources.resx file) works the same as creating a new MyResources(); (and setting the MyResources.Culture which is null to any existing culture)
    • whatever the CultureInfo (default is "en-US") I pass (CultureInfo.CurrentCulture, new CultureInfo("fr"), new CultureInfo("fr-FR")) to the ResourceManager.GetText() method, I always get the english translation!

    I've missed something?

    Does anyone have an idea explaining why it does not works?

  • CraigDunnCraigDunn USXamarin Team Xamurai

    Yeah sorry, I had not finished the WinPhone sample. It works now - the code is on github. It needed to have the ILocale interface supplied:

    [assembly: Dependency(typeof(Todo.WinPhone.Locale_WinPhone))]
    
    public class Locale_WinPhone : Todo.ILocale
    {
        public string GetCurrent()
        {
            var lang = System.Threading.Thread.CurrentThread.CurrentUICulture.Name;
            return lang;
        }
    }
    

    Screenshots attached show the app in Spanish and German.

  • MatF_DevolisMatF_Devolis USMember

    Yes, that's exactly what I did (in my app or in your sample), but the GetString() method of the ResourceManager always gives me the English translation... Even if y use GetString("label", new CultureInfo("fr")); whatever the language I pass to GetString, I get English!

    I test it on the WP emulator, set it's language to "French" and country to "France".

  • MatF_DevolisMatF_Devolis USMember

    Found the error: in supported languages on my WP project and WP manifest, I set "French (France)" instead of "French", because I have a resource file marked as ".fr.resx".

    Note that you can use code generation on your resx file and simply use Resx.AppResources.Something, it works on Android and WP (once I set the correct supported cultures) for me.

  • rmarinhormarinho PTMember, Insider, Beta Xamurai

    Wanted to give some feedback using Localization with Resx ..

    I think you don't need to pass the Culture when using the GetString method, the ResourceManager will only load 1 file of resources, i found this out when i was trying to force another culture and it wasn't working, at least on IOS
    It only worked when i changed the culture on the phone .. so it seems ResourceManager knows somehow already the correct culture to load ?!

  • rmarinhormarinho PTMember, Insider, Beta Xamurai

    well actually i was wrong, you still need to set it..

  • nodoidnodoid GBMember, Beta ✭✭✭

    I approached this issue in a different way as my problem required me to do a reverse look up (get the text on the screen, find the look up token originally used and then work with that).

    I have a created a small class to be used as an SQLite table like this

    public class Languages
        {
            [PrimaryKey]
            public string id { get; set; }
    
            public DateTime __updatedAt{ get; set; }
    
            public string key { get; set; }
    
            public string value { get; set; }
    
            public string locale { get; set; }
        }
    

    With the locale code, I can use the system with any language available through Google translator. The table is preloaded with the text used within the app, and accessed through by StringUtils.GetString (all it does is look up the token and return the localized string). The difference though is that if the text being requested isn't available, google supplies it and the app records it, so next time it's there. As it has a value parameter, the localized text can be read in from the screen and the key returned.

    While this may be slower, the system will always learn so if you miss something, as long as the native one is up to date, the translation can be obtained.

    I supposed to speed it up, at the start of the app running I could create/amend an XML file and read directly from that but then my issue with the reading back would not be readily available...

    The other nice thing about using SQLite for this operation is that it fits the Xam.Forms model and doesn't require additional code to generate the information ;)

  • LudovicThomasLudovicThomas USMember ✭✭

    If you have issued with the namespace that is incorrect on Xamarin Studio, with a runtime error message like "could not find any resources appropriate for the specified culture or the neutral culture".
    It's because Xamarin Studio default configuration is not using the folder structure to create Namespace.
    So if your "resx" files are in a folder like "AppResources" for example, your designer.cs file must be have the code System.Resources.ResourceManager("MyProject.AppResources.TextResources",...) and if your settings are incorrect, you will have System.Resources.ResourceManager("MyProject.TextResources",...).

    To change that, you can go to Settings > .Net naming Policies, and activate the folder structure. You will need to recreate your files again after that to ensure it's working fine.

    @CraigDunn I used your sample to get the locale working on iOS and Android, and it's fine. Nevertheless, you don't use the designer.cs file that is nice to get the key of the strings that are available from the resx main file. So instead of L10n.Localize("SaveButton", ""), you can use TextResources.SaveButton, which is verified at compilation time.
    In that case, you can initialized the TextResources culture, using the following code, and the class L10n is no more needed.

    // Initialize the locale only once var netLanguage = DependencyService.Get<ILocale>().GetCurrent(); TextResources.Culture = new CultureInfo (netLanguage);

  • CraigDunnCraigDunn USXamarin Team Xamurai

    @LudovicThomas‌ I did not know this!! That is a great tip :)

    To change that, you can go to Settings > .Net naming Policies, and activate the folder structure

  • LudovicThomasLudovicThomas USMember ✭✭

    @CraigDunn‌ Yes. In order to better follow the Visual Studio default configuration, perhaps it woulkd be good to activate it by default on Xamarin Studio?

  • KymPhillpottsKymPhillpotts AUMember, University ✭✭

    Late to the party, but just as another perspective I am using the Multilanguage App Toolkit along with a markup extension for Xaml (described above). Seems to be working fine.

  • JPBoroJPBoro PHMember ✭✭

    Using Resx and following TodoRessx sample file worked for me. But is there a way to change the languages of default texts in the device like the "Cancel" button of the Camera? It doesn't directly change when you change the phone language when you build an app in xamarin. Is there any way to access the .text property of those? Thanks.

  • JPBoroJPBoro PHMember ✭✭
    edited October 2014

    Fixed my problem in iOS by adding the folder for the languages needed ex: de.lproj with InfoPlist.strings

  • DirkWeltzDirkWeltz DEMember ✭✭✭

    Up to now I use Vernacular. Great tool. But now I have a problem, which I couldn't can solve.

    I want to localize the files for the preferences. For Android it's no problem. But the setting files from iOS aren't scanned and generated. How could I do this (it's best to use Vernacular)?

  • CraigDunnCraigDunn USXamarin Team Xamurai

    Not sure Vernacular already knows about Root.plist and Settings files, so I'll think you have to create your own Root.strings file (and others if you have sub-pages in settings).

    The best place to look is Apple's docs for Settings... scroll down to the localization part.

  • DanielLDanielL PLInsider ✭✭✭✭

    BTW: If you're testing this app (TodoL10nResx) on iOS simulator 8.1 it'll always return en locale. It's a known issue with iOS 8.1 simulators.

  • Chandan.3739Chandan.3739 USMember

    Hi, I am using Vernacular Tool in my Mobility Project supporting UK and US Locale. I am using below code to generate separate PO files for both the languages...

    if IOS

                Title = Vernacular.Catalog.GetString("EditProduct_IOS");
    

    else

                Title = Vernacular.Catalog.GetString("EditProduct_Andr");
    

    endif

    But when I use Vernacular Command to create .POT file, it is not able to Scan IOS Keys (e.g. EditProduct_IOS) as in Windows Machine, the #If IOS section not able to Scan as it is not Active.

    Please suggest.

    Thanks in Advance.

  • DirkWeltzDirkWeltz DEMember ✭✭✭

    You should scan both executables (iOS and Android) with one call to Vernacular. With this, you get all strings in one POT file. Later you could generate with the translated PO file the files for iOS or Android.

    I'm not at my computer, but if you have problems to do this, I could send you the command.

  • Chandan.3739Chandan.3739 USMember

    Thanks Charlenni for the reply.
    Actually I am having the commands. But my question was that with that command it was not able to scan IOS key in the "if" conditions.
    Anyhow I am able to scan both the key with out any changes. It is bit strange but it working now.

  • DirkWeltzDirkWeltz DEMember ✭✭✭

    That's the reason, why I scan both binaries with the following command (my apps name is WF.Player

        mono ../Vernacular/Vernacular.Tool/bin/Debug/Vernacular.exe
        --input=./WF.Player.Droid/Resources/values/Strings.xml
        --input=./WF.Player.Droid/Resources/values/array.xml
        --input=./WF.Player.Droid/bin/Debug/
        --input=./WF.Player.iOS/bin/iPhone/Debug/
        --input=./WF.Player.iOS/Settings.bundle/
        --source-root=./
        --output=./WF.Player.pot
        --generator=po 
    

    So you get the strings from if and from else.

  • BillFultonBillFulton AUMember ✭✭

    Further to @LudovicThomas' great post, I needed to check the following boxes in .NET Naming Policies to get it to work:

    1. Associate namespaces with directory names
    2. Use default namespace as root
    3. Hierarchical
    4. Use Visual Studio-style resource names
  • ChristophThielChristophThiel DEMember ✭✭

    @CraigDunn could you tell me how to implement Resx Localization in Shared Projects (not PCL)?

  • CraigDunnCraigDunn USXamarin Team Xamurai
    edited April 2015

    @ChristophThiel I just converted my sample to a Shared Project and put it on github -> TodoL10nShared. The Resx folder has the exact same files as the PCL version, with the same Build Action: Embedded Resource.

    Because shared projects don't actually have an assembly of their own, you have to make the iOS and Android (and Windows Phone) projects all have the exact same default namespace and assembly name.

    And finally I used the resource debug code

            // FOR DEBUGGING
            var assembly = typeof(L10n).GetTypeInfo().Assembly;
            foreach (var res in assembly.GetManifestResourceNames())
                System.Diagnostics.Debug.WriteLine("found resource: " + res);
    

    to figure out the resource name needed to changed slightly

            ResourceManager temp = new ResourceManager("Todo.AppResources", typeof(L10n).GetTypeInfo().Assembly);
            //ResourceManager temp = new ResourceManager("Todo.Resx.AppResources", typeof(L10n).GetTypeInfo().Assembly);
    

    Then it works the same as the PCL version:

  • n.kuznetsovn.kuznetsov USUniversity ✭✭

    Is there a Xamarin.Forms localization sample with Vernacular? The previous one got removed from here:
    https://github.com/conceptdev/xamarin-forms-samples/tree/master/TodoL10nVernacular

    Also, what's the proper way to switch app language on the fly? I.e. Phone's language is set to English but when I load the app the user might want to switch the language to Spanish (updating the UI with proper text).

  • StacyHenwoodStacyHenwood NZMember

    @n.kuznetsov said:
    Is there a Xamarin.Forms localization sample with Vernacular? The previous one got removed from here:
    https://github.com/conceptdev/xamarin-forms-samples/tree/master/TodoL10nVernacular

    Also, what's the proper way to switch app language on the fly? I.e. Phone's language is set to English but when I load the app the user might want to switch the language to Spanish (updating the UI with proper text).

    We have found that switching language on the fly is pretty horrid.

    While I have no experience using Vernacular, we use the .resx method described above.

    This is what you need to do:

    Firstly, Amend the culture of the phone:

    Using a dependency service, do something like this (WinPhone example):

    namespace AppName.WinPhone
    {
        public class Localize: ILocalize
        {
            public System.Globalization.CultureInfo GetCurrentCultureInfo()
            {
                return System.Threading.Thread.CurrentThread.CurrentUICulture;
            }
    
            public void SetUICulture(System.Globalization.CultureInfo culture)
            {
                // need to set both the ui culture and the culture so that the date selectors are correctly displayed
                System.Threading.Thread.CurrentThread.CurrentUICulture = culture;
                System.Threading.Thread.CurrentThread.CurrentCulture = culture;
            }
        }
    }
    

    This will make all newly instantiated pages display in the new culture, but wont affect any existing pages.

    Secondly, you need to update all the labels on all the pages that are already in the navigation stack. We ended up updating them all in the OnAppearing as it was easier than reverse navigating the entire stack...

    Good luck!

«1
Sign In or Register to comment.