Internationalization¶
All user-visible strings in FreeField must be internationalized and localized.
Internationalization is done using the I18N
class server-side, or using the
clientside-i18n.php
client-side. To make I18N
available for usage in a script use the following:
require_once("../includes/lib/global.php");
__require("i18n");
To include clientside-i18n.php for use in JavaScript, add the file to the HTML header of the page it is being used on, after jQuery, but before other scripts:
<head>
<!-- Meta tags, etc. -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"
integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="
crossorigin="anonymous"></script>
<script src="./js/clientside-i18n.php" async defer></script>
<!-- Other scripts -->
</head>
For all static and server-side dynamically generated HTML, I18N
should be
used. clientside-i18n.php is only for use in standalone JavaScript files which
are not parsed by the PHP parser.
String assignment¶
All strings are stored in the localization files assigned to a key (an
“internationalization token”). Internationalization tokens act as identifiers
for strings, and can consist of lowercase alphanumeric letters, periods and
underscores. Here is an example of the structure of the localization file,
showing the three tokens ui.button.close
, ui.button.cancel
and
ui.button.select
in the English localization files:
ui.button.close = "Close"
ui.button.cancel = "Cancel"
ui.button.select = "Select"
When requesting a localized string, you must use the internationalization token to refer to the string.
Usage¶
There are two types of strings that can be localized - simple strings, and
parameterized strings. Simple strings are static, unchanging strings, and are
used for most UI elements. Parameterized strings are strings that can change
depending on data arguments passed to them, and can be identified by the
appearance of substitution tokens within the strong. A substitution token is a
percentage sign followed by a number, both wrapped together in curly braces -
for example, {%1}
. These substitution tokens are substituted by other data,
such as a number or another string at runtime. There can be any number of
substitution tokens in a string, starting from {%1}
with sequentially
increasing numbers for each token.
Note
Substitution tokens are normally ordered in increasing order from
their natural placement in the English-language variant of strings,
but this may not always be the case. Some strings do not start with
{%1}
as the first token, and they may not necessarily be in
increasing order. While it is strongly advisable that the tokens do
appear in increasing order, switching them around may be preferable in
some cases where it is sensible due to programming or style.
One example of this is the quantity
parameter for research
objectives. For singular variants of the strings, the substitution
token for quantity
is typically replaced by an article such as “a”
or “an.” To ensure that tokens start numbering from 1, and to avoid
“gaps” in the numbering sequence of tokens, quantity
is given the
highest substitution token number to ensure that the numbering makes
sense if the token is omitted, even though it in most cases would
appear as the first token of the string and therefore be assigned
{%1}
.
Important
When adding parameterized strings to the localization files, examples and explanations should be made for each substitution token in your string to assist translators in accurately translating the string.
Important
Any strings you want to use in clientside-i18n.php must be declared in that file on the server - they will not work unless their namespace have already been declared in the file from before.
Note
Strings for use in JavaScript on the administration pages must be
declared with internationalization tokens starting with
admin.clientside.
and not under admin.
directly.
Using simple strings¶
The basic I18N
function to localize strings is I18N::resolve($token)
.
This function takes an internationalization token as input and returns a
localized string for the currently active language.
$str = I18N::resolve("ui.button.close");
echo $str; // Echoes "Close"
Danger
Never use resolve()
as part of output! See Security in FreeField for
information on resolveHTML()
and other functions that should be
used instead for output in order to prevent security/XSS
vulnerabilities.
The JavaScript equivalent with clientside-i18n.php is resolveI18N()
:
var str = resolveI18N("ui.button.close");
console.log(str); // Writes "Close" to console
Danger
Never use .innerHTML
or jQuery .html()
to assign string
content to elements - use .textContent
or jQuery .text()
instead to prevent security/XSS vulnerabilities and character
encoding issues. Please see Security in FreeField for more information.
Using parameterized strings¶
The I18N
function to localize parameterized strings is
I18N::resolveArgs($token, ...$args)
. This function takes an
internationalization token along with a list of arguments as input, and returns
a localized string for the currently active language.
$str = I18N::resolveArgs("webhook.reported_by", "JohnDoe45");
echo $str; // Echoes "Reported by JohnDoe45"
Danger
Never use resolveArgs()
as part of output! See Security in FreeField
for information on resolveArgsHTML()
and other functions that
should be used instead for output in order to prevent security/XSS
vulnerabilities.
The JavaScript equivalent with clientside-i18n.php is the same as for simple strings:
var str = resolveI18N("webhook.reported_by", "JohnDoe45");
console.log(str); // Writes "Reported by JohnDoe45" to console
Danger
Never use .innerHTML
or jQuery .html()
to assign string
content to elements - use .textContent
or jQuery .text()
instead to prevent security/XSS vulnerabilities and character
encoding issues. Please see Security in FreeField for more information.
Localization file structure¶
If you want to add new internationalization tokens to the localization files, you should stay in line with the structure of the file. Pay attention to headers and ensure that strings you add are grouped with similar strings. For example, generic UI elements/buttons should be localized under the “USER INTERFACE” header near the top of the file. Please do not randomly tack any additional strings to the start or end of the file.