Flutter internationalization - Dynamic strings - internationalization

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?

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"))

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.

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]
);

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",
}

Related

Golang invopop jsonschema usage of if/then/else

I'm using the library invopop/jsonschema for generating our json-schema based on go struct tags. But I struggle on how to use the if/then/else attributes.
I was doing something like this
type Boulou struct {
Name string `json:"name" jsonschema:"required,minLength=1,description=unique name"`
Transformers []TransformerConfig `json:"transformers" jsonschema:"title=transformers,if=properties.kind.const=convert_swim,then=required[0]=convert_swim_config"`
}
But does not seems to work (i made a go playground if you would like to play with).
Thanks in advance !
Resources:
json-schema spec for conditions: https://json-schema.org/understanding-json-schema/reference/conditionals.html
These complex use-cases aren't supported all that well using Go tags in invopop/jsonschema. Anything that breaks out of regular use-cases I'd recommend implementing the JSONSchema() method so you can define the object manually. Following your example:
type Boulou struct {
Name string `json:"name"`
Transformers []TransformerConfig `json:"transformers"`
}
func (Boulou) JSONSchema() *jsonschema.Schema {
props = orderedmap.New()
props.Set("name", &jsonschema.Schema{
Type: "string",
Title: "Name",
})
props.Set("transformers", &jsonschema.Schema{
Type: "array",
Title: "Transformers",
Items: &jsonschema.Schema{
Ref: ".....",
If: "properties.kind.const=convert_swim",
Then: "required[0]=convert_swim_config",
},
})
return &jsonschema.Schema{
Type: "object",
Title: "Boulou",
Properties: props,
}
}
I haven't tested this directly, but I'm sure you get the idea. You'll need to figure out what the Ref for your TransformerConfig is manually.
Update: there is now a new PR #52 which once launched, should make this much easier to do!

Get complete GraphQL response using POST without specify field name in request [duplicate]

Assume you have a GraphQL type and it includes many fields.
How to query all the fields without writing down a long query that includes the names of all the fields?
For example, If I have these fields :
public function fields()
{
return [
'id' => [
'type' => Type::nonNull(Type::string()),
'description' => 'The id of the user'
],
'username' => [
'type' => Type::string(),
'description' => 'The email of user'
],
'count' => [
'type' => Type::int(),
'description' => 'login count for the user'
]
];
}
To query all the fields usually the query is something like this:
FetchUsers{users(id:"2"){id,username,count}}
But I want a way to have the same results without writing all the fields, something like this:
FetchUsers{users(id:"2"){*}}
//or
FetchUsers{users(id:"2")}
Is there a way to do this in GraphQL ??
I'm using Folkloreatelier/laravel-graphql library.
Unfortunately what you'd like to do is not possible. GraphQL requires you to be explicit about specifying which fields you would like returned from your query.
Yes, you can do this using introspection. Make a GraphQL query like (for type UserType)
{
__type(name:"UserType") {
fields {
name
description
}
}
}
and you'll get a response like (actual field names will depend on your actual schema/type definition)
{
"data": {
"__type": {
"fields": [
{
"name": "id",
"description": ""
},
{
"name": "username",
"description": "Required. 150 characters or fewer. Letters, digits, and #/./+/-/_ only."
},
{
"name": "firstName",
"description": ""
},
{
"name": "lastName",
"description": ""
},
{
"name": "email",
"description": ""
},
( etc. etc. ...)
]
}
}
}
You can then read this list of fields in your client and dynamically build a second GraphQL query to get the values of these fields.
This relies on you knowing the name of the type that you want to get the fields for -- if you don't know the type, you could get all the types and fields together using introspection like
{
__schema {
types {
name
fields {
name
description
}
}
}
}
NOTE: This is the over-the-wire GraphQL data -- you're on your own to figure out how to read and write with your actual client. Your GraphQL javascript library may already employ introspection in some capacity. For example, the apollo codegen command uses introspection to generate types.
2022 Update
Since this answer was originally written, it is now a recommended security practice to TURN OFF introspection in production. Reference: Why you should disable GraphQL introspection in production.
For an environment where introspection is off in production, you could use it in development as a way to assist in creating a static query that was used in production; you wouldn't actually be able to create a query dynamically in production.
I guess the only way to do this is by utilizing reusable fragments:
fragment UserFragment on Users {
id
username
count
}
FetchUsers {
users(id: "2") {
...UserFragment
}
}
I faced this same issue when I needed to load location data that I had serialized into the database from the google places API. Generally I would want the whole thing so it works with maps but I didn't want to have to specify all of the fields every time.
I was working in Ruby so I can't give you the PHP implementation but the principle should be the same.
I defined a custom scalar type called JSON which just returns a literal JSON object.
The ruby implementation was like so (using graphql-ruby)
module Graph
module Types
JsonType = GraphQL::ScalarType.define do
name "JSON"
coerce_input -> (x) { x }
coerce_result -> (x) { x }
end
end
end
Then I used it for our objects like so
field :location, Types::JsonType
I would use this very sparingly though, using it only where you know you always need the whole JSON object (as I did in my case). Otherwise it is defeating the object of GraphQL more generally speaking.
GraphQL query format was designed in order to allow:
Both query and result shape be exactly the same.
The server knows exactly the requested fields, thus the client downloads only essential data.
However, according to GraphQL documentation, you may create fragments in order to make selection sets more reusable:
# Only most used selection properties
fragment UserDetails on User {
id,
username
}
Then you could query all user details by:
FetchUsers {
users() {
...UserDetails
}
}
You can also add additional fields alongside your fragment:
FetchUserById($id: ID!) {
users(id: $id) {
...UserDetails
count
}
}
Package graphql-type-json supports custom-scalars type JSON.
Use it can show all the field of your json objects.
Here is the link of the example in ApolloGraphql Server.
https://www.apollographql.com/docs/apollo-server/schema/scalars-enums/#custom-scalars

