Flutter internationalization - Dynamic strings
Asked Answered
C

4

29

I'm translating my app to spanish using the intl package.

locales.dart

class AppLocale {
...
   String get folder => Intl.message("Folder", name: 'folder');
...
}

messages_es.dart

class MessageLookup extends MessageLookupByLibrary {
      get localeName => 'es';

      final messages = _notInlinedMessages(_notInlinedMessages);
      static _notInlinedMessages(_) => <String, Function> {
            "folder": MessageLookupByLibrary.simpleMessage("Carpeta"),
      };
}

I call it using the following code:

AppLocale.of(context).folder

It is working fine.

However, I need to create "dynamic" strings. For example:

"Hi, {$name}"

Then I would call this string, passing this "name" as parameter, or something like this. It would be translate as "Hola, {$name}" in spanish.

It is possible using this intl package?

Courtesan answered 11/9, 2018 at 14:17 Comment(0)
E
15

The README of the intl package explains that example https://github.com/dart-lang/intl

The purpose of wrapping the message in a function is to allow it to have parameters which can be used in the result. The message string is allowed to use a restricted form of Dart string interpolation, where only the function's parameters can be used, and only in simple expressions. Local variables cannot be used, and neither can expressions with curly braces. Only the message string can have interpolation. The name, desc, args, and examples must be literals and not contain interpolations. Only the args parameter can refer to variables, and it should list exactly the function parameters. If you are passing numbers or dates and you want them formatted, you must do the formatting outside the function and pass the formatted string into the message.

greetingMessage(name) => Intl.message(
      "Hello $name!",
      name: "greetingMessage",
      args: [name],
      desc: "Greet the user as they first open the application",
      examples: const {'name': "Emily"});
  print(greetingMessage('Dan'));

Below this section there are more complex examples explained that also deal with plurals and genders.

Engvall answered 11/9, 2018 at 14:21 Comment(0)
O
64

If you follow the official internationalization docs and specify all your phrases in .arb files, you can do parameters like this:

{
    "greeting": "Hi, {name}!",
    "@greeting": {
        "description": "Greet the user by their name.",
        "placeholders": {
            "name": {
                "type": "String",
                "example": "Jane"
            }
        }
    }
}

When you compile your code, a function like the following will be generated for you, complete with a nice docbloc to power your IDE tooltips:

  /// Greet the user by their name.
  ///
  /// In en, this message translates to:
  /// **'Hi, {name}!'**
  String greeting(String name);

So you can just use it like this:

Text(AppLocalizations.of(context)!.greeting("Koos"))
Omor answered 29/7, 2021 at 14:2 Comment(7)
It was also interesting to me that the placeholders block needs to be present only in one arb file (in my case it was intl_en.arb).Boreal
How to add these values to other localization files, let us say app_es.arb?Jacobi
@HusamAlhwadi you can add them the same way, but typically it only makes sense to add them in the primary language file that will be used to translate the other languages from as a guide for the translator who should be familiar with the primary language.Omor
@JannieTheunissen thanks for your reply, I already have added it to app_en.arb file but this is not enough (as per my knowledge) , Each key value in placeholders need to be added to other arb files (in my case I have 4 different languages), App is running and doesn't give any error but no translation is done , can you please elborate more how we can add {name} values to other arb files?Jacobi
@HusamAlhwadi The parameters you pass in (in this case {name}) are dynamic values that are only available at run time and so they will never be translated.Omor
@JannieTheunissen, I thought this approach can help me to pass different strings values which app fetch them fusing API's to AppLocalizations.of(context)!.{Variable}, but unfortunately this not works since AppLocalization class looks to varaible name instead of its return value and thats why i find my self need to hardcode all scenarios and pass them to AppLocalizations.of(context)!., which i dont think is practical option when you have so many options!! Not sure if you have any alternative solutions where we can pass dynamic string to AppLocalizations.of(context)! ?Jacobi
I had to run flutter clean and flutter pub get for changes to take effectPitapat
E
15

The README of the intl package explains that example https://github.com/dart-lang/intl

The purpose of wrapping the message in a function is to allow it to have parameters which can be used in the result. The message string is allowed to use a restricted form of Dart string interpolation, where only the function's parameters can be used, and only in simple expressions. Local variables cannot be used, and neither can expressions with curly braces. Only the message string can have interpolation. The name, desc, args, and examples must be literals and not contain interpolations. Only the args parameter can refer to variables, and it should list exactly the function parameters. If you are passing numbers or dates and you want them formatted, you must do the formatting outside the function and pass the formatted string into the message.

greetingMessage(name) => Intl.message(
      "Hello $name!",
      name: "greetingMessage",
      args: [name],
      desc: "Greet the user as they first open the application",
      examples: const {'name': "Emily"});
  print(greetingMessage('Dan'));

Below this section there are more complex examples explained that also deal with plurals and genders.

Engvall answered 11/9, 2018 at 14:21 Comment(0)
C
4

In order to use placeholders in your translations you need to:

  • Add that placeholder as a getter argument
  • Mention that placeholder with $ prefix in the translation (ie $name)
  • Add the placeholder in args list when calling Intl.message

So a full example looks like this:

greetingMessage(name) => Intl.message(
  "Hello $name!",
  name: 'greetingMessage',
  args: [name]
);
Ciprian answered 25/12, 2019 at 19:20 Comment(0)
E
0

Follow this link. Once you have finished all steps, do the below changes in your .arb file:

{  
  "title": "App Title",
  "helloWorld": "{name1} and {name2} must be different",
  "@helloWorld": {
        "description": "The conventional newborn programmer greeting",
        "placeholders": {
                    "name1": {
                        "type": "String"
                    },
                    "name2": {
                        "type": "String"
                    }
                }
      },
  "appInfo":  "Information about your app",
 }
Excessive answered 18/4, 2022 at 6:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.