as

Settings
Sign out
Notifications
Alexa
Amazon Appstore
AWS
Documentation
Support
Contact Us
My Cases
Get Started
Design and Develop
Publish
Reference
Support

PUFF-J File Format

PUFF-J

PUFF-J is a JSON-based file format that uses UTF-8 character encoding for localized resources. A resource is a string that is submitted to linguists for translation.

This format enables you to provide your resources in the form of a map:

Resource objects can be decorated with a few other properties that either provide:

  • A description of the resource, including context in which the resource is used.
  • Additional information about how the resource is to be treated during its lifecycle - either during the translation process or at runtime when the resource is consumed.

The format is meant to be developer-facing, human-readable, and easy to edit. It's converted at build-time to an internal format that's easier to consume at runtime.

PUFF-J files must have the extension puff.json.

Resource Level Properties

Resource Identifier

Each resource being submitted for translation is identified with its unique identifier. This resource ID is provided as property name for the resource object. Although JSON allows this string to be virtually any Unicode character, PUFF-J restricts the character set to:

Copied to clipboard.

^(\\w[\\w-:]*)$`.

\w is equivalent to [a-zA-Z_0-9].

Resource Value

The resource value is the actual value that gets submitted to linguists for translation. It is normally specified in the value property and can be one of three types:

Optional Properties

A resource object can have additional properties. These properties provide further information about how the resource is to be processed in the translation process:

  • translate
    • A flag indicates whether the string should be translated. If omitted or its value is equal to true, the string should be translated. This means it will be included in the translation request.
  • note
    • Context notes are STRONGLY RECOMMENDED.
    • Each note has a 3,000-character limit.
    • Note represents developers' comments that give broader context for the string and placeholders as a help for translators.

    Example:

Copied to clipboard.

  {
    "dir" : "ltr",
    "resources": {
      "messageXml": {
        "note" : "{0} is the tracking number for customer order.",
        "value": "Your order number is {0}."
      },
      "messageXml2": {
        "translate": false,
        "note" : "This variable doesn't need to be translated by translators. It is localized by MessageFormat",
        "value": "{numItems,number,integer}"
      }
    }
  }

Resource Types

As mentioned, a resource value that is sent to linguists for translation can be one of three types:

This section gives more information about these types and best practices on how to represent them appropriately in the PUFF-J file.

Key Points

  • Use structured resource value types to relieve the pain of editing and reading complex MessageFormat plural and select patterns.
  • From ICU MessageFormat documentation:

    It is tempting to cover only a minimal part of a message string with a complex argument (for example, plural). However, this is difficult for translators for two reasons: 1. They might have trouble understanding how the sentence fragments in the argument sub-messages interact with the rest of the sentence, and 2. They will not know whether and how they can shrink or grow the extent of the part of the sentence that is inside the argument to make the whole message work for their language.

    Recommendation: If possible, use complex arguments as the outermost structure of a message, and write full sentences in their sub-messages. If you have nested select and plural arguments, place the select arguments (with their fixed sets of choices) on the outside and nest the plural arguments (hopefully at most one) inside.

  • Add context notes. These notes represent developers' comments and give translators broader context for the string and placeholders. They also provide information that helps translators understand words or concepts that are potentially ambiguous (such as the word “window”: window in a computer vs. a window in a house).

Let's look more closely at the different resource types, use cases, and recommendations.

String Type

Simple strings are represented as JSON strings. The strings are written as MessageFormat patterns, with or without placeholders for parameters (string, number, date, time, etc.) that are formatted and injected at runtime.

Strings can contain any Unicode character, except control characters that are escaped. See Escape Syntax.

Although it's valid JSON, the typewriter apostrophe U+0027 (') (the default single quote mark on US English keyboards) is an exception because it's a special character in MessageFormat patterns. It's best to avoid this character in source strings; instead, use the closing single quotation mark U+2019 () character for representing a single quote mark.

Translated strings might need to include single quote marks, even if the source string doesn't include any. This is particularly common in French translations, for example. Instruct translators to prefer using the closing single quotation mark U+2019 () character in this case. It is also good for developers to remind translators about this in a context note.

If it's necessary to specifically include a literal typewriter apostrophe character in a MessageFormat pattern, you can do so by by escaping it with a second typewriter apostrophe. For example, '' in a MessageFormat pattern renders as '.

Curly brace is another exception. It is also a special character in MessageFormat patterns. The one case where the typewriter apostrophe definitely should be used is as an escape character to include a literal curly brace character in a MessageFormat pattern. For example, '{''}' in a MessageFormat pattern renders as {'}. For such usage, it's best to include a context note for translators. Also, the translations that are returned should be carefully reviewed because the syntax is unintuitive.

Examples of simple strings, with and without placeholders (shorthand representation):

Copied to clipboard.

"stringId1": "This is a window.",
"stringId2": "Hello {user}, this is a window."

The first example shows a simple string without placeholders. The second example shows a string with a string placeholder.

Note: Number, date, and time placeholders must include the format type in the syntax.

Examples of value structure (verbose representation):

Copied to clipboard.

"stringId1": {
    "value": "This is a window.",
    "note": "This refers to a window in a computer."
},
"stringId2": {
    "value": "Hello {user}, this is a window.",
    "note": "This refers to a window in a computer."
},

The first example shows a string without placeholders. The second example shows a string with a string placeholder. Adding a context note can clarify for translators whether the window represents a window in a computer or a physical window in a house.

Recommendation: Using the value structure with a context note to help translators is strongly recommended. Context note should be included especially when the string has a placeholder.

Structured Resource Value Types

Structured resource value types relieve the pain of editing and reading complex MessageFormat plural and selected patterns. Sub-patterns that include branching based on the parameter can be provided as a map with parameter values as keys. Items in a map represent different branches for a sub-pattern.

Plural Type

Recommendation: Writing complex MessageFormat plural patterns is complicated and error-prone For this reason, and to increase readability of resources, developers are strongly recommended to construct plural forms with plural structured resource value type, which encourages full, translatable sentences for each plural item, and avoid the complex MessageFormat constructs. Doing so helps ensure high-quality translations.

When inserting numeric values into strings, a common problem is making the resulting sentence grammatically correct. For example, you might have a MessageFormat pattern like:

Copied to clipboard.

"You have {0,number,integer} **items** in your cart"

However, if the number of items is 1, the sentence should read:

Copied to clipboard.

"You have 1 **item** in your cart"

To handle this case, it can be tempting to create two strings:

Copied to clipboard.

"itemsInCartPattern_singular"

and

Copied to clipboard.

"itemsInCartPattern_plural"

It can also be tempting to avoid the problem by using a “neutral” string, such as:

Copied to clipboard.

"You have {0,number,integer} item(s) in your cart"

However, both of these solutions overlooks the grammatical requirements of other languages, which do not always fall neatly into just two categories.

MessageFormat has a pattern syntax for handling plurals, but it is difficult to work with. Instead, using plural structured resource value type syntax makes writing grammatically correct plurals for any language easier.

To construct a plural resource, you need to provide two parameters:

  • param: The name of the variable to use in selecting the message
  • pluralItems: The list of strings with associated rules to select between

The selection of the appropriate plural variant is made based on the parameter value. The relevant parameter ID is provided with the param property. The parameters in MessageFormat can be both named and numbered, so this property can be either a string or a number.

Plural variants are contained in pluralItems property, which is a map of plural parameter values and plural variants.

Allowed parameter names are:

Copied to clipboard.

[^[[:Pattern_Syntax:][:Pattern_White_Space:]]]+

[:Pattern_Syntax:] and [:Pattern_White_Space:] are ICU UnicodeSet.

Parameter names cannot include spaces.

Allowed plural parameter values are:

  • zero
  • one
  • two
  • few
  • many
  • ^(=[0-9]+)$
  • other (Required; other must always appear because it is the rule that triggers when the parameter value matches no other rule)

Note: The set of plural parameter values varies by language. English uses =0, one, and other. It doesn't have distinct grammatical use cases for two, few, many, ^(=[0-9]+)$. If source strings are authored in English, the latter values should not appear in source plural structured resource values.

Rules fall into two categories: enumerated rules and numerical rules. The enumerated rules are zero, one, two, few, many, and other. Although the names are suggestive, the rules do not always "mean what they say". Each locale has different logic for when a rule triggers. For example, in English, the one rule triggers for the value 1. But this rule does not trigger for languages that don't have grammatical plurals, such as Japanese or Chinese, and triggers for different values, such as numbers ending in one (21, 31, etc.) in some other locales.

Numerical rules match specific values. In our example, the =0 rule matches the value 0. Numerical rules take precedence over enumerated rules. You should write a numerical rule when you want a specific message tied to a value. For example, if you want to display the message "You have one chance remaining before your account is locked", you should use the rule =1 rather than the one rule to ensure that the message is always and only displayed when the parameter value is equal to one.

When authoring resources in English, always write the rules used in the example: =0, one, and other. Localization should take care of generating any rules required by other locales during the translation process. Add numerical rules as required, such as the =1 case mentioned above.

Example plural structured resource value:

Copied to clipboard.

{
"resources": {
  "message1": {
    "value": {
     "param": "appleCount",
     "pluralItems": {
        "=0": "You have no apples in a basket",
        "one": "You have {appleCount,number,integer} apple in a basket",
        "other": "You have {appleCount,number,integer} apples in a basket"
      }
    }
  }
}

And the same example with numbered parameter:

Copied to clipboard.

{
  "resources": {
    "message1": {
      "value": {
        "param": 0,
        "pluralItems": {
          "=0": "You have no apples in a basket",
          "one": "You have {0,number,integer} apple in a basket",
          "other": "You have {0,number,integer} apples in a basket"
        }
      }
    }
  }
}

In the previous examples, the parameter is used for branching and also appears in branch sentences.

When to Use A Plural

Use a plural any time a number or price is inserted into sentence. For example:

Copied to clipboard.

"You have 2 items in your cart"

or

Copied to clipboard.

"You will be charged $5 per item."

Use a plural, even if the English string is grammatically correct for all values. It might not be grammatically correct for all values in other languages.

When Not to Use A Plural

Do not use a plural if the number or value is not part of the sentence. For example:

Copied to clipboard.

"Number of items: 2"

or

Copied to clipboard.

"Price: $3.27"
Plural Type Sample Use Case

Let's look at a sample use case. Suppose you want to insert a numeric value into a string, such as to display the number of items in a customer's cart. For example:

Copied to clipboard.

"You have no items in your cart."

"You have 1 item in your cart."

"You have 2 items in your cart."

...

For this example, you should construct a plural structured resource value, so that customers get grammatically correct results for their language and there's no hassle of having to edit and read complex MessageFormat patterns.

'Recommended: The following format is strongly recommended. Notice that plural structured resource value type has full, translatable sentences for each plural item. This increases the readability for the translators and gives them the full context of the string. Also, with full sentences, it's easier to rearrange the word ordering in the translation to follow the natural language flow. The following example also includes a context note to give translators more information:

Copied to clipboard.

{
  "resources": {
    "number-of-items-in-cart": {
      "note": "cartItems is a placeholder that shows number of items in the cart",
      "value": {
        "param": "cartItems",
        "pluralItems": {
          "=0": "You have zero items in your cart.",
          "one": "You have {cartItems,number,integer} item in your cart.",
          "other": "You have {cartItems,number,integer} items in your cart."
        }
      }
    }
  }
}

Not recommended: The following format expresses an incomplete thought. This can lead to problems with word order in the translations, and it's difficult for translators to understand the context:

{% include copybutton.html id="xkLOZZAE" %}

{
  "resources": {
    "plural-message-format": "You have {cartItems,plural,=0 {zero items} one {{cartItems,number,integer} item} other {{cartItems,number,integer} items}} in your cart."
  }
}

Select type

When inserting names or nouns into a string, their grammatical gender property can affect other associated words in the string. Select MessageFormat pattern is designed to help with handling grammatical gender based inflection. For more information, see ICU SelectFormat documentation.

Select structured resource value type simplifies usage of select MessageFormat pattern. This type represents branching based on a parameter with arbitrary values. The select structured resource value has two required properties:

  • param: The name of the variable to use in selecting the message
  • selectItems: The list of strings with associated parameter values to select between

Select parameter ID is provided through param property. The parameters in MessageFormat patterns can be both named and numbered, so this property can be either a string or a number.

The branches are specified as items in selectItems property. Select item key does not have any restrictions apart from the ones imposed for string type in JSON.

Allowed parameter names are:

Copied to clipboard.

[^[[:Pattern_Syntax:][:Pattern_White_Space:]]]+

[:Pattern_Syntax:] and [:Pattern_White_Space:] are ICU UnicodeSet.

Parameter names cannot include spaces.

selectItems is required to have the other rule in the list. other must always appear because it is the rule that triggers when the parameter value matches no other item keys.

Example select structured resource value:

Copied to clipboard.

{
  "resources": {
    "message2": {
      "note" : "Simple select example",
      "value": {
        "param": "gender",
        "selectItems": {
          "female": "She has invited us for supper.",
          "male": "He has invited us for supper.",
          "other": "They have invited us for supper."
        }
      }
    }
  }
}

And the same example with numbered parameter:

Copied to clipboard.

{
  "resources": {
    "message2": {
      "note" : "Simple select example",
      "value": {
        "param": 0,
        "selectItems": {
          "female": "She has invited us for supper.",
          "male": "He has invited us for supper.",
          "other": "They have invited us for supper."
        }
      }
    }
  }
}

In previous examples, the parameter is used only for branching and does not appear in any of the branch sentences.

Select Type Sample Use Case

Let's look at a sample use case. Suppose you want to display one of the following strings depending on the host's gender:

Copied to clipboard.

"{hostName} invites you to her party."

"{hostName} invites you to his party."

"{hostName} invites you to their party."

To achieve this, specify a select structured resource value with a string as the parameter to operate the select. Note that selectItems is required to have other rule specified as an item:

Copied to clipboard.

{
  "resources": {
    "party-invitation": {
      "note" : "hostGender is a string parameter for the host's gender. hostName is a string placeholder for the host's name.",
      "value": {
        "param": "hostGender",
        "selectItems": {
          "female": "{hostName} invites you to her party.",
          "male": "{hostName} invites you to his party.",
          "other": "{hostName} invites you to their party.",
        }
      }
    }
  }
}

Nesting

Sentences may vary with more than one plural and/or select parameters:

Copied to clipboard.

There are 3 warnings and 1 error.

While this can be avoided in some cases, there are cases where there is a real need to support multiple parameters and branching based on those parameters. This is achieved by nesting structured resource values.

Nesting plural and select structured resource values is possible as each plural or select item can be of type number, string, plural, or select. At the deepest nested level, items of a complex form represent the full translation sentences.

Example of nesting structured resource values:

Copied to clipboard.

{
  "resources": {
    "party-invitation-status": {
      "note" : "guestCount is a number parameter for the number of invited guests. hostGender is a string parameter for the host's gender. hostName is a string placeholder for the host's name.",
      "value": {
        "param": "guestCount",
        "pluralItems": {
          "=0": {
            "param": "hostGender",
            "selectItems": {
                "female": "{hostName} did not invite any guests to her party.",
                "male": "{hostName} did not invite any guests to his party.",
                "other": "{hostName} did not invite any guests to their party."
            }
          },
          "one": {
            "param": "hostGender",
            "selectItems": {
                "female": "{hostName} invited one guest to her party.",
                "male": "{hostName} invited one guest to his party.",
                "other": "{hostName} invited one guest to their party."
            }
          },
          "other": {
            "param": "hostGender",
            "selectItems": {
                "female": "{hostName} invited {guestCount,number,integer} guests to her party.",
                "male": "{hostName} invited {guestCount,number,integer} guests to his party.",
                "other": "{hostName} invited {guestCount,number,integer} guests to their party."
            }
          }
        }
      }
    }
  }
}

Above example shows how a localized message branching that depends on two parameters, one being plural and the other select, is defined by nesting structured resource values. The third parameter {hostName} is added to demonstrate the possibility of having other parameters in plural and select branches that are not related to the selection of plural and select items.

Escape Syntax

PUFF-J follows standard JSON definition of string:

A string is a sequence of zero or more Unicode characters, wrapped in double quotes, using backslash escapes. A character is represented as a single character string. A string is very much like a C or Java string.

Multi-line Strings

JSON by definition does not support multi-line strings. Any newline characters have to be replaced with \n.


Last updated: Sep 30, 2025