Do a full query simply in GraphQL [duplicate]

Assume you have a GraphQL type and it includes many fields.
How to query all the fields without writing down a long query that includes the names of all the fields?
For example, If I have these fields :
public function fields()
{
return [
'id' => [
'type' => Type::nonNull(Type::string()),
'description' => 'The id of the user'
],
'username' => [
'type' => Type::string(),
'description' => 'The email of user'
],
'count' => [
'type' => Type::int(),
'description' => 'login count for the user'
]
];
}
To query all the fields usually the query is something like this:
FetchUsers{users(id:"2"){id,username,count}}
But I want a way to have the same results without writing all the fields, something like this:
FetchUsers{users(id:"2"){*}}
//or
FetchUsers{users(id:"2")}
Is there a way to do this in GraphQL ??
I'm using Folkloreatelier/laravel-graphql library.
Unfortunately what you'd like to do is not possible. GraphQL requires you to be explicit about specifying which fields you would like returned from your query.
Yes, you can do this using introspection. Make a GraphQL query like (for type UserType)
{
__type(name:"UserType") {
fields {
name
description
}
}
}
and you'll get a response like (actual field names will depend on your actual schema/type definition)
{
"data": {
"__type": {
"fields": [
{
"name": "id",
"description": ""
},
{
"name": "username",
"description": "Required. 150 characters or fewer. Letters, digits, and #/./+/-/_ only."
},
{
"name": "firstName",
"description": ""
},
{
"name": "lastName",
"description": ""
},
{
"name": "email",
"description": ""
},
( etc. etc. ...)
]
}
}
}
You can then read this list of fields in your client and dynamically build a second GraphQL query to get the values of these fields.
This relies on you knowing the name of the type that you want to get the fields for -- if you don't know the type, you could get all the types and fields together using introspection like
{
__schema {
types {
name
fields {
name
description
}
}
}
}
NOTE: This is the over-the-wire GraphQL data -- you're on your own to figure out how to read and write with your actual client. Your GraphQL javascript library may already employ introspection in some capacity. For example, the apollo codegen command uses introspection to generate types.
2022 Update
Since this answer was originally written, it is now a recommended security practice to TURN OFF introspection in production. Reference: Why you should disable GraphQL introspection in production.
For an environment where introspection is off in production, you could use it in development as a way to assist in creating a static query that was used in production; you wouldn't actually be able to create a query dynamically in production.
I guess the only way to do this is by utilizing reusable fragments:
fragment UserFragment on Users {
id
username
count
}
FetchUsers {
users(id: "2") {
...UserFragment
}
}
I faced this same issue when I needed to load location data that I had serialized into the database from the google places API. Generally I would want the whole thing so it works with maps but I didn't want to have to specify all of the fields every time.
I was working in Ruby so I can't give you the PHP implementation but the principle should be the same.
I defined a custom scalar type called JSON which just returns a literal JSON object.
The ruby implementation was like so (using graphql-ruby)
module Graph
module Types
JsonType = GraphQL::ScalarType.define do
name "JSON"
coerce_input -> (x) { x }
coerce_result -> (x) { x }
end
end
end
Then I used it for our objects like so
field :location, Types::JsonType
I would use this very sparingly though, using it only where you know you always need the whole JSON object (as I did in my case). Otherwise it is defeating the object of GraphQL more generally speaking.
GraphQL query format was designed in order to allow:
Both query and result shape be exactly the same.
The server knows exactly the requested fields, thus the client downloads only essential data.
However, according to GraphQL documentation, you may create fragments in order to make selection sets more reusable:
# Only most used selection properties
fragment UserDetails on User {
id,
username
}
Then you could query all user details by:
FetchUsers {
users() {
...UserDetails
}
}
You can also add additional fields alongside your fragment:
FetchUserById($id: ID!) {
users(id: $id) {
...UserDetails
count
}
}
Package graphql-type-json supports custom-scalars type JSON.
Use it can show all the field of your json objects.
Here is the link of the example in ApolloGraphql Server.
https://www.apollographql.com/docs/apollo-server/schema/scalars-enums/#custom-scalars

How to pass GraphQLEnumType in mutation as a string value

I have following GraphQLEnumType
const PackagingUnitType = new GraphQLEnumType({
name: 'PackagingUnit',
description: '',
values: {
Carton: { value: 'Carton' },
Stack: { value: 'Stack' },
},
});
On a mutation query if i pass PackagingUnit value as Carton (without quotes) it works. But If i pass as string 'Carton' it throws following error
In field "packagingUnit": Expected type "PackagingUnit", found "Carton"
Is there a way to pass the enum as a string from client side?
EDIT:
I have a form in my front end, where i collect the PackagingUnit type from user along with other fields. PackagingUnit type is represented as a string in front end (not the graphQL Enum type), Since i am not using Apollo Client or Relay, i had to construct the graphQL query string by myself.
Right now i am collecting the form data as JSON and then do JSON.stringify() and then remove the double Quotes on properties to get the final graphQL compatible query.
eg. my form has two fields packagingUnitType (An GraphQLEnumType) and noOfUnits (An GraphQLFloat)
my json structure is
{
packagingUnitType: "Carton",
noOfUnits: 10
}
convert this to string using JSON.stringify()
'{"packagingUnitType":"Carton","noOfUnits":10}'
And then remove the doubleQuotes on properties
{packagingUnitType:"Carton",noOfUnits:10}
Now this can be passed to the graphQL server like
newStackMutation(input: {packagingUnitType:"Carton", noOfUnits:10}) {
...
}
This works only if the enum value does not have any quotes. like below
newStackMutation(input: {packagingUnitType:Carton, noOfUnits:10}) {
...
}
Thanks
GraphQL queries can accept variables. This will be easier for you, as you will not have to do some tricky string-concatenation.
I suppose you use GraphQLHttp - or similar. To send your variables along the query, send a JSON body with a query key and a variables key:
// JSON body
{
"query": "query MyQuery { ... }",
"variables": {
"variable1": ...,
}
}
The query syntax is:
query MyMutation($input: NewStackMutationInput) {
newStackMutation(input: $input) {
...
}
}
And then, you can pass your variable as:
{
"input": {
"packagingUnitType": "Carton",
"noOfUnits": 10
}
}
GraphQL will understand packagingUnitType is an Enum type and will do the conversion for you.

CKEditor - Use Advanced Content Filter rule to specify values

It seems that some plugins of CKEditor specify values of properties. For example, the left-to-right plugin has the following rule:
{
"styles":null,
"requiredStyles":null,
"classes":null,
"requiredClasses":null,
"attributes":{
"dir":"ltr"
},
"requiredAttributes":{
"dir":true
},
"elements":{
"span":true
},
"featureName":"styles",
"propertiesOnly":false,
"match":null
},
How can I specify values with string format rules?
Something like span[!dir=ltr].
You can't. String format doesn't allow such definition. You can specify span[!dir] so all spans require dir attribute and nothing else. With object definition you can do more, e.g. use functions:
...
'ul, li: true,
'$0': {
match: function( el ) {
return el.name == 'b';
},
propertiesOnly: true,
attributes: 'dir'
}
'$1': {
...
Why do you persist to use string format? You can use objects and store it as JSON.

Resources