<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://en.doc.boardgamearena.com/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Archduke</id>
	<title>Board Game Arena - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://en.doc.boardgamearena.com/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Archduke"/>
	<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/Special:Contributions/Archduke"/>
	<updated>2026-11-13T15:30:23Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.43.11</generator>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Tutorials_checklist&amp;diff=20146</id>
		<title>Tutorials checklist</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Tutorials_checklist&amp;diff=20146"/>
		<updated>2024-02-20T09:24:03Z</updated>

		<summary type="html">&lt;p&gt;Archduke: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;In order to allow for a full-fledged tutorial to be built for the game you have adapted on BGA studio:&lt;br /&gt;
# the game replay archive generated for the game must be valid (you should be able to run the replay from start to finish without errors using the &amp;quot;Replay game&amp;quot; function on a finished table)&lt;br /&gt;
# each action of the replay should be replayable by triggering it manually (i.e. by reproducing the exact same sequence as done played originally during the game&lt;br /&gt;
# each element of the game interface should be available for attaching a comment or a highlight component on it.&lt;br /&gt;
&lt;br /&gt;
You can read more about building tutorials in practice here: https://boardgamearena.com/tutorialfaq&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If a player trying to create a tutorial reports you an issue about 1) or 2), the most likely reasons for the issue are:&lt;br /&gt;
* that you have triggered this.ajaxcall() programmatically in a notification handling function or a callback instead of only on a user interface action.&lt;br /&gt;
* or (for 2) ), that there are several way to trigger the next action with different URL/arguments. You should make sure that the same game actions are triggered with the same &amp;quot;ajaxcall&amp;quot; whatever the UX path used.&lt;br /&gt;
&lt;br /&gt;
If a player trying to create a tutorial reports you an issue about 3):&lt;br /&gt;
* you might have some overlapping elements preventing to access the &amp;quot;div&amp;quot; tag of an important interface element to attach tutorial content to it.&lt;br /&gt;
* you might have some missing &amp;quot;ID&amp;quot; on elements of the interface, preventing the tutorial author to attach elements to them.&lt;br /&gt;
&lt;br /&gt;
== Publishing Tutorials ==&lt;br /&gt;
Tutorials, in general, are only published if they satisfy these conditions:&lt;br /&gt;
&lt;br /&gt;
* They have an average rating of 4.2 or higher&lt;br /&gt;
* They have been rated at least 10 times (for moving to BETA)&lt;br /&gt;
* They have been rated at least 100 times (for moving to LIVE)&lt;br /&gt;
&lt;br /&gt;
If a tutorial should be published, but does not meet these requirements, the help of a BGA admin is required.&lt;br /&gt;
&lt;br /&gt;
== Tutorial Game release override ==&lt;br /&gt;
&lt;br /&gt;
In case someone already wrote a tutorial that did not work well because something small must be changed in the game adaptation code, it may be possible to make the existing tutorial works with a newer version of the game adaptation.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
* You wrote 90% of a tutorial for game Carcassonne, based on a game replay which is using BGA version V1.&lt;br /&gt;
* Because of a problem in the game adaptation, you cannot write the remaining 10%.&lt;br /&gt;
* The developer of the Carcassonne adaptation fixes the issue in a new version of Carcassonne for BGA: version V2.&lt;br /&gt;
* You will have to rewrite the entire tutorial using a replay based on a game played with this new version V2.&lt;br /&gt;
* HOWEVER, using Tutorial game release override, you can ask a BGA admin to switch your tutorial to the newer version of the game.&lt;br /&gt;
&lt;br /&gt;
Important: This can only works if the game release updates are limited. To be more specific: the new version must be compatible with the moves notifications sent by the previous version. For example, if on the new version you expect on Client side a new parameter in a move notification, the version override will just break the replay and make your tutorial unplayable.&lt;br /&gt;
&lt;br /&gt;
As a tutorial author, if you want to do this switch, please write an email to studio(at)boardgamearena.com specifying:&lt;br /&gt;
* The tutorial ID (you must be the tutorial author or the game adaptation developer)&lt;br /&gt;
* The game version that the tutorial should use&lt;br /&gt;
* &amp;quot;Tutorial game release override&amp;quot; as email subject&lt;/div&gt;</summary>
		<author><name>Archduke</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Template:Studio_Framework_Navigation&amp;diff=19172</id>
		<title>Template:Studio Framework Navigation</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Template:Studio_Framework_Navigation&amp;diff=19172"/>
		<updated>2023-12-12T11:18:54Z</updated>

		<summary type="html">&lt;p&gt;Archduke: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;!-- Do not use heading tags, or else these sidebar headings appear in the page TOCs --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;studio-framework-navigation&amp;quot; style=&amp;quot;float: right; width: 300px; border: solid #000 1px; padding: 1em; margin-left: 1em; background: #fff;&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-weight:bold;font-size:1.2em;margin-top:0.3em;line-height:1.6;padding-top:0.5em;&amp;quot;&amp;gt;&amp;lt;center&amp;gt;&#039;&#039;&#039;Game File Reference&#039;&#039;&#039;&amp;lt;/center&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-weight:bold;font-size:1.2em;margin-top:0.3em;line-height:1.6;padding-top:0.5em;&amp;quot;&amp;gt;&amp;lt;center&amp;gt;&#039;&#039;&#039;[[Studio file reference|Overview]]&#039;&#039;&#039;&amp;lt;/center&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* [[Game database model: dbmodel.sql|&amp;lt;b&amp;gt;dbmodel.sql&amp;lt;/b&amp;gt;]] - database model&lt;br /&gt;
* [[Game meta-information: gameinfos.inc.php|&amp;lt;b&amp;gt;gameinfos.inc.php&amp;lt;/b&amp;gt;]] - meta-information&lt;br /&gt;
* [[Options and preferences: gameoptions.json, gamepreferences.json|&amp;lt;b&amp;gt;gameoptions.json&amp;lt;/b&amp;gt;]] - game options &amp;amp; user preferences&lt;br /&gt;
* [[Game art: img directory|&amp;lt;b&amp;gt;img/&amp;lt;/b&amp;gt;]] - game art&lt;br /&gt;
* [[Game_metadata_manager|&amp;lt;b&amp;gt;Game Metadata Manager&amp;lt;/b&amp;gt;]] - tags and metadata media&lt;br /&gt;
* [[Game material description: material.inc.php|&amp;lt;b&amp;gt;material.inc.php&amp;lt;/b&amp;gt;]] - static data&lt;br /&gt;
* &amp;lt;b&amp;gt;misc/&amp;lt;/b&amp;gt; - studio-only storage&lt;br /&gt;
* &amp;lt;b&amp;gt;modules/&amp;lt;/b&amp;gt; - additional game code&lt;br /&gt;
* [[Your game state machine: states.inc.php|&amp;lt;b&amp;gt;states.inc.php&amp;lt;/b&amp;gt;]] - state machine&lt;br /&gt;
* [[Game statistics: stats.json|&amp;lt;b&amp;gt;stats.json&amp;lt;/b&amp;gt;]] - statistics&lt;br /&gt;
* [[Players actions: yourgamename.action.php|X.&amp;lt;b&amp;gt;action.php&amp;lt;/b&amp;gt;]] - player actions&lt;br /&gt;
* [[Game interface stylesheet: yourgamename.css|X&amp;lt;b&amp;gt;.css&amp;lt;/b&amp;gt;]] - interface stylesheet&lt;br /&gt;
* [[Main game logic: yourgamename.game.php|X.&amp;lt;b&amp;gt;game.php&amp;lt;/b&amp;gt;]] - main logic&lt;br /&gt;
* [[Game interface logic: yourgamename.js|X.&amp;lt;b&amp;gt;js&amp;lt;/b&amp;gt;]] - interface logic&lt;br /&gt;
* [[Game layout: view and template: yourgamename.view.php and yourgamename_yourgamename.tpl|X.&amp;lt;b&amp;gt;view.php&amp;lt;/b&amp;gt;]] - dynamic game layout&lt;br /&gt;
* [[Game layout: view and template: yourgamename.view.php and yourgamename_yourgamename.tpl|X_X.&amp;lt;b&amp;gt;tpl&amp;lt;/b&amp;gt;]] - static game layout&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
-----&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-weight:bold;font-size:1.2em;margin-top:0.3em;line-height:1.6;padding-top:0.5em;&amp;quot;&amp;gt;&amp;lt;center&amp;gt;&#039;&#039;&#039;Useful Components&#039;&#039;&#039;&amp;lt;/center&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Official&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* [[Deck]]: a PHP component to manage cards (deck, hands, picking cards, moving cards, shuffle deck, ...).&lt;br /&gt;
* [[Draggable]]: a JS component to manage drag&#039;n&#039;drop actions.&lt;br /&gt;
* [[Counter]]: a JS component to manage a counter that can increase/decrease (ex: player&#039;s score).&lt;br /&gt;
* [[ExpandableSection]]: a JS component to manage a rectangular block of HTML than can be displayed/hidden.&lt;br /&gt;
* [[Scrollmap]]: a JS component to manage a scrollable game area (useful when the game area can be infinite. Examples:  Saboteur or Takenoko games).&lt;br /&gt;
* [[Stock]]: a JS component to manage and display a set of game elements displayed at a position.&lt;br /&gt;
* [[Zone]]: a JS component to manage a zone of the board where several game elements can come and leave, but should be well displayed together (See for example: token&#039;s places at Can&#039;t Stop).&lt;br /&gt;
&lt;br /&gt;
Undocumented component (if somebody knows please help with docs)&lt;br /&gt;
* [[Wrapper]]: a JS component to wrap a  &amp;amp;lt;div&amp;amp;gt; element around its child, even if these elements are absolute positioned.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Unofficial&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* [[BGA Code Sharing]] - Shared resources, projects on git hub, common code, other links&lt;br /&gt;
* [[BGA Studio Cookbook]] - Tips and instructions on using API&#039;s, libraries and frameworks&lt;br /&gt;
* [[Some usual board game elements image ressources]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
-----&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-weight:bold;font-size:1.2em;margin-top:0.3em;line-height:1.6;padding-top:0.5em;&amp;quot;&amp;gt;&amp;lt;center&amp;gt;&#039;&#039;&#039;Game Development Process&#039;&#039;&#039;&amp;lt;/center&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* [[First steps with BGA Studio]]&lt;br /&gt;
* [[Create a game in BGA Studio: Complete Walkthrough]]&lt;br /&gt;
* [[Tutorial reversi]] &lt;br /&gt;
* [[Tutorial gomoku]] &lt;br /&gt;
* [[Tutorial hearts]]&lt;br /&gt;
* [[BGA Studio Guidelines]]&lt;br /&gt;
* [[BGA game Lifecycle]]&lt;br /&gt;
* [[Pre-release checklist]]&lt;br /&gt;
* [[Post-release phase]]&lt;br /&gt;
* [[Help|Player Resources]] - add player help/rules to your game page&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
-----&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-weight:bold;font-size:1.2em;margin-top:0.3em;line-height:1.6;padding-top:0.5em;&amp;quot;&amp;gt;&amp;lt;center&amp;gt;&#039;&#039;&#039;Guides for Common Topics&#039;&#039;&#039;&amp;lt;/center&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* [[Translations]] - make your game translatable&lt;br /&gt;
* [[Game replay|Game Replay]]&lt;br /&gt;
* [[Your game mobile version|Mobile Users]]&lt;br /&gt;
* [[3D]]&lt;br /&gt;
* [[Compatibility]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
-----&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-weight:bold;font-size:1.2em;margin-top:0.3em;line-height:1.6;padding-top:0.5em;&amp;quot;&amp;gt;&amp;lt;center&amp;gt;&#039;&#039;&#039;Miscellaneous Resources&#039;&#039;&#039;&amp;lt;/center&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* [[Studio FAQ]]&lt;br /&gt;
* [[Tools and tips of BGA Studio]] - Tips and instructions on setting up development environment&lt;br /&gt;
* [[Studio logs]] - Instructions for log access&lt;br /&gt;
* [[Practical debugging]] - Tips focused on debugging&lt;br /&gt;
* [[Troubleshooting]] - Most common &amp;quot;I am really stuck&amp;quot; situations&lt;br /&gt;
* [https://studio.boardgamearena.com/bugs Studio Bugs] - Reports against Studio itself (not BGA!)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Archduke</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Troubleshooting&amp;diff=18888</id>
		<title>Troubleshooting</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Troubleshooting&amp;diff=18888"/>
		<updated>2023-11-15T12:48:39Z</updated>

		<summary type="html">&lt;p&gt;Archduke: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
Describing common errors which are hard to understand and debug. This may be useful for troubleshooting.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Game does not start at all ==&lt;br /&gt;
&lt;br /&gt;
=== Undefined offset: 0 in table/table.game.php on line 1417 ===&lt;br /&gt;
&lt;br /&gt;
Do not call self::getActivePlayerName() during setupNewGame()&lt;br /&gt;
&lt;br /&gt;
Ensure you&#039;re calling $this-&amp;gt;gamestate-&amp;gt;changeActivePlayer() at the end of your game setup. You must always have at least one active player.&lt;br /&gt;
&lt;br /&gt;
=== Javascript error: During pageload n is null ===&lt;br /&gt;
&lt;br /&gt;
When calling dojo.place(), the name of the container (second parameter) to place the new block into is not defined in the page template.&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error: Wrong formatted data from BGA gameserver 1 (method: createGame): ... ===&lt;br /&gt;
&lt;br /&gt;
This is generic message usually followed by exact position in your source code, and usually its syntax error in one of yours php script&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error: Propagating error from GS 1 (method: createGame): Fatal error during yourgame setup: Not logged ===&lt;br /&gt;
&lt;br /&gt;
Calling self::getCurrentPlayerId () or using $g_user from &#039;args&#039; state function, see also below&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error: Propagating error from GS 1 (method: createGame): Fatal error during yourgame setup: Unknow player statistic: ===&lt;br /&gt;
&lt;br /&gt;
Calling self::incStat() with second parameter which is an empty string&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error:  Propagating error from GS 1 (method: createGame): Fatal error during yourgame setup: Error while processing SQL request: INSERT INTO stats ... ===&lt;br /&gt;
&lt;br /&gt;
Fatal error during yourgame setup: Error while processing SQL request: INSERT INTO stats (stats_type, stats_player_id, stats_value) VALUES (&#039;10&#039;,&#039;2300663&#039;,&#039;0&#039;),(&#039;10&#039;,&#039;2300662&#039;,&#039;0&#039;)&lt;br /&gt;
Duplicate entry &#039;10-2300663&#039; for key &#039;stats_table_id&#039;&lt;br /&gt;
&lt;br /&gt;
Why? In the stats.inc.php you declared two keys with the same integer &amp;quot;id&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error:  Propagating error from GS 1 (method: createGame): Fatal error during yourgame setup: BGA main website do not respond ===&lt;br /&gt;
&lt;br /&gt;
Check if other games work; if not, it&#039;s a problem with BGA Studio; if so, your game likely reaches an end state immediately. Check your states.inc.php and your transitions.&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error: Propagating error from GS 1 (method: createGame): BGA service error ===&lt;br /&gt;
&lt;br /&gt;
You may have a syntax error in your dbmodel.sql.&lt;br /&gt;
&lt;br /&gt;
Or, you may be calling self::initStat() for a statistic that does not exist. Check the statistic name, and make sure you clicked &amp;quot;Reload statistics configuration&amp;quot; button in the admin console after making changes to stats.inc.php&lt;br /&gt;
&lt;br /&gt;
Or you may not have your states.inc.php set up correctly.&lt;br /&gt;
&lt;br /&gt;
You may have an error in your table.game.php file in setupNewGame (such as &amp;lt;code&amp;gt;$result[&#039;x&#039;] = y;&amp;lt;/code&amp;gt; when $result is not an array).&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error: Table status of a starting game should be &#039;setup&#039; ===&lt;br /&gt;
&lt;br /&gt;
This error message appears when you start a one player game using the &amp;quot;Express Start&amp;quot; button.&lt;br /&gt;
&lt;br /&gt;
In normal situation, the game starts just after this message and everything should works normally. In this case, you can just ignore this message.&lt;br /&gt;
&lt;br /&gt;
If the games does not start, it is most probable that there is a syntax error in any of your php code (Check your states.inc.php and X.game.php)&lt;br /&gt;
&lt;br /&gt;
=== Fatal error during creation of database ebd_quoridor_389 Not logged ===&lt;br /&gt;
&lt;br /&gt;
Check that you didn&#039;t use $g_user or getCurrentPlayerId() in setupNewGame() function or in an &#039;args&#039; function of your state.&lt;br /&gt;
&lt;br /&gt;
As these functions are not consequences of a user action, there is no current player defined.&lt;br /&gt;
&lt;br /&gt;
As a general rule, you should use getActivePlayerId() and not getCurrentPlayerId(). See the [http://www.slideshare.net/boardgamearena/bga-studio-focus-on-bga-game-state-machine presentation on the game state machine] for more information.&lt;br /&gt;
&lt;br /&gt;
=== Warning: Invalid argument supplied for foreach() in table.game.php ===&lt;br /&gt;
&lt;br /&gt;
   Warning: Invalid argument supplied for foreach() in /var/tournoi/release/tournoi-151226-1240-gs/www/game/module/table/table.game.php on line 129 &lt;br /&gt;
   Fatal error: Cannot unset string offsets in /var/tournoi/release/tournoi-151226-1240-gs/www/game/module/table/table.game.php on line 143&lt;br /&gt;
&lt;br /&gt;
That appears when your arg* function that suppose to return array of state arguments returns a scalar (a non-array) value&lt;br /&gt;
&lt;br /&gt;
=== The server reported an error ===&lt;br /&gt;
&lt;br /&gt;
During table creation: &amp;quot;The server reported an error&amp;quot; error shown and nothing else.&lt;br /&gt;
&lt;br /&gt;
If you cannot even create a table - there is syntax error in gameinfos.php, check it, reload it from management panel.&lt;br /&gt;
If still no luck copy clean version from template https://github.com/elaskavaia/bga-sharedcode/blob/master/gameinfos.inc.php&lt;br /&gt;
&lt;br /&gt;
=== Unexpected Error : Invalid player number for this game : 4 ===&lt;br /&gt;
&lt;br /&gt;
This error may comes when trying to change the player number configuration in gameinfos.inc.php from a higher to lower number of players (for example from 4 to 2).&lt;br /&gt;
&lt;br /&gt;
The following steps will help to change a player config from array(4) to array(2) :&lt;br /&gt;
&lt;br /&gt;
* change in gameinfos.inc.php the entry to &#039;players&#039; =&amp;gt; array( 2,3,4 )&lt;br /&gt;
* In game management page (Control Panel &amp;gt; Manage Games &amp;gt; &amp;quot;Your Game&amp;quot;), press the &amp;quot;Reload Game information&amp;quot; button&lt;br /&gt;
* create a new table&lt;br /&gt;
* reduce the number of players to 2 and start the game&lt;br /&gt;
* (express) Stop the game&lt;br /&gt;
* change in gameinfos.inc.php the entry to &#039;players&#039; =&amp;gt; array( 2 )&lt;br /&gt;
* press again the &amp;quot;Reload Game information&amp;quot; button&lt;br /&gt;
&lt;br /&gt;
=== Blank page ===&lt;br /&gt;
If you see no html at all check &lt;br /&gt;
* if you have syntax error in your view.php file &lt;br /&gt;
* class name of your view.php file  does not match the project name (should be view_foo_foo if project is foo)&lt;br /&gt;
* game name return by getGameName() does not match the project name  (should be &amp;quot;foo&amp;quot; if project is foo)&lt;br /&gt;
&lt;br /&gt;
    class view_russianrailroads_russianrailroads extends game_view {&lt;br /&gt;
    function getGameName() {&lt;br /&gt;
        return &amp;quot;russianrailroads&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
=== &amp;quot;Ooooops, this page does not exists :/&amp;quot; ===&lt;br /&gt;
If your table is created, but you are redirected to &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;https://studio.boardgamearena.com/1/index.php&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; when you try to launch your table, then you are most likely missing the [[Players actions: yourgamename.action.php|action PHP file]].&lt;br /&gt;
&lt;br /&gt;
No other error is displayed or logged, meaning this can be tough to debug.&lt;br /&gt;
&lt;br /&gt;
Make sure the file is correctly named, as any typo means the studio won&#039;t be able to find the file.&lt;br /&gt;
&lt;br /&gt;
== Game starts but I can&#039;t make a move ==&lt;br /&gt;
&lt;br /&gt;
=== When I do a move, I got &amp;quot;Move recorded, waiting for update ...&amp;quot; forever ===&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Move recorded&amp;quot; means that your ajaxcall request has been sent to the server and returned normally.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Waiting for update&amp;quot; means that your client interface is waiting for some notifications from the server that correspond to the move we just did.&lt;br /&gt;
&lt;br /&gt;
If this message stays forever, it is probably that your PHP code does not send any notification when the move happens, which is abnormal. To fix this: add a notifyAllPlayers or a notifyPlayer call in your PHP code.&lt;br /&gt;
&lt;br /&gt;
=== When I do a move, I get &amp;quot;Sending move to server...&amp;quot; then nothing and game resets to state before the move ===&lt;br /&gt;
&lt;br /&gt;
Its possible that server code get into infinite loops or thinks too much, in which case it will timeout and will be aborted without any extra logs (and db transaction you saw in the log won&#039;t be committed). You will usually see &amp;quot;Unable to connect to server&amp;quot; message on console in this case. You have to put more logging into server&lt;br /&gt;
to trace where it hangs.&lt;br /&gt;
&lt;br /&gt;
You may also see this error in the log in this case: &amp;quot;Error (2006) while processing SQL request: MySQL server has gone away&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=== When I do a move, I get &amp;quot;Ajaxcall error: empty answer&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
You either have missing self::ajaxResponse(); in your [[Players actions: yourgamename.action.php|game.action.php]] method, or there is some problem with getting arguments (check that you are using btoa() on client when using AT_base64 arg type in action.php)&lt;br /&gt;
&lt;br /&gt;
=== When I do a move, I get &amp;quot;Gameserver is locked by configuration&amp;quot;. ===&lt;br /&gt;
&lt;br /&gt;
You may have an error in your AJAX path, such as /reversi/reversi when your game&#039;s name is different.&lt;br /&gt;
&lt;br /&gt;
=== Some player action is triggered randomly when I click somewhere on the game area ===&lt;br /&gt;
&lt;br /&gt;
You probably used &amp;quot;dojo.connect&amp;quot; on a null object. In this case, dojo.connect associate the event (ex: &amp;quot;onclick&amp;quot;) to the whole game area.&lt;br /&gt;
&lt;br /&gt;
Most of the time it happens in this situation, when my_object element does not exists:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   dojo.connect( $(&amp;quot;my_object&amp;quot;), &amp;quot;onclick&amp;quot;, this, (event)=&amp;gt;{})&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To determine if this is the case, place &amp;quot;alert( $(&amp;quot;my_object&amp;quot;) )&amp;quot; before the dojo.connect to check if the object exists or not.&lt;br /&gt;
&lt;br /&gt;
=== Error: This is not your turn ===&lt;br /&gt;
&lt;br /&gt;
This happens when checkAction() is called and current player is NOT the active player.&lt;br /&gt;
&lt;br /&gt;
You can change the active player in studio by clicking the red arrow next to their name in the player panel (right side of the page).&lt;br /&gt;
&lt;br /&gt;
[[File:Change_active_player.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== Error: Please wait, an action is already in progress ===&lt;br /&gt;
Its followed by error &amp;quot;(Generated by checkAction / XXX)&amp;quot; on studio.&lt;br /&gt;
&lt;br /&gt;
This error is triggered in the JS by the checkAction function for XXX action.&lt;br /&gt;
&lt;br /&gt;
This can happen when the player sent an Ajax request action earlier, and:&lt;br /&gt;
* action is not complete yet - i.e. takes some time, and user clicked something again &lt;br /&gt;
* if there is bug in interface where MULTIPLE handlers are fired on same click. To debug this add some console.trace() in place this specific checkAction is called.&lt;br /&gt;
* did not get any notification from the PHP side. To avoid this, put an empty notifyPlayer in the PHP side of the Ajax handler to ensure the client receives a response. This line of code should do it:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    $this-&amp;gt;notifyPlayer($this-&amp;gt;getCurrentPlayerId(), &#039;message&#039;, &#039;&#039;, []); // sent to current player, who originated the action&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Error: This move is not authorized now ===&lt;br /&gt;
This is generic error message generated by this.showMoveUnauthorized() function. If you did not call this function yourself, check the console log, it may have additional information.&lt;br /&gt;
If you see &amp;quot;Move not authorized now : XXX&amp;quot; in the log, where XXX is your action name - this means that action XXX is not defined in list of possible actions for your current state. This error generated by checkAction() function.&lt;br /&gt;
&lt;br /&gt;
=== Error: You are not connected - after waiting for the submitted move ===&lt;br /&gt;
In the log you may find: &lt;br /&gt;
  Query execution was interrupted, maximum statement execution time exceeded - Request: SELECT global_id, global_value FROM global WHERE 1&lt;br /&gt;
&lt;br /&gt;
The error message above is because of failed attempt to lock a table, which happens because of infinite loop in you game.&lt;br /&gt;
* Check that don&#039;t enter same game state over and over again&lt;br /&gt;
* Check that you reverse for loop actually descrease counter or other loop issues&lt;br /&gt;
* Check that recursive function ends&lt;br /&gt;
&lt;br /&gt;
== Predefined server errors ==&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error: Unexpected final game state (XX) ===&lt;br /&gt;
&lt;br /&gt;
The action function does not transition to any state, i.e.&lt;br /&gt;
  function selectField($field) {&lt;br /&gt;
    self::checkAction ( &#039;selectField&#039; );&lt;br /&gt;
    if ($field!=0) $this-&amp;gt;gamestate-&amp;gt;nextState ( &#039;next&#039; );&lt;br /&gt;
  }&lt;br /&gt;
Here if $field is 0 there is no transition&lt;br /&gt;
&lt;br /&gt;
=== This game action is impossible right now ===&lt;br /&gt;
&lt;br /&gt;
Check the game log. Usually your state does not define the action you trying to perform in &#039;possibleactions&#039; array.&lt;br /&gt;
&lt;br /&gt;
Also check your onActionName javascript function. Make sure you are calling the right &amp;quot;actionname.html&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error: This transition (playerTurn) is impossible at this state (42) ===&lt;br /&gt;
&lt;br /&gt;
This is pretty self explanatory. Function nextState() takes transition name not a state name, so you probably did not&lt;br /&gt;
define this transition that the given state&lt;br /&gt;
&lt;br /&gt;
== Game interface hangs during reload or on start ==&lt;br /&gt;
&lt;br /&gt;
Showing &amp;quot;Application Loading...&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=== Javascript error: During pageload undefined no_stack_avail Script: ===&lt;br /&gt;
&lt;br /&gt;
This error usually has no useful data, but it means you called somes API that require a callback and did not define callback function, i.e&lt;br /&gt;
in dojo.connect, this.connectClass, dojo.subscribe, etc&lt;br /&gt;
   &lt;br /&gt;
      this.connectClass(&#039;field&#039;, &#039;onclick&#039;, &#039;onField&#039;); // &amp;lt;-- onField is not defined&lt;br /&gt;
&lt;br /&gt;
=== Other errors with &amp;quot;Application loading...&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
You probably have a syntax error in your Javascript code, and the interface refuses to load.&lt;br /&gt;
&lt;br /&gt;
To find this error, check if there is an error message in the Javascript console (F12).&lt;br /&gt;
&lt;br /&gt;
If there is really nothing on the log, it&#039;s probably that the system was unable to load your Javascript because of an syntax error that affect the structure of the Javascript file, typically a missing &amp;quot;}&amp;quot; or a missing &amp;quot;,&amp;quot; after a method definition.&lt;br /&gt;
&lt;br /&gt;
If you have &amp;quot;Uncaught ReferenceError: bgagame is not defined&amp;quot; you have major syntax error in your js file, you should see some other clues in the log where the errors is.&lt;br /&gt;
&lt;br /&gt;
If you have &amp;quot;dojo.publish is not defined&amp;quot; or something similar, this could be caused by another error earlier. For example, a syntax error caused by a malformed generated file (such as using newlines in tiebreaker description). Also you might have left some images in the /img directory with special characters in the name which must be removed. If you edited images for the game box and website, ensure that you have not left any unnecessary files there.&lt;br /&gt;
&lt;br /&gt;
=== Unexpected Syntax Error: ===&lt;br /&gt;
&lt;br /&gt;
No further details in the log. When log is filling with some social connect errors.&lt;br /&gt;
&lt;br /&gt;
Possible Reason: Syntax error in of the php script which is loaded before the start, such as gameoptions.inc.php, gameinfos.inc.php and such.&lt;br /&gt;
&lt;br /&gt;
=== Game interface spins in a loop throwing error ===&lt;br /&gt;
&lt;br /&gt;
Errors is something like &amp;quot;Cannot read property &#039;is_ai&#039; of undefined&amp;quot;. Cannot restart the game because cannot access UI to stop.&lt;br /&gt;
Likely you get in actplayer state with player id == 0. The only way to fix it is to edit database, globals index == 2 set player id to one of your test dudes&lt;br /&gt;
(can copy from row 5 for example).&lt;br /&gt;
&lt;br /&gt;
=== Unable to find table database (1): ebd_yourgame_112222 ===&lt;br /&gt;
&lt;br /&gt;
Its either temporarily server error especially on studio it timeouts sometimes, just try reloading again.&lt;br /&gt;
Or check if you have syntax errors in your php game file or sql.&lt;br /&gt;
&lt;br /&gt;
== Type conversion / juggling errors ==&lt;br /&gt;
&lt;br /&gt;
=== On php side I get a number instead of string I expect ===&lt;br /&gt;
&lt;br /&gt;
 $num = 3;&lt;br /&gt;
 $meeple = &amp;quot;meeple_&amp;quot; + $num; // &amp;lt;-- suppose to be &amp;quot;meeple_3&amp;quot;!&lt;br /&gt;
&lt;br /&gt;
When you switch between JS and PHP it easy to type this and not notice the +. Plus sign (+) in php does not mean string concatenation (in javascript does!),&lt;br /&gt;
in php + means integer arithmetic. So change + to . (dot)&lt;br /&gt;
&lt;br /&gt;
=== On php side my string comparison does not work ===&lt;br /&gt;
&lt;br /&gt;
   if ($color == &#039;4baae2&#039; || $color == &#039;000000&#039;) { &lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
Apparently you should not be using &#039;==&#039; in php to compare strings! You should use &#039;===&#039;. The (==) operator will typecast the strings &lt;br /&gt;
to numbers then do comparison!&lt;br /&gt;
Its not very apparent because usually you can get away with it, but not when strings resemble numbers like hex &#039;colors&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Integer columns in the database are returned as strings ===&lt;br /&gt;
&lt;br /&gt;
This is normal PHP behavior. All fields are returned as string type, regardless of their actual type in the database. This also applies to global variables accessed via getGameStateValue(), since they are stored in a database table.&lt;br /&gt;
&lt;br /&gt;
You can use type-casting to convert them to the correct type after they come out of the database.&lt;br /&gt;
&lt;br /&gt;
   $myValueInt = (int)self::getGameStateValue(GLOBAL_ROUND_NUMBER);&lt;br /&gt;
&lt;br /&gt;
or&lt;br /&gt;
&lt;br /&gt;
   $myValueInt = self::getGameStateValue(GLOBAL_ROUND_NUMBER) + 0; // adding 0 casts to int&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
same with direct qdb ueries&lt;br /&gt;
   $sql = &amp;quot;SELECT my_int_column FROM my_table WHERE my_condition&amp;quot;;&lt;br /&gt;
   $myResult = self::getUniqueValueFromDB($sql); &amp;lt;-- this is a string&lt;br /&gt;
   $myResultAsInt = (int)$myResult;&lt;br /&gt;
&lt;br /&gt;
https://stackoverflow.com/questions/5323146/mysql-integer-field-is-returned-as-string-in-php&lt;br /&gt;
&lt;br /&gt;
== Zombie mode ==&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error: Propagating error from GS 1 (method: zombie): Not logged ===&lt;br /&gt;
&lt;br /&gt;
You are probably calling getCurrentPlayerId() or getCurrentPlayerName() in your zombieTurn method or any of the methods it uses. Instead, use the $active_player_id provided as parameter to zombieTurn().&lt;br /&gt;
&lt;br /&gt;
If you do not see these commands within &amp;quot;function zombieTurn( $state, $active_player ){}&amp;quot;, check all the functions called from zombieTurn, also &amp;quot;function getGameProgression(){}&amp;quot; and all the functions THAT calls.&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error: Can&#039;t manage zombie player in this game state ===&lt;br /&gt;
&lt;br /&gt;
The state the game was in at the time the error was generated didn&#039;t have &amp;quot;transitions&amp;quot; =&amp;gt; array( &amp;quot;zombiePass&amp;quot; =&amp;gt; 27 )&amp;quot; in states.inc.php (27 was an arbitrary example, but everything else must be spelled exactly that way.)&lt;br /&gt;
&lt;br /&gt;
To correct this error, either add &amp;quot;zombiePass&amp;quot; =&amp;gt; ## to the transitions array or work out why the game is in a state it should not be in.&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error: Wrong formatted data from BGA gameserver 1 (method: zombie): ===&lt;br /&gt;
&lt;br /&gt;
This is almost certainly an undefined value in PHP code. Look for a warning or error message in the game replay log on the right side of the table UI.&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error: BGA gameserver 1 do not respond (method: zombie) (timeout: cluster) ===&lt;br /&gt;
&lt;br /&gt;
You are trying to end the game from a zombie method. This is not allowed. The zombie logic must continue the game as best it can. See [[Main_game_logic:_yourgamename.game.php#Zombie_mode|Zombie mode]] for more info.&lt;br /&gt;
&lt;br /&gt;
=== Game unexpectedly ends when one player becomes zombie ===&lt;br /&gt;
&lt;br /&gt;
There is an error in handling zombie mode, check error log. Example: if the zombie turn is called again, framework detects a infinite loop and cancels the game. On the studio there is a notification called ZombieTurnFailed&lt;br /&gt;
&lt;br /&gt;
== Dead locks ==&lt;br /&gt;
&lt;br /&gt;
=== Database dead lock in multiplayer state ===&lt;br /&gt;
You normally won&#039;t see this error until game is released because to reproduce game it have to be hit with 2 players doing an action simultaneosly.&lt;br /&gt;
You only can reprodoce this on studio if you either very fast or you use a script (with direct REST calls).&lt;br /&gt;
&lt;br /&gt;
There is few types of deadlocks&lt;br /&gt;
I) Try-lock - this one you don&#039;t need to worry about even it does appear in the log, this is 2 player doing the action and second cannot lock db, it will re-try up to 3 times and hopefully it be ok&lt;br /&gt;
II) Real dead lock - when 2 tables are locked in reversed by 2 actions, its unclar if this really  happen  but workaround number 2 theorically should solved it (but it will increase number of deadlocks of type I)&lt;br /&gt;
&lt;br /&gt;
There are two known workarounds:&lt;br /&gt;
&lt;br /&gt;
1) Use $this-&amp;gt;bIndependantMultiactiveTable=true in constructor which will force usage of playermultiactive table, but this does not eliminate dead lock completely.&lt;br /&gt;
&lt;br /&gt;
2) Before every action explictly lock tables in specific order (add this code in your game.php file)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   // Due to deadlock issues involving the playersmultiactive and player tables,&lt;br /&gt;
   //   standard tables are queried FOR UPDATE when any operation occurs -- AJAX or refreshing a game table.&lt;br /&gt;
   //&lt;br /&gt;
   // Otherwise at least two situations have been observed to cause deadlocks:&lt;br /&gt;
   //   * Multiple players in a live game with tabs open, two players trading multiactive state back and forth.&lt;br /&gt;
   //   * Two players trading multiactive state back and forth, another player refreshes their game page.&lt;br /&gt;
   private function queryStandardTables() {&lt;br /&gt;
      // Query the standard global table.&lt;br /&gt;
      $this-&amp;gt;DbQuery(&amp;quot;SELECT global_id, global_value FROM global WHERE 1 ORDER BY global_id FOR UPDATE&amp;quot;);&lt;br /&gt;
      // Query the standard player table.&lt;br /&gt;
      $this-&amp;gt;DbQuery(&amp;quot;SELECT player_id id, player_score score FROM player WHERE 1 ORDER BY player_id FOR UPDATE&amp;quot;);&lt;br /&gt;
      // Query the playermultiactive  table. DO NOT USE THIS is you don&#039;t use $this-&amp;gt;bIndependantMultiactiveTable=true&lt;br /&gt;
      $this-&amp;gt;DbQuery(&amp;quot;SELECT ma_player_id player_id, ma_is_multiactive player_is_multiactive FROM playermultiactive ORDER BY player_id FOR UPDATE&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
      // TODO should the stats table be queried as well?&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
    /** This is action function that canbe called from multiplayer state */&lt;br /&gt;
    protected function actionXXX() {&lt;br /&gt;
        $this-&amp;gt;queryStandardTables();&lt;br /&gt;
        ... // your arg function code&lt;br /&gt;
    }&lt;br /&gt;
    /** This is arg function of multiplayer state, XXX is replaced by actual name of state. &lt;br /&gt;
        You need to do it for EVERY arg function in multiplayer states which accesses the database. &lt;br /&gt;
        You don&#039;t need to do it for arg function for single player states  &lt;br /&gt;
    */&lt;br /&gt;
    protected function argXXX() {&lt;br /&gt;
        $this-&amp;gt;queryStandardTables();&lt;br /&gt;
        ... // your arg function code&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Other errors ==&lt;br /&gt;
&lt;br /&gt;
=== Javascript does not know how to sum two numbers ===&lt;br /&gt;
&lt;br /&gt;
Be careful when you manipulate integers returned by notifications: most of the time, Javascript considers they are Strings and not Integers.&lt;br /&gt;
&lt;br /&gt;
As a result:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    var i=1;&lt;br /&gt;
    i += notif.args.increment;  // With notif.args.increment=&#039;1&#039;&lt;br /&gt;
    alert( i );                 // i=11 instead of 2 !! Javascript concatenate 2 strings !&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To solve this, you should use the &amp;quot;toint&amp;quot; function:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    var i=1;&lt;br /&gt;
    i += toint( notif.args.increment );  // With notif.args.increment=&#039;1&#039;&lt;br /&gt;
    alert( i );                 // i=2 :)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Javascript: do not use substr with negative numbers ===&lt;br /&gt;
&lt;br /&gt;
To get the last characters of a string, use &amp;quot;slice&amp;quot; instead of &amp;quot;substr&amp;quot; which has a bug on IE:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    var three_last_characters = string.substr( -3 );   // Wrong&lt;br /&gt;
    var three_last_characters = string.slice( -3 );    // Correct&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Game &amp;quot;spontaneously&amp;quot; transition to a new state without user input ===&lt;br /&gt;
&lt;br /&gt;
Make sure on php side you have no code after   $this-&amp;gt;gamestate-&amp;gt;nextState(...) code.&lt;br /&gt;
Because if you do accidentally have code that goes to another state it will cause another state transition without user interaction.&lt;br /&gt;
&lt;br /&gt;
 function selectField($field) {&lt;br /&gt;
   self::checkAction ( &#039;selectField&#039; );&lt;br /&gt;
   if ($field!=0) $this-&amp;gt;gamestate-&amp;gt;nextState ( &#039;next&#039; );&lt;br /&gt;
   $this-&amp;gt;gamestate-&amp;gt;nextState ( &#039;last&#039; ); // &amp;lt;-- here is missing else, so it will cause double state transition&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Message &amp;quot;Invalid or missing substitution argument for log message: ${actplayer} ... &amp;quot; when entering a state ===&lt;br /&gt;
&lt;br /&gt;
You probably have an args function defined for that state that does &#039;&#039;&#039;not&#039;&#039;&#039; return an array&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Server syntax error: Warning: count(): Parameter must be an array or an object that implements Countable in /var/tournoi/release/tournoi-220308-1000-gs/www/game/module/table/gamestate.game.php on line 823 ===&lt;br /&gt;
&lt;br /&gt;
Generally comes with that syntax error : Warning: implode(): Invalid arguments passed in /var/tournoi/release/tournoi-220308-1000-gs/www/game/module/table/gamestate.game.php on line 845&lt;br /&gt;
&lt;br /&gt;
It is most probable that you used setPlayersMultiactive method with id of a single player not included in an array -&amp;gt; you should use: ... setPlayersMultiactive( array($player_id), ...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Red banner &amp;quot;Uncaught EvalError: Possible side-effect in debug-evaluate&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is a known issue that can be ignored (for most of case). Generally happening when working on devtool.&lt;br /&gt;
A workaround is to disable the &amp;quot;error&amp;quot; event listener. To do so, you can temporarily disable the event listener in DevTools, like this:&lt;br /&gt;
&lt;br /&gt;
 - At the top of DevTools, open the &amp;quot;Elements&amp;quot; tab&lt;br /&gt;
 - Press &amp;quot;»&amp;quot;, on the right of &amp;quot;Styles&amp;quot;, &amp;quot;Computed&amp;quot;, &amp;quot;Layout&amp;quot;&lt;br /&gt;
 - Choose &amp;quot;Event listeners&amp;quot;&lt;br /&gt;
 - Find and expand &amp;quot;error&amp;quot;&lt;br /&gt;
 - Click &amp;quot;Remove&amp;quot;&lt;br /&gt;
&lt;br /&gt;
This will remove the event listener, but the issue will return after you refresh the page.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Studio]]&lt;/div&gt;</summary>
		<author><name>Archduke</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Game_replay&amp;diff=18887</id>
		<title>Game replay</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Game_replay&amp;diff=18887"/>
		<updated>2023-11-15T10:42:32Z</updated>

		<summary type="html">&lt;p&gt;Archduke: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Studio_Framework_Navigation}}&lt;br /&gt;
&lt;br /&gt;
Game replay is managed by the framework. You do not need to do anything special about it in your code, except taking care of updating the client interface through the framework notification system (and not for example, by using the callback function of an ajaxcall).&lt;br /&gt;
&lt;br /&gt;
The game replay works like this:&lt;br /&gt;
* The static files for the game at the time of the game start are archived&lt;br /&gt;
* All notifications sent to the browser are added to the archive&lt;br /&gt;
* When replaying, the static files are loaded in the browser, then notifications are sent back to replay the game moves.&lt;br /&gt;
&lt;br /&gt;
So in essence, the replay works like an exact recording.&lt;br /&gt;
&lt;br /&gt;
NB: the game replay feature is now available on the studio (since December 2020). Please note that there may be a delay before the replay becomes available.&lt;br /&gt;
&lt;br /&gt;
=== Preview Videos ===&lt;br /&gt;
Example games are periodically selected from which videos are generated to show off the game on the game panel.&lt;br /&gt;
&lt;br /&gt;
Wingspan: https://x.boardgamearena.net/data/gamepreviews/1635/en-w640.webm&lt;br /&gt;
&lt;br /&gt;
=== Hiding UI elements from preview video ===&lt;br /&gt;
&lt;br /&gt;
Some games have pop-up modals which are displayed in some cases, these should be hidden for the replay video so you can show off the gameplay right from the game page!&lt;br /&gt;
&lt;br /&gt;
[[File:Mycity-with-modal.png|500px]]&lt;br /&gt;
&lt;br /&gt;
Previews are generated with a query variable set &amp;lt;code&amp;gt;target=video&amp;lt;/code&amp;gt;. You can check for this query param in the following way:&lt;br /&gt;
&lt;br /&gt;
 const searchParams = new URLSearchParams(window.location.search);&lt;br /&gt;
 if (searchParams) {&lt;br /&gt;
     const target = searchParams.get(&#039;target&#039;);&lt;br /&gt;
     if (target === &amp;quot;video&amp;quot;) {&lt;br /&gt;
         // Hide modal popups...&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
[[Category:Studio]]&lt;/div&gt;</summary>
		<author><name>Archduke</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=File:Mycity-with-modal.png&amp;diff=18886</id>
		<title>File:Mycity-with-modal.png</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=File:Mycity-with-modal.png&amp;diff=18886"/>
		<updated>2023-11-15T10:39:59Z</updated>

		<summary type="html">&lt;p&gt;Archduke: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Preview video with obstructing modal&lt;/div&gt;</summary>
		<author><name>Archduke</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Compatibility&amp;diff=18876</id>
		<title>Compatibility</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Compatibility&amp;diff=18876"/>
		<updated>2023-11-14T08:48:19Z</updated>

		<summary type="html">&lt;p&gt;Archduke: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Studio_Framework_Navigation}}&lt;br /&gt;
&lt;br /&gt;
The mainsite is built with compatibility for several old browsers.&lt;br /&gt;
&lt;br /&gt;
We use a [https://browsersl.ist/#q=last+2+versions%2C+not+dead%2C+%3E+0.2%25 browserslist] config to define the targeted browsers: &amp;lt;code&amp;gt;last 2 versions, not dead, &amp;gt; 0.2%, safari &amp;gt;= 11&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
There are currently no hard rules about what you should target, but it is recommended to follow the same targets as the mainsite. You can use [https://babeljs.io/ babel] to compile your modern JavaScript code into backwards compatible code. Babel accepts a browserslist targets string, so you can use the targets above.&lt;br /&gt;
&lt;br /&gt;
== Current list ==&lt;br /&gt;
&lt;br /&gt;
As of November 2023, &amp;lt;code&amp;gt;last 2 versions, not dead, &amp;gt; 0.2%, safari &amp;gt;= 11&amp;lt;/code&amp;gt; corresponds to:&lt;br /&gt;
&lt;br /&gt;
* and_chr 113&lt;br /&gt;
* and_ff 113&lt;br /&gt;
* and_qq 13.1&lt;br /&gt;
* and_uc 13.4&lt;br /&gt;
* android 113&lt;br /&gt;
* android 4.4.3-4.4.4&lt;br /&gt;
* chrome 113&lt;br /&gt;
* chrome 112&lt;br /&gt;
* chrome 111&lt;br /&gt;
* chrome 110&lt;br /&gt;
* chrome 109&lt;br /&gt;
* chrome 108&lt;br /&gt;
* chrome 103&lt;br /&gt;
* chrome 79&lt;br /&gt;
* edge 113&lt;br /&gt;
* edge 112&lt;br /&gt;
* edge 111&lt;br /&gt;
* firefox 113&lt;br /&gt;
* firefox 112&lt;br /&gt;
* firefox 111&lt;br /&gt;
* ios_saf 16.4&lt;br /&gt;
* ios_saf 16.3&lt;br /&gt;
* ios_saf 16.2&lt;br /&gt;
* ios_saf 16.1&lt;br /&gt;
* ios_saf 16.0&lt;br /&gt;
* ios_saf 15.6&lt;br /&gt;
* ios_saf 15.5&lt;br /&gt;
* ios_saf 14.5-14.8&lt;br /&gt;
* ios_saf 14.0-14.4&lt;br /&gt;
* ios_saf 12.2-12.5&lt;br /&gt;
* kaios 3.0-3.1&lt;br /&gt;
* kaios 2.5&lt;br /&gt;
* op_mini all&lt;br /&gt;
* op_mob 73&lt;br /&gt;
* opera 98&lt;br /&gt;
* opera 97&lt;br /&gt;
* opera 96&lt;br /&gt;
* safari 16.4&lt;br /&gt;
* safari 16.3&lt;br /&gt;
* safari 16.2&lt;br /&gt;
* safari 16.1&lt;br /&gt;
* safari 16.0&lt;br /&gt;
* safari 15.6&lt;br /&gt;
* safari 15.5&lt;br /&gt;
* safari 15.4&lt;br /&gt;
* safari 15.2-15.3&lt;br /&gt;
* safari 15.1&lt;br /&gt;
* safari 15&lt;br /&gt;
* safari 14.1&lt;br /&gt;
* safari 14&lt;br /&gt;
* safari 13.1&lt;br /&gt;
* safari 13&lt;br /&gt;
* safari 12.1&lt;br /&gt;
* safari 12&lt;br /&gt;
* safari 11.1&lt;br /&gt;
* safari 11&lt;br /&gt;
* samsung 20&lt;br /&gt;
* samsung 19.0&lt;br /&gt;
&lt;br /&gt;
[[Category:Studio]]&lt;/div&gt;</summary>
		<author><name>Archduke</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Template:Studio_Framework_Navigation&amp;diff=18868</id>
		<title>Template:Studio Framework Navigation</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Template:Studio_Framework_Navigation&amp;diff=18868"/>
		<updated>2023-11-13T16:25:28Z</updated>

		<summary type="html">&lt;p&gt;Archduke: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;!-- Do not use heading tags, or else these sidebar headings appear in the page TOCs --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;studio-framework-navigation&amp;quot; style=&amp;quot;float: right; width: 300px; border: solid #000 1px; padding: 1em; margin-left: 1em; background: #fff;&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-weight:bold;font-size:1.2em;margin-top:0.3em;line-height:1.6;padding-top:0.5em;&amp;quot;&amp;gt;&amp;lt;center&amp;gt;&#039;&#039;&#039;Game File Reference&#039;&#039;&#039;&amp;lt;/center&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-weight:bold;font-size:1.2em;margin-top:0.3em;line-height:1.6;padding-top:0.5em;&amp;quot;&amp;gt;&amp;lt;center&amp;gt;&#039;&#039;&#039;[[Studio file reference|Overview]]&#039;&#039;&#039;&amp;lt;/center&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* [[Game database model: dbmodel.sql|&amp;lt;b&amp;gt;dbmodel.sql&amp;lt;/b&amp;gt;]] - database model&lt;br /&gt;
* [[Game meta-information: gameinfos.inc.php|&amp;lt;b&amp;gt;gameinfos.inc.php&amp;lt;/b&amp;gt;]] - meta-information&lt;br /&gt;
* [[Options and preferences: gameoptions.json, gamepreferences.json|&amp;lt;b&amp;gt;gameoptions.json&amp;lt;/b&amp;gt;]] - game options &amp;amp; user preferences&lt;br /&gt;
* [[Game art: img directory|&amp;lt;b&amp;gt;img/&amp;lt;/b&amp;gt;]] - game art&lt;br /&gt;
* [[Game_metadata_manager|&amp;lt;b&amp;gt;Game Metadata Manager&amp;lt;/b&amp;gt;]] - tags and metadata media&lt;br /&gt;
* [[Game material description: material.inc.php|&amp;lt;b&amp;gt;material.inc.php&amp;lt;/b&amp;gt;]] - static data&lt;br /&gt;
* &amp;lt;b&amp;gt;misc/&amp;lt;/b&amp;gt; - studio-only storage&lt;br /&gt;
* &amp;lt;b&amp;gt;modules/&amp;lt;/b&amp;gt; - additional game code&lt;br /&gt;
* [[Your game state machine: states.inc.php|&amp;lt;b&amp;gt;states.inc.php&amp;lt;/b&amp;gt;]] - state machine&lt;br /&gt;
* [[Game statistics: stats.inc.php|&amp;lt;b&amp;gt;stats.inc.php&amp;lt;/b&amp;gt;]] - statistics&lt;br /&gt;
* [[Players actions: yourgamename.action.php|X.&amp;lt;b&amp;gt;action.php&amp;lt;/b&amp;gt;]] - player actions&lt;br /&gt;
* [[Game interface stylesheet: yourgamename.css|X&amp;lt;b&amp;gt;.css&amp;lt;/b&amp;gt;]] - interface stylesheet&lt;br /&gt;
* [[Main game logic: yourgamename.game.php|X.&amp;lt;b&amp;gt;game.php&amp;lt;/b&amp;gt;]] - main logic&lt;br /&gt;
* [[Game interface logic: yourgamename.js|X.&amp;lt;b&amp;gt;js&amp;lt;/b&amp;gt;]] - interface logic&lt;br /&gt;
* [[Game layout: view and template: yourgamename.view.php and yourgamename_yourgamename.tpl|X.&amp;lt;b&amp;gt;view.php&amp;lt;/b&amp;gt;]] - dynamic game layout&lt;br /&gt;
* [[Game layout: view and template: yourgamename.view.php and yourgamename_yourgamename.tpl|X_X.&amp;lt;b&amp;gt;tpl&amp;lt;/b&amp;gt;]] - static game layout&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
-----&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-weight:bold;font-size:1.2em;margin-top:0.3em;line-height:1.6;padding-top:0.5em;&amp;quot;&amp;gt;&amp;lt;center&amp;gt;&#039;&#039;&#039;Useful Components&#039;&#039;&#039;&amp;lt;/center&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Official&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* [[Deck]]: a PHP component to manage cards (deck, hands, picking cards, moving cards, shuffle deck, ...).&lt;br /&gt;
* [[Draggable]]: a JS component to manage drag&#039;n&#039;drop actions.&lt;br /&gt;
* [[Counter]]: a JS component to manage a counter that can increase/decrease (ex: player&#039;s score).&lt;br /&gt;
* [[ExpandableSection]]: a JS component to manage a rectangular block of HTML than can be displayed/hidden.&lt;br /&gt;
* [[Scrollmap]]: a JS component to manage a scrollable game area (useful when the game area can be infinite. Examples:  Saboteur or Takenoko games).&lt;br /&gt;
* [[Stock]]: a JS component to manage and display a set of game elements displayed at a position.&lt;br /&gt;
* [[Zone]]: a JS component to manage a zone of the board where several game elements can come and leave, but should be well displayed together (See for example: token&#039;s places at Can&#039;t Stop).&lt;br /&gt;
&lt;br /&gt;
Undocumented component (if somebody knows please help with docs)&lt;br /&gt;
* [[Wrapper]]: a JS component to wrap a  &amp;amp;lt;div&amp;amp;gt; element around its child, even if these elements are absolute positioned.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Unofficial&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* [[BGA Code Sharing]] - Shared resources, projects on git hub, common code, other links&lt;br /&gt;
* [[BGA Studio Cookbook]] - Tips and instructions on using API&#039;s, libraries and frameworks&lt;br /&gt;
* [[Some usual board game elements image ressources]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
-----&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-weight:bold;font-size:1.2em;margin-top:0.3em;line-height:1.6;padding-top:0.5em;&amp;quot;&amp;gt;&amp;lt;center&amp;gt;&#039;&#039;&#039;Game Development Process&#039;&#039;&#039;&amp;lt;/center&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* [[First steps with BGA Studio]]&lt;br /&gt;
* [[Create a game in BGA Studio: Complete Walkthrough]]&lt;br /&gt;
* [[Tutorial reversi]] &lt;br /&gt;
* [[Tutorial gomoku]] &lt;br /&gt;
* [[Tutorial hearts]]&lt;br /&gt;
* [[BGA Studio Guidelines]]&lt;br /&gt;
* [[BGA game Lifecycle]]&lt;br /&gt;
* [[Pre-release checklist]]&lt;br /&gt;
* [[Post-release phase]]&lt;br /&gt;
* [[Help|Player Resources]] - add player help/rules to your game page&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
-----&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-weight:bold;font-size:1.2em;margin-top:0.3em;line-height:1.6;padding-top:0.5em;&amp;quot;&amp;gt;&amp;lt;center&amp;gt;&#039;&#039;&#039;Guides for Common Topics&#039;&#039;&#039;&amp;lt;/center&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* [[Translations]] - make your game translatable&lt;br /&gt;
* [[Game replay|Game Replay]]&lt;br /&gt;
* [[Your game mobile version|Mobile Users]]&lt;br /&gt;
* [[3D]]&lt;br /&gt;
* [[Compatibility]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
-----&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-weight:bold;font-size:1.2em;margin-top:0.3em;line-height:1.6;padding-top:0.5em;&amp;quot;&amp;gt;&amp;lt;center&amp;gt;&#039;&#039;&#039;Miscellaneous Resources&#039;&#039;&#039;&amp;lt;/center&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* [[Studio FAQ]]&lt;br /&gt;
* [[Tools and tips of BGA Studio]] - Tips and instructions on setting up development environment&lt;br /&gt;
* [[Studio logs]] - Instructions for log access&lt;br /&gt;
* [[Practical debugging]] - Tips focused on debugging&lt;br /&gt;
* [[Troubleshooting]] - Most common &amp;quot;I am really stuck&amp;quot; situations&lt;br /&gt;
* [https://studio.boardgamearena.com/bugs Studio Bugs] - Reports against Studio itself (not BGA!)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Archduke</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Your_game_state_machine:_states.inc.php&amp;diff=18254</id>
		<title>Your game state machine: states.inc.php</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Your_game_state_machine:_states.inc.php&amp;diff=18254"/>
		<updated>2023-10-04T08:57:12Z</updated>

		<summary type="html">&lt;p&gt;Archduke: /* Private parallel states */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Studio_Framework_Navigation}}&lt;br /&gt;
&lt;br /&gt;
This file describes the state machine of your game (all the game states properties, and the transitions to get from one state to another).&lt;br /&gt;
&lt;br /&gt;
Important: to understand the game state machine, it&#039;s recommended that you read this presentation first:&lt;br /&gt;
&lt;br /&gt;
[http://www.slideshare.net/boardgamearena/bga-studio-focus-on-bga-game-state-machine Focus on BGA game state machine]&lt;br /&gt;
&lt;br /&gt;
== Overall structure ==&lt;br /&gt;
&lt;br /&gt;
The machine states are described by a PHP associative array.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$machinestates = array(&lt;br /&gt;
&lt;br /&gt;
    // The initial state. Please do not modify.&lt;br /&gt;
    1 =&amp;gt; array(&lt;br /&gt;
        &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;gameSetup&amp;quot;,&lt;br /&gt;
        &amp;quot;description&amp;quot; =&amp;gt; clienttranslate(&amp;quot;Game setup&amp;quot;),&lt;br /&gt;
        &amp;quot;type&amp;quot; =&amp;gt; &amp;quot;manager&amp;quot;,&lt;br /&gt;
        &amp;quot;action&amp;quot; =&amp;gt; &amp;quot;stGameSetup&amp;quot;,&lt;br /&gt;
        &amp;quot;transitions&amp;quot; =&amp;gt; array( &amp;quot;&amp;quot; =&amp;gt; 2 )&lt;br /&gt;
    ),&lt;br /&gt;
    &lt;br /&gt;
    // Note: ID=2 =&amp;gt; your first state&lt;br /&gt;
&lt;br /&gt;
    2 =&amp;gt; array(&lt;br /&gt;
    		&amp;quot;name&amp;quot; =&amp;gt; &amp;quot;playerTurn&amp;quot;,&lt;br /&gt;
    		&amp;quot;description&amp;quot; =&amp;gt; clienttranslate(&#039;${actplayer} must play a card or pass&#039;),&lt;br /&gt;
    		&amp;quot;descriptionmyturn&amp;quot; =&amp;gt; clienttranslate(&#039;${you} must play a card or pass&#039;),&lt;br /&gt;
    		&amp;quot;type&amp;quot; =&amp;gt; &amp;quot;activeplayer&amp;quot;,&lt;br /&gt;
    		&amp;quot;possibleactions&amp;quot; =&amp;gt; array( &amp;quot;playCard&amp;quot;, &amp;quot;pass&amp;quot; ),&lt;br /&gt;
    		&amp;quot;transitions&amp;quot; =&amp;gt; array( &amp;quot;playCard&amp;quot; =&amp;gt; 2, &amp;quot;pass&amp;quot; =&amp;gt; 2 )&lt;br /&gt;
    ),&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Syntax ==&lt;br /&gt;
&lt;br /&gt;
=== id ===&lt;br /&gt;
&lt;br /&gt;
The keys determine game state IDs (in the example above: 1 and 2).&lt;br /&gt;
&lt;br /&gt;
IDs must be positive integers.&lt;br /&gt;
&lt;br /&gt;
ID=1 is reserved for the first game state and should not be used (and you must not modify it).&lt;br /&gt;
&lt;br /&gt;
ID=99 is reserved for the last game state (end of the game) (and you must not modify it).&lt;br /&gt;
&lt;br /&gt;
Note: you may use any ID, even an ID greater than 100. But you cannot use 1 or 99.&lt;br /&gt;
&lt;br /&gt;
Note²: You must not use the same ID twice.&lt;br /&gt;
&lt;br /&gt;
Note³: When a game is in prod and you change the ID of a state, all active games (including many turn based) will behave unpredictably.&lt;br /&gt;
&lt;br /&gt;
=== name ===&lt;br /&gt;
&lt;br /&gt;
(&#039;&#039;&#039;Mandatory&#039;&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
The name of a game state is used to identify it in your game logic.&lt;br /&gt;
&lt;br /&gt;
Several game states can share the same name; however, this is not recommended.&lt;br /&gt;
&lt;br /&gt;
Warning! Do not put spaces in the name. This could cause unexpected problems in some cases.&lt;br /&gt;
&lt;br /&gt;
PHP example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
// Get current game state&lt;br /&gt;
$state = $this-&amp;gt;gamestate-&amp;gt;state();&lt;br /&gt;
if( $state[&#039;name&#039;] == &#039;myGameState&#039; )&lt;br /&gt;
{&lt;br /&gt;
...&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
JS example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        onEnteringState: function( stateName, args )&lt;br /&gt;
        {&lt;br /&gt;
            console.log( &#039;Entering state: &#039;+stateName );&lt;br /&gt;
            &lt;br /&gt;
            switch( stateName )&lt;br /&gt;
            case &#039;myGameState&#039;:&lt;br /&gt;
            &lt;br /&gt;
                // Do some stuff at the beginning at this game state&lt;br /&gt;
                ....&lt;br /&gt;
                &lt;br /&gt;
                break;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== type ===&lt;br /&gt;
&lt;br /&gt;
(&#039;&#039;&#039;Mandatory&#039;&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
You can use 3 types of game states:&lt;br /&gt;
* activeplayer (1 player is active and must play.)&lt;br /&gt;
* multipleactiveplayer (1..N players can be active and must play.)&lt;br /&gt;
* private (during multiactive states players can independently move to different private parallel states. See more details [[#Private_parallel_states|here]].&lt;br /&gt;
* game (No player is active. This is a transitional state to do something automatic specified by the game rules.)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note:&#039;&#039;&#039; Make sure you don&#039;t mistype the value of this attribute. If you do (e.g. &#039;multiactiveplayer&#039; instead of &#039;multipleactiveplayer&#039;), things won&#039;t work, and you might have a hard time figuring out why.&lt;br /&gt;
&lt;br /&gt;
=== description ===&lt;br /&gt;
&lt;br /&gt;
(&#039;&#039;&#039;Mandatory&#039;&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
The description is the string that is displayed in the main action bar (top of the screen) when the state is active.&lt;br /&gt;
&lt;br /&gt;
When a string is specified as a description, you must use &amp;quot;clienttranslate&amp;quot; in order for the string to be translated on the client side:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 		&amp;quot;description&amp;quot; =&amp;gt; clienttranslate(&#039;${actplayer} must play a card or pass&#039;),&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the description string, you can use ${actplayer} to refer to the active player.&lt;br /&gt;
&lt;br /&gt;
You can also use custom arguments in your description. These custom arguments correspond to values returned by your &amp;quot;args&amp;quot; PHP method (see below &amp;quot;args&amp;quot; field).&lt;br /&gt;
&lt;br /&gt;
Example of custom field:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In states.inc.php:&lt;br /&gt;
        &amp;quot;description&amp;quot; =&amp;gt; clienttranslate(&#039;${actplayer} must choose ${nbr} identical energies&#039;),&lt;br /&gt;
        &amp;quot;args&amp;quot; =&amp;gt; &amp;quot;argMyArgumentMethod&amp;quot;&lt;br /&gt;
&lt;br /&gt;
In mygame.game.php:&lt;br /&gt;
    function argMyArgumentMethod()&lt;br /&gt;
    {&lt;br /&gt;
        return array(&lt;br /&gt;
            &#039;nbr&#039; =&amp;gt; 2  // In this case ${nbr} in the description will be replaced by &amp;quot;2&amp;quot;&lt;br /&gt;
        );    &lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: You may specify an empty string (&amp;quot;&amp;quot;) here if it never happens that the game remains in this state (i.e., if this state immediately jumps to another state when activated).&lt;br /&gt;
&lt;br /&gt;
Note²: Usually, you specify a string for &amp;quot;activeplayer&amp;quot; and &amp;quot;multipleactiveplayer&amp;quot; game states, and you specify an empty string for &amp;quot;game&amp;quot; game states. BUT, if you are using synchronous notifications, the client can remain on a &amp;quot;game&amp;quot; type game state for a few seconds, and in this case it may be useful to display a description in the status bar while in this state.&lt;br /&gt;
&lt;br /&gt;
=== descriptionmyturn ===&lt;br /&gt;
&lt;br /&gt;
(&#039;&#039;&#039;Mandatory&#039;&#039;&#039; when the state type is &amp;quot;activeplayer&amp;quot; or &amp;quot;multipleactiveplayer&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
&amp;quot;descriptionmyturn&amp;quot; has exactly the same role and properties as &amp;quot;description&amp;quot;, except that this value is displayed to the current active player - or to all active players in case of a multipleactiveplayer game state.&lt;br /&gt;
&lt;br /&gt;
In general, we have this situation:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        &amp;quot;description&amp;quot; =&amp;gt; clienttranslate(&#039;${actplayer} can take some actions&#039;),&lt;br /&gt;
        &amp;quot;descriptionmyturn&amp;quot; =&amp;gt; clienttranslate(&#039;${you} can take some actions&#039;),&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: you can use ${you} in descriptionmyturn so the description will display &amp;quot;You&amp;quot; instead of the name of the player.&lt;br /&gt;
&lt;br /&gt;
Note 2: you can use ${otherplayer} to refer to some other player if you want this to be shown in player&#039;s color, but you must provide otherplayer_id as argument (along with otherplayer) to specify this player&#039;s id in this case or game won&#039;t load.&lt;br /&gt;
&lt;br /&gt;
I.e.&lt;br /&gt;
&lt;br /&gt;
 &amp;quot;descriptionmyturn&amp;quot; =&amp;gt; clienttranslate(&#039;${you} can follow action of ${otherplayer}&#039;),&lt;br /&gt;
&lt;br /&gt;
And this will have to be state arguments for this&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    function arg_playerTurnFollow(){&lt;br /&gt;
        return [&#039;otherplayer&#039;=&amp;gt; $this-&amp;gt;getLeaderPlayerName(),&lt;br /&gt;
                &#039;otherplayer_id&#039;=&amp;gt; $this-&amp;gt;getLeaderPlayerId()&lt;br /&gt;
        ];&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== action ===&lt;br /&gt;
&lt;br /&gt;
(&#039;&#039;&#039;Mandatory&#039;&#039;&#039; when the state type is &amp;quot;game.&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
&amp;quot;action&amp;quot; specifies a PHP method to call when entering this game state.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
In states.inc.php:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    28 =&amp;gt; array(&lt;br /&gt;
        &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;gameTurnNextPlayer&amp;quot;,&lt;br /&gt;
        &amp;quot;description&amp;quot; =&amp;gt; clienttranslate(&#039;Updating some stuff...&#039;),&lt;br /&gt;
        &amp;quot;type&amp;quot; =&amp;gt; &amp;quot;game&amp;quot;,&lt;br /&gt;
        &amp;quot;action&amp;quot; =&amp;gt; &amp;quot;st_gameTurnNextPlayer&amp;quot;,&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
In mygame.game.php:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    function st_gameTurnNextPlayer() {&lt;br /&gt;
        $player_id = $this-&amp;gt;getActivePlayerId();&lt;br /&gt;
        $next_player_id = $this-&amp;gt;getPlayerAfter($player_id);&lt;br /&gt;
        $this-&amp;gt;giveExtraTime($next_player_id);&lt;br /&gt;
        $this-&amp;gt;incStat(1, &#039;turns_number&#039;, $next_player_id);&lt;br /&gt;
        $this-&amp;gt;incStat(1, &#039;turns_number&#039;);&lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;changeActivePlayer($next_player_id);&lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;nextState(&#039;next&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Usually, for a &amp;quot;game&amp;quot; state type, the action method is used to perform automatic functions specified by the rules (for example: check victory conditions, deal cards for a new round, go to the next player, etc.) and then jump to another game state.&lt;br /&gt;
&lt;br /&gt;
Note: a BGA convention specifies that PHP methods called with &amp;quot;action&amp;quot; are prefixed by &amp;quot;st&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Note: this field CAN be used for player states to set something up; e.g., for multiplayer states, it can make all players active.&lt;br /&gt;
&lt;br /&gt;
Example for action in player state:&lt;br /&gt;
in states.inc.php:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    2 =&amp;gt; array(&lt;br /&gt;
    		&amp;quot;name&amp;quot; =&amp;gt; &amp;quot;playerTurnPlace&amp;quot;,&lt;br /&gt;
    		&amp;quot;description&amp;quot; =&amp;gt; clienttranslate(&#039;Other player must place ships&#039;),&lt;br /&gt;
    		&amp;quot;descriptionmyturn&amp;quot; =&amp;gt; clienttranslate(&#039;${you} must place ships (click on YOUR SHIPS board to place)&#039;),&lt;br /&gt;
    		&amp;quot;type&amp;quot; =&amp;gt; &amp;quot;multipleactiveplayer&amp;quot;,&lt;br /&gt;
            &#039;action&#039; =&amp;gt; &#039;st_MultiPlayerInit&#039;,&lt;br /&gt;
            &#039;args&#039; =&amp;gt; &#039;arg_playerTurnPlace&#039;,&lt;br /&gt;
    		&amp;quot;possibleactions&amp;quot; =&amp;gt; array( &amp;quot;playPlace&amp;quot; ),&lt;br /&gt;
            &amp;quot;transitions&amp;quot; =&amp;gt; array( &amp;quot;next&amp;quot; =&amp;gt; 4, &amp;quot;last&amp;quot; =&amp;gt; 99)&lt;br /&gt;
    ),&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
in mygame.game.php:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    function st_MultiPlayerInit() {&lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;setAllPlayersMultiactive();&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== transitions ===&lt;br /&gt;
&lt;br /&gt;
(&#039;&#039;&#039;Mandatory&#039;&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
With &amp;quot;transitions&amp;quot; you specify which game state(s) you can jump to from a given game state.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    25 =&amp;gt; array(&lt;br /&gt;
        &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;myGameState&amp;quot;,&lt;br /&gt;
        &amp;quot;transitions&amp;quot; =&amp;gt; array( &amp;quot;nextPlayer&amp;quot; =&amp;gt; 27, &amp;quot;endRound&amp;quot; =&amp;gt; 39 ),&lt;br /&gt;
        ....&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the example above, if &amp;quot;myGameState&amp;quot; is the current active game state, I can jump to the game state with ID 27 or the game state with ID 39.&lt;br /&gt;
&lt;br /&gt;
Example to jump to ID 27:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
In mygame.game.php:&lt;br /&gt;
    $this-&amp;gt;gamestate-&amp;gt;nextState( &amp;quot;nextPlayer&amp;quot; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Important: &amp;quot;nextPlayer&amp;quot; is the name of the transition, and NOT the name of the target game state. Multiple transitions can lead to the same game state.&lt;br /&gt;
&lt;br /&gt;
Note: If there is only 1 transition, you may give it an empty name.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
In states.inc.php:&lt;br /&gt;
    &amp;quot;transitions&amp;quot; =&amp;gt; array( &amp;quot;&amp;quot; =&amp;gt; 27 ),&lt;br /&gt;
&lt;br /&gt;
In mygame.game.php:&lt;br /&gt;
    $this-&amp;gt;gamestate-&amp;gt;nextState(  );     // We don&#039;t need to specify a transition as there is only one here&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== possibleactions ===&lt;br /&gt;
&lt;br /&gt;
(&#039;&#039;&#039;Mandatory&#039;&#039;&#039; when the game state is &amp;quot;activeplayer&amp;quot; or &amp;quot;multipleactiveplayer&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
&amp;quot;possibleactions&amp;quot; defines the actions possible by the players in this game state, and ensures they cannot perform actions that are not allowed in this state.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
In states.game.php:&lt;br /&gt;
       	&amp;quot;possibleactions&amp;quot; =&amp;gt; array( &amp;quot;playCard&amp;quot;, &amp;quot;pass&amp;quot; ),&lt;br /&gt;
&lt;br /&gt;
In mygame.game.php:&lt;br /&gt;
        function playCard( ...)&lt;br /&gt;
        {&lt;br /&gt;
             self::checkAction( &amp;quot;playCard&amp;quot; );    // Will fail if &amp;quot;playCard&amp;quot; is not specified in &amp;quot;possibleactions&amp;quot; in the current game state.&lt;br /&gt;
&lt;br /&gt;
            ....&lt;br /&gt;
&lt;br /&gt;
In mygame.js:&lt;br /&gt;
        playCard: function( ... )&lt;br /&gt;
        {&lt;br /&gt;
            if( this.checkAction( &amp;quot;playCard&amp;quot; ) ) // Will fail if &amp;quot;playCard&amp;quot; is not specified in &amp;quot;possibleactions&amp;quot; in the current game state.&lt;br /&gt;
            {  return ;   }&lt;br /&gt;
&lt;br /&gt;
            ....&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== args ===&lt;br /&gt;
&lt;br /&gt;
(optional)&lt;br /&gt;
&lt;br /&gt;
Sometimes it happens that you need some information on the client side (i.e., for your game interface) only for a specific game state.&lt;br /&gt;
&lt;br /&gt;
Example 1: in &#039;&#039;Reversi&#039;&#039;, the list of possible moves during the playerTurn state.&lt;br /&gt;
&lt;br /&gt;
Example 2: in &#039;&#039;Caylus&#039;&#039;, the number of remaining king&#039;s favors to choose in the state where the player is choosing a favor.&lt;br /&gt;
&lt;br /&gt;
Example 3: in &#039;&#039;Can&#039;t Stop&#039;&#039;, the list of possible die combinations to be displayed to the active player so that he can choose from among them.&lt;br /&gt;
&lt;br /&gt;
In such a situation, you can specify a method name as the « args » argument for your game state. This method must retrieve some piece of information about the game (example: for &#039;&#039;Reversi&#039;&#039;, the list of possible moves) and return it.&lt;br /&gt;
&lt;br /&gt;
Thus, this data can be transmitted to the clients and used by the clients to display it. It should always be an associative array.&lt;br /&gt;
&lt;br /&gt;
Let&#039;s see a complete example using args with &#039;&#039;Reversi&#039;&#039; game:&lt;br /&gt;
&lt;br /&gt;
In states.inc.php, we specify an &#039;&#039;&#039;args&#039;&#039;&#039; argument for gamestate &#039;&#039;&#039;playerTurn&#039;&#039;&#039;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    10 =&amp;gt; array(&lt;br /&gt;
        &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;playerTurn&amp;quot;,&lt;br /&gt;
		&amp;quot;description&amp;quot; =&amp;gt; clienttranslate(&#039;${actplayer} must play a disc&#039;),&lt;br /&gt;
		&amp;quot;descriptionmyturn&amp;quot; =&amp;gt; clienttranslate(&#039;${you} must play a disc&#039;),&lt;br /&gt;
        &amp;quot;type&amp;quot; =&amp;gt; &amp;quot;activeplayer&amp;quot;,&lt;br /&gt;
        &amp;quot;args&amp;quot; =&amp;gt; &amp;quot;argPlayerTurn&amp;quot;,    // &amp;lt;==== HERE&lt;br /&gt;
        &amp;quot;possibleactions&amp;quot; =&amp;gt; array( &#039;playDisc&#039; ),&lt;br /&gt;
        &amp;quot;transitions&amp;quot; =&amp;gt; array( &amp;quot;playDisc&amp;quot; =&amp;gt; 11, &amp;quot;zombiePass&amp;quot; =&amp;gt; 11 )&lt;br /&gt;
    ),&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It corresponds to a &#039;&#039;&#039;argPlayerTurn&#039;&#039;&#039; method in our PHP code (reversi.game.php):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    function argPlayerTurn() {&lt;br /&gt;
        return array(&lt;br /&gt;
            &#039;possibleMoves&#039; =&amp;gt; self::getPossibleMoves()&lt;br /&gt;
        );&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then, when we enter into the &#039;&#039;&#039;playerTurn&#039;&#039;&#039; game state on the client side, we can highlight the possible moves on the board using information returned by &#039;&#039;&#039;argPlayerTurn&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        onEnteringState: function( stateName, args )  {&lt;br /&gt;
           console.log( &#039;Entering state: &#039;+stateName );&lt;br /&gt;
            &lt;br /&gt;
            switch( stateName )  {&lt;br /&gt;
            case &#039;playerTurn&#039;:&lt;br /&gt;
                this.updatePossibleMoves( args.args.possibleMoves );&lt;br /&gt;
                break;&lt;br /&gt;
            }&lt;br /&gt;
        },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Naming and API conventions ====&lt;br /&gt;
&lt;br /&gt;
As a BGA convention, PHP methods called with &amp;quot;args&amp;quot; are prefixed by &amp;quot;arg&amp;quot; followed by state name (example: &#039;&#039;&#039;argPlayerTurn&#039;&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
All &amp;quot;arg*&amp;quot; methods are put into corresponding section of .game.php file commented as&lt;br /&gt;
   //////////// Game state arguments&lt;br /&gt;
&lt;br /&gt;
Arg method MUST return array. Return integer or string will result in some undebuggable exceptions.&lt;br /&gt;
&lt;br /&gt;
Arg method MUST be defined in php if it is declared in state description, if you don&#039;t need it comment it out from the states.inc.php file (the &#039;&#039;&#039;args&#039;&#039;&#039; parameter). If you not sure if you need it or not you can keep it returning empty array until you figure it out.&lt;br /&gt;
&lt;br /&gt;
    function argPlayerTurn() {&lt;br /&gt;
        return array(); // must be an array&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Warning&#039;&#039;&#039;: the &amp;quot;args&amp;quot; method can be called before the &amp;quot;action&amp;quot; method so don&#039;t expect data modifications by the &amp;quot;action&amp;quot; method to be available in the &amp;quot;args&amp;quot; method!&lt;br /&gt;
Also don&#039;t modify database in this method!&lt;br /&gt;
&lt;br /&gt;
You should NOT be calling getCurrentPlayer() in the context of this function, since state transitions are broadcasted to all player independent of who initiated it. Instead you should send information on per player basis (Note: if this is private info see section below). &lt;br /&gt;
&lt;br /&gt;
If you using this function in multi-player state, you should not call getActivePlayer() either, you should send per player info:&lt;br /&gt;
&lt;br /&gt;
    function arg_playerTurn() {&lt;br /&gt;
        $res = array ();&lt;br /&gt;
        $players = $this-&amp;gt;loadPlayersBasicInfos();&lt;br /&gt;
        foreach ( $players as $player_id =&amp;gt; $player_info ) {&lt;br /&gt;
            $color = $player_info [&#039;player_color&#039;];&lt;br /&gt;
            $res [$player_id] = array(&amp;quot;color&amp;quot;=&amp;gt;$color);&lt;br /&gt;
        }&lt;br /&gt;
        return $res;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Note: you never need to send player color like this, this is just an example.&lt;br /&gt;
&lt;br /&gt;
Note 2: you CAN call methods that return all active players if multi-player states if its relevant.&lt;br /&gt;
&lt;br /&gt;
==== Other usages ====&lt;br /&gt;
&lt;br /&gt;
You can use values returned by your &amp;quot;args&amp;quot; method to have some custom values in your &amp;quot;description&amp;quot;/&amp;quot;descriptionmyturn&amp;quot;, i.e. in states.inc.php:&lt;br /&gt;
&lt;br /&gt;
   &amp;quot;descriptionmyturn&amp;quot; =&amp;gt; clienttranslate(&#039;${you} must play ${color} disc&#039;),&lt;br /&gt;
&lt;br /&gt;
So arg function will be something like:&lt;br /&gt;
&lt;br /&gt;
  function argPlayerTurn() {&lt;br /&gt;
        return array(&#039;color&#039;=&amp;gt;$this-&amp;gt;getActivePlayerColor()); &lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
You can use args also in &#039;&#039;&#039;onUpdateActionButtons&#039;&#039;&#039; function on js side, however two important notes:&lt;br /&gt;
* it is just &#039;&#039;&#039;args&#039;&#039;&#039; (not args.args like in &#039;&#039;&#039;onEnteringState&#039;&#039;&#039;)&lt;br /&gt;
* it is args of the current state, which may not be state you think it will be! This method is called during change of active player, which happens in some weird place especially during &amp;quot;multipleactiveplayer&amp;quot; states. If you pulling your hair thinking why its &amp;quot;undefined&amp;quot; on js side - check the current state.&lt;br /&gt;
&lt;br /&gt;
==== Private info in args ====&lt;br /&gt;
&lt;br /&gt;
By default, all data provided through this method are PUBLIC TO ALL PLAYERS. Please do not send any private data with this method, as a cheater could see it even it is not used explicitly by the game interface logic.&lt;br /&gt;
&lt;br /&gt;
However, it is possible to specify that some data should be sent to specific players only.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note: You cannot use Example 1 and Example 2 together. If you have to send private args to multiple players, use Example 2.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Example 1: send information to active player(s) only:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    function argPlayerTurn()  {&lt;br /&gt;
        return array(&lt;br /&gt;
            &#039;_private&#039; =&amp;gt; array(          // Using &amp;quot;_private&amp;quot; keyword, all data inside this array will be made private&lt;br /&gt;
                &#039;active&#039; =&amp;gt; array(       // Using &amp;quot;active&amp;quot; keyword inside &amp;quot;_private&amp;quot;, you select active player(s)&lt;br /&gt;
                    &#039;somePrivateData&#039; =&amp;gt; self::getSomePrivateData()   // will be send only to active player(s)&lt;br /&gt;
                )&lt;br /&gt;
            ),&lt;br /&gt;
            &#039;possibleMoves&#039; =&amp;gt; self::getPossibleMoves()          // will be sent to all players&lt;br /&gt;
        );&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Inside the js file, these variables will be available through `args.args._private`. (e.g. `args.args._private.somePrivateData` -- it is not `args._private.active.somePrivateData` nor is it `args.somePrivateData`)&lt;br /&gt;
&lt;br /&gt;
Example 2: send information to a specific player (&amp;lt;specific_player_id&amp;gt;) only:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    function argPlayerTurn()  {&lt;br /&gt;
        $specific_player_id = ...; // calculate some-how&lt;br /&gt;
        return array(&lt;br /&gt;
            &#039;_private&#039; =&amp;gt; array(   // all data inside this array will be private&lt;br /&gt;
                $specific_player_id =&amp;gt; array(   // will be sent only to that player   &lt;br /&gt;
                    &#039;somePrivateData&#039; =&amp;gt; self::getSomePrivateData()   &lt;br /&gt;
                )&lt;br /&gt;
            ),&lt;br /&gt;
&lt;br /&gt;
            &#039;possibleMoves&#039; =&amp;gt; self::getPossibleMoves()   // will be sent to all players&lt;br /&gt;
        );&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
IMPORTANT: in certain situations (i.e. &amp;quot;multipleactiveplayer&amp;quot; game state) these &amp;quot;private data&amp;quot; features can have a significant impact on performance. Please do not use if not needed.&lt;br /&gt;
&lt;br /&gt;
It is also possible to use these private args in the &amp;quot;description&amp;quot; messages, like &amp;quot;${you} have to play ${_private.count} cards&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
==== Translations in args ====&lt;br /&gt;
You can do the same as in notification by adding i18n parameter, i.e&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function argPlayerTurn()  {&lt;br /&gt;
 return [&lt;br /&gt;
      &#039;i18n&#039; =&amp;gt; [&#039;terrainName&#039; ],&lt;br /&gt;
      &#039;terrainName&#039; =&amp;gt; ($this-&amp;gt;token_types[$terrain][&#039;name&#039;]), // this should be defined in material.inc.php and with clienttranslate &lt;br /&gt;
      &#039;terrain&#039; =&amp;gt; $terrain,&lt;br /&gt;
   ];&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Than you can do something like this in state:&lt;br /&gt;
  &amp;quot;descriptionmyturn&amp;quot; =&amp;gt; clienttranslate(&#039;${you} must place a house on ${terrainName}&#039;),&lt;br /&gt;
&lt;br /&gt;
See more in [[Translations]]&lt;br /&gt;
&lt;br /&gt;
=== updateGameProgression ===&lt;br /&gt;
&lt;br /&gt;
(optional)&lt;br /&gt;
&lt;br /&gt;
If you specify &amp;quot;updateGameProgression =&amp;gt; true&amp;quot; in a game state, your &amp;quot;getGameProgression&amp;quot; PHP method will be called at the beginning of this game state - and thus the game progression of the game will be updated.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;At least one&#039;&#039; of your game states (any one) must specify &amp;quot;updateGameProgression=&amp;gt;true&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== initialprivate ===&lt;br /&gt;
&lt;br /&gt;
(optional)&lt;br /&gt;
&lt;br /&gt;
This parameter will enable private parallel states in a multiplayer state. Parameter should be set to first private parallel state a player will be transitioned to.&lt;br /&gt;
See more details about Private parallel states [[#Private_parallel_states|here]].&lt;br /&gt;
&lt;br /&gt;
== Implementation Notes ==&lt;br /&gt;
&lt;br /&gt;
=== Private parallel states ===&lt;br /&gt;
&lt;br /&gt;
Private parallel states are useful when multiple players are active and their turn is very complex. In that case it is possible with parallel states for each player to be in a independent state. &lt;br /&gt;
&lt;br /&gt;
Lets say that players need to do three complex action one after another in multiactive state. With parallel states each player can independently be in a different state (i.e. one player still need to decide about first action while some players are deciding their second action and the fastest player is already on their third action. Normally this can be handled with two simple, but limited, approaches:&lt;br /&gt;
&lt;br /&gt;
* Moving all players to different states together - this is limiting for faster players as they need to wait other players for each separate action. The more problematic thing is that it would be hard to implement an undo feature when one player wants to change their previous action. In that case all players should be moved back to previous state which will interrupt their flow.&lt;br /&gt;
* Using client states, by changing the state in which the player is in javascript - the problem with this approach is that players will lose their progress on browser refresh (F5). Furthermore the validation logic of specific actions should be implemented on both server side and client side and we cannot have specific args for each different action, but they should be calculated only at the beginning of the first action and possibly calculated on client side after each action, which again duplicates logic on client and server.&lt;br /&gt;
&lt;br /&gt;
With private parallel states, each specific action can be implemented as a parallel state. Parallel states are defined with the type &#039;private&#039; and players are moved to those private states during one master multiactive state. Lets look at the example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    10 =&amp;gt; [&lt;br /&gt;
        &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;playerTurn&amp;quot;,&lt;br /&gt;
        &amp;quot;description&amp;quot; =&amp;gt; clienttranslate(&#039;Waiting for other players to end their turn.&#039;),&lt;br /&gt;
        &amp;quot;descriptionmyturn&amp;quot; =&amp;gt; clienttranslate(&#039;${you} must do your turn&#039;), // Won&#039;t be displayed anyway since each private state has its own description&lt;br /&gt;
        &amp;quot;type&amp;quot; =&amp;gt; &amp;quot;multipleactiveplayer&amp;quot;,&lt;br /&gt;
        &amp;quot;initialprivate&amp;quot; =&amp;gt; 50, // This makes this state a master multiactive state and enables private states, this is also a first private state&lt;br /&gt;
        &amp;quot;action&amp;quot; =&amp;gt; &amp;quot;stPlayerTurn&amp;quot;,&lt;br /&gt;
        &amp;quot;args&amp;quot; =&amp;gt; &amp;quot;argPlayerTurn&amp;quot;,&lt;br /&gt;
        &amp;quot;possibleactions&amp;quot; =&amp;gt; [&amp;quot;changeMind&amp;quot;], //this action is possible if player is not in any private state which usually happens when they are inactive&lt;br /&gt;
        &amp;quot;transitions&amp;quot; =&amp;gt; [&amp;quot;playersDecide&amp;quot; =&amp;gt; 11] // this is normal next transition which will happen after all players finish their turns &lt;br /&gt;
    ],&lt;br /&gt;
&lt;br /&gt;
    50 =&amp;gt; [&lt;br /&gt;
        &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;chooseFirst&amp;quot;,&lt;br /&gt;
        &amp;quot;descriptionmyturn&amp;quot; =&amp;gt; clienttranslate(&#039;${you} must make your first choice&#039;), // just this parameter is needed. description is not needed as no player is inactive in this state&lt;br /&gt;
        &amp;quot;type&amp;quot; =&amp;gt; &amp;quot;private&amp;quot;, // this state is reachable only as a private state&lt;br /&gt;
        &amp;quot;args&amp;quot; =&amp;gt; &amp;quot;argChooseFirst&amp;quot;, //this method will be called with playerId as a parametar and is used to calculate arguments for this action for specific player&lt;br /&gt;
        &amp;quot;action&amp;quot; =&amp;gt; &amp;quot;stChooseFirst&amp;quot;, // this method will be called with playerId as a parameter and can be used to make some changes when player enters this private state&lt;br /&gt;
        &amp;quot;possibleactions&amp;quot; =&amp;gt; [&amp;quot;toSecond&amp;quot;],&lt;br /&gt;
        &amp;quot;transitions&amp;quot; =&amp;gt; [&lt;br /&gt;
          &#039;chooseSecond&#039; =&amp;gt; 51, // transition to another private state&lt;br /&gt;
        ]&lt;br /&gt;
      ],&lt;br /&gt;
   &lt;br /&gt;
    51 =&amp;gt; [&lt;br /&gt;
        &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;chooseSecond&amp;quot;,&lt;br /&gt;
        &amp;quot;descriptionmyturn&amp;quot; =&amp;gt; clienttranslate(&#039;${you} must make your second choice&#039;),&lt;br /&gt;
        &amp;quot;type&amp;quot; =&amp;gt; &amp;quot;private&amp;quot;,&lt;br /&gt;
        &amp;quot;args&amp;quot; =&amp;gt; &amp;quot;argChooseSecond&amp;quot;,&lt;br /&gt;
        &amp;quot;possibleactions&amp;quot; =&amp;gt; [&amp;quot;finish&amp;quot;, &amp;quot;back&amp;quot;],&lt;br /&gt;
        &amp;quot;transitions&amp;quot; =&amp;gt; [&lt;br /&gt;
          &#039;back&#039; =&amp;gt; 50,&lt;br /&gt;
        ]&lt;br /&gt;
      ],&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When entering the master state it is usually useful to set some players as multiactive and initialize their private state:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    function stPlayerTurn() {&lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;setAllPlayersMultiactive();&lt;br /&gt;
        &lt;br /&gt;
        //this is needed when starting private parallel states; players will be transitioned to initialprivate state defined in master state&lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;initializePrivateStateForAllActivePlayers(); &lt;br /&gt;
&lt;br /&gt;
        // in some cases you can move immediately some or all players to different private states&lt;br /&gt;
        if ($someCondition) {&lt;br /&gt;
            //move all players to different state &lt;br /&gt;
            $this-&amp;gt;gamestate-&amp;gt;nextPrivateStateForAllActivePlayers(&amp;quot;chooseSecond&amp;quot;);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if ($other condition) {&lt;br /&gt;
            //move single player to different state&lt;br /&gt;
            $this-&amp;gt;gamestate-&amp;gt;nextPrivateState($specificPlayerId, &amp;quot;chooseSecond&amp;quot;);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When some action is done by a player, you can move them to the next private state:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    function toSecond() {&lt;br /&gt;
        $this-&amp;gt;checkAction(&amp;quot;toSecond&amp;quot;);  //the action must be defined in private state; actions defined in master state are not possible&lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;nextPrivateState($this-&amp;gt;getCurrentPlayerId(), &amp;quot;chooseSecond&amp;quot;); //moving current player to different state&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Please check the detailed API [[Main_game_logic:_yourgamename.game.php#Private_parallel_states|here]].&lt;br /&gt;
&lt;br /&gt;
=== Client States ===&lt;br /&gt;
Client state almost have nothing to do with server states, except they can simulate same experience without actually changing server states.&lt;br /&gt;
&lt;br /&gt;
See description here: https://en.doc.boardgamearena.com/BGA_Studio_Cookbook#Multi_Step_Interactions:_Select_Worker.2FPlace_Worker_-_Using_Client_States&lt;br /&gt;
&lt;br /&gt;
In many cases you can achive similar results by using client states vs private server states. The only caviat - when using client states during multiactive server state&lt;br /&gt;
other player will trigger state changes (multiactive player set) which will call onUpdateActionButtons. Some measures have to be taken to preserve client state in this case.&lt;br /&gt;
&lt;br /&gt;
=== Using Named Constants for States ===&lt;br /&gt;
&lt;br /&gt;
Using numeric constants is prone to errors. If you want you can declare state constants as PHP named constants. This way you can&lt;br /&gt;
use them in the states file and in game.php as well&lt;br /&gt;
&lt;br /&gt;
EXAMPLE:&lt;br /&gt;
&lt;br /&gt;
states.inc.php:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// define contants for state ids&lt;br /&gt;
if (!defined(&#039;STATE_END_GAME&#039;)) { // ensure this block is only invoked once, since it is included multiple times&lt;br /&gt;
   define(&amp;quot;STATE_PLAYER_TURN&amp;quot;, 2);&lt;br /&gt;
   define(&amp;quot;STATE_GAME_TURN&amp;quot;, 3);&lt;br /&gt;
   define(&amp;quot;STATE_PLAYER_TURN_CUBES&amp;quot;, 4);&lt;br /&gt;
   define(&amp;quot;STATE_END_GAME&amp;quot;, 99);&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
$machinestates = array(&lt;br /&gt;
&lt;br /&gt;
   ...&lt;br /&gt;
&lt;br /&gt;
    STATE_PLAYER_TURN =&amp;gt; array(&lt;br /&gt;
    		&amp;quot;name&amp;quot; =&amp;gt; &amp;quot;playerTurn&amp;quot;,&lt;br /&gt;
    		&amp;quot;description&amp;quot; =&amp;gt; clienttranslate(&#039;${actplayer} must select an Action Space or Pass&#039;),&lt;br /&gt;
    		&amp;quot;descriptionmyturn&amp;quot; =&amp;gt; clienttranslate(&#039;${you} must select an Action Space or Pass&#039;),&lt;br /&gt;
    		&amp;quot;type&amp;quot; =&amp;gt; &amp;quot;activeplayer&amp;quot;,&lt;br /&gt;
                &amp;quot;args&amp;quot; =&amp;gt; &#039;arg_playerTurn&#039;,&lt;br /&gt;
    		&amp;quot;possibleactions&amp;quot; =&amp;gt; array( &amp;quot;selectWorkerAction&amp;quot;, &amp;quot;pass&amp;quot; ),&lt;br /&gt;
    		&amp;quot;transitions&amp;quot; =&amp;gt; array( &lt;br /&gt;
    		        &amp;quot;loopback&amp;quot; =&amp;gt; STATE_PLAYER_TURN,&lt;br /&gt;
    		        &amp;quot;playCubes&amp;quot; =&amp;gt; STATE_PLAYER_TURN_CUBES,&lt;br /&gt;
    		        &amp;quot;pass&amp;quot; =&amp;gt; STATE_GAME_TURN )&lt;br /&gt;
    ),&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Example of multipleactiveplayer state ===&lt;br /&gt;
&lt;br /&gt;
This is an example of a multipleactiveplayer state:&lt;br /&gt;
&lt;br /&gt;
  2 =&amp;gt;  array (&lt;br /&gt;
    &#039;name&#039; =&amp;gt; &#039;playerTurnSetup&#039;,&lt;br /&gt;
    &#039;type&#039; =&amp;gt; &#039;multipleactiveplayer&#039;,&lt;br /&gt;
    &#039;description&#039; =&amp;gt; clienttranslate(&#039;Other players must choose one Objective&#039;),&lt;br /&gt;
    &#039;descriptionmyturn&#039; =&amp;gt; clienttranslate(&#039;${you} must choose one Objective card to keep&#039;),&lt;br /&gt;
    &#039;possibleactions&#039; =&amp;gt;     array (&#039;playKeep&#039; ),&lt;br /&gt;
    &#039;transitions&#039; =&amp;gt;    array (       &#039;next&#039; =&amp;gt; 5, &#039;loopback&#039; =&amp;gt; 2, ),&lt;br /&gt;
    &#039;action&#039; =&amp;gt; &#039;st_MultiPlayerInit&#039;,&lt;br /&gt;
    &#039;args&#039; =&amp;gt; &#039;arg_playerTurnSetup&#039;,&lt;br /&gt;
  ),&lt;br /&gt;
&lt;br /&gt;
In game.php:&lt;br /&gt;
    // this will make all players multiactive just before entering the state&lt;br /&gt;
    function st_MultiPlayerInit() {&lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;setAllPlayersMultiactive();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Note: if you want exact this function its already defined in table class its called &#039;stMakeEveryoneActive&#039;&lt;br /&gt;
&lt;br /&gt;
When ending the player action, instead of a state transition, deactivate player.&lt;br /&gt;
&lt;br /&gt;
    function action_playKeep($cardId) {&lt;br /&gt;
        $this-&amp;gt;checkAction(&#039;playKeep&#039;);&lt;br /&gt;
        $player_id = $this-&amp;gt;getCurrentPlayerId(); // CURRENT!!! not active&lt;br /&gt;
        ... // some logic here&lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;setPlayerNonMultiactive($player_id, &#039;next&#039;); // deactivate player; if none left, transition to &#039;next&#039; state&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
=== Difference between Single active and Multi active states ===&lt;br /&gt;
In a classic &amp;quot;activePlayer&amp;quot; state:&lt;br /&gt;
&lt;br /&gt;
* You cannot change the active player DURING the state. This is to ensure that during 1 activePlayer state, only ONE player is active&lt;br /&gt;
* As a consequence, you must set the active player BEFORE entering the activePlayer state&lt;br /&gt;
* In such states on JS side onUpdateActionButtons is called before onEnteringState during game play (but after during reload, i.e. F5)&lt;br /&gt;
* Finally, during onEnteringState, on JS side, the active player is signaled as active and the information is reliable and usable.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In a &amp;quot;multiplePlayer&amp;quot; state:&lt;br /&gt;
&lt;br /&gt;
* You can (and must) change the active players DURING the state&lt;br /&gt;
* During such a state, players can be activated/desactivated anytime during the state, giving you the maximum of possibilities.&lt;br /&gt;
* You shouldn&#039;t set active player before entering the state. But you can set it in &amp;quot;state initializer&amp;quot; php function (see example above st_MultiPlayerInit)&lt;br /&gt;
* Finally, during onEnteringState, on JS side, the active players are NOT active yet so you must use onUpdateActionButtons to perform the client side operation which depends on a player active/inactive status.&lt;br /&gt;
&lt;br /&gt;
Note: in some off cases other players can perform special actions even if they are not active, see example https://en.doc.boardgamearena.com/BGA_Studio_Cookbook#Out-of-turn_actions%3A_Un-pass. Do not abuse this technique!&lt;br /&gt;
&lt;br /&gt;
=== Designing states ===&lt;br /&gt;
&lt;br /&gt;
As a general rule you state machine should resemble &amp;quot;round/turn overview&amp;quot; from the game rule-book. Normally if book say its player turn and player can do multiple things during their turn it is still only&lt;br /&gt;
one player state (plus a game to switch player), not muliple states.&lt;br /&gt;
&lt;br /&gt;
In a classic game (i.e. chess), there is only active player at any time, so it is simple playerTurn/gameTurn sequence and you only need 2 states.&lt;br /&gt;
&lt;br /&gt;
[[File:Simplestates.png]]&lt;br /&gt;
&lt;br /&gt;
In complex euro game there can be multiple rounds, and each round have phases which can be distinctly unique, i.e. in first phase everybody draws card and discard (multi-player), then player have one turn each (single-active), then another is resolution of actions from players and some of them may become active again, then there is round upkeep/reset. This would require one multi-player state for phase 1, pair of states for phase2 (singel-active + game), pair of states for phase3 and finally round-end/unkeep game state.&lt;br /&gt;
&lt;br /&gt;
For pair of active player/game states you can make player state first, which transitions to game state, or the other way around, you start with game state which transition to active player state, its loop in any case but depends on how you want to do &amp;quot;phase&amp;quot; initiazations.&lt;br /&gt;
&lt;br /&gt;
[[File:Eurogamestates.png]]&lt;br /&gt;
&lt;br /&gt;
=== Complete examples ===&lt;br /&gt;
&lt;br /&gt;
Example of simple game where player take turns&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if ( !defined(&#039;STATE_END_GAME&#039;)) { // guard since this included multiple times&lt;br /&gt;
    define(&amp;quot;STATE_PLAYER_TURN&amp;quot;, 2);&lt;br /&gt;
    define(&amp;quot;STATE_GAME_TURN_NEXT_PLAYER&amp;quot;, 3);&lt;br /&gt;
    define(&amp;quot;STATE_PLAYER_GAME_END&amp;quot;, 4);&lt;br /&gt;
    define(&amp;quot;STATE_END_GAME&amp;quot;, 99);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$machinestates = [    &lt;br /&gt;
        1 =&amp;gt; [ // The initial state. Please do not modify.&lt;br /&gt;
               &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;gameSetup&amp;quot;,&lt;br /&gt;
               &amp;quot;description&amp;quot; =&amp;gt; &amp;quot;&amp;quot;,&lt;br /&gt;
               &amp;quot;type&amp;quot; =&amp;gt; &amp;quot;manager&amp;quot;,&lt;br /&gt;
               &amp;quot;action&amp;quot; =&amp;gt; &amp;quot;stGameSetup&amp;quot;,&lt;br /&gt;
               &amp;quot;transitions&amp;quot; =&amp;gt; [ &amp;quot;&amp;quot; =&amp;gt; STATE_PLAYER_TURN ] ],&lt;br /&gt;
        // Game states &lt;br /&gt;
        STATE_PLAYER_TURN =&amp;gt; [ // main active player state &lt;br /&gt;
                &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;playerTurn&amp;quot;,&lt;br /&gt;
                &amp;quot;description&amp;quot; =&amp;gt; clienttranslate(&#039;${actplayer} must do something or pass&#039;),&lt;br /&gt;
                &amp;quot;descriptionmyturn&amp;quot; =&amp;gt; clienttranslate(&#039;${you} must do something or pass&#039;),&lt;br /&gt;
                &amp;quot;type&amp;quot; =&amp;gt; &amp;quot;activeplayer&amp;quot;,&lt;br /&gt;
                &amp;quot;args&amp;quot; =&amp;gt; &amp;quot;arg_playerTurn&amp;quot;,&lt;br /&gt;
                &amp;quot;possibleactions&amp;quot; =&amp;gt; [ &amp;quot;dosomething&amp;quot;,&amp;quot;pass&amp;quot; ],&lt;br /&gt;
                &amp;quot;transitions&amp;quot; =&amp;gt; [ &amp;quot;next&amp;quot; =&amp;gt; STATE_GAME_TURN_NEXT_PLAYER,&amp;quot;last&amp;quot; =&amp;gt; STATE_PLAYER_GAME_END ] // &lt;br /&gt;
        ],&lt;br /&gt;
        STATE_GAME_TURN_NEXT_PLAYER =&amp;gt; [ // next player state&lt;br /&gt;
                &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;gameTurnNextPlayer&amp;quot;,&lt;br /&gt;
                &amp;quot;description&amp;quot; =&amp;gt; clienttranslate(&#039;Upkeep...&#039;),&lt;br /&gt;
                &amp;quot;type&amp;quot; =&amp;gt; &amp;quot;game&amp;quot;, //&lt;br /&gt;
                &amp;quot;action&amp;quot; =&amp;gt; &amp;quot;st_gameTurnNextPlayer&amp;quot;, //&lt;br /&gt;
                &amp;quot;updateGameProgression&amp;quot; =&amp;gt; true,&lt;br /&gt;
                &amp;quot;transitions&amp;quot; =&amp;gt; [ &amp;quot;next&amp;quot; =&amp;gt; STATE_PLAYER_TURN,&amp;quot;loopback&amp;quot; =&amp;gt; STATE_GAME_TURN_NEXT_PLAYER,&lt;br /&gt;
                        &amp;quot;last&amp;quot; =&amp;gt; STATE_PLAYER_GAME_END ], // TODO replace with STATE_END_GAME, its there to use undo/restore during dev&lt;br /&gt;
        ],&lt;br /&gt;
    &lt;br /&gt;
        STATE_PLAYER_GAME_END =&amp;gt; [ // active player state for debugging end of game&lt;br /&gt;
                &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;playerGameEnd&amp;quot;,&lt;br /&gt;
                &amp;quot;description&amp;quot; =&amp;gt; clienttranslate(&#039;${actplayer} Game Over&#039;),&lt;br /&gt;
                &amp;quot;descriptionmyturn&amp;quot; =&amp;gt; clienttranslate(&#039;${you} Game Over&#039;),&lt;br /&gt;
                &amp;quot;type&amp;quot; =&amp;gt; &amp;quot;activeplayer&amp;quot;,&lt;br /&gt;
                &amp;quot;args&amp;quot; =&amp;gt; &amp;quot;arg_playerTurn&amp;quot;,&lt;br /&gt;
                &amp;quot;possibleactions&amp;quot; =&amp;gt; [&amp;quot;endGame&amp;quot;],&lt;br /&gt;
                &amp;quot;transitions&amp;quot; =&amp;gt; [&amp;quot;next&amp;quot; =&amp;gt; STATE_END_GAME,&amp;quot;loopback&amp;quot; =&amp;gt; STATE_PLAYER_GAME_END ] // &lt;br /&gt;
        ],&lt;br /&gt;
        // End of Game states &lt;br /&gt;
        // Final state.&lt;br /&gt;
        // Please do not modify (and do not overload action/args methods).&lt;br /&gt;
        STATE_END_GAME =&amp;gt; [&lt;br /&gt;
                &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;gameEnd&amp;quot;,&lt;br /&gt;
                &amp;quot;description&amp;quot; =&amp;gt; clienttranslate(&amp;quot;End of game&amp;quot;),&amp;quot;type&amp;quot; =&amp;gt; &amp;quot;manager&amp;quot;,&lt;br /&gt;
                &amp;quot;action&amp;quot; =&amp;gt; &amp;quot;stGameEnd&amp;quot;,&lt;br /&gt;
                &amp;quot;args&amp;quot; =&amp;gt; &amp;quot;argGameEnd&amp;quot; ] &lt;br /&gt;
&lt;br /&gt;
];&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:Studio]]&lt;/div&gt;</summary>
		<author><name>Archduke</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=BGA_Studio_Guidelines&amp;diff=18035</id>
		<title>BGA Studio Guidelines</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=BGA_Studio_Guidelines&amp;diff=18035"/>
		<updated>2023-09-13T13:17:39Z</updated>

		<summary type="html">&lt;p&gt;Archduke: /* IV-8 Namespace recommendations */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Studio_Framework_Navigation}}&lt;br /&gt;
&lt;br /&gt;
= BGA Studio Guidelines = &lt;br /&gt;
&lt;br /&gt;
Originally From: https://www.slideshare.net/boardgamearena/bga-studio-guidelines&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Why guidelines? ==&lt;br /&gt;
More and more game publishers are choosing Board Game Arena for their game adaptations because the quality of these adaptations is high.&lt;br /&gt;
If we want to continue to have nice games in the future, we have to make sure that every game published in the BGA platform is matching the quality standards of BGA.&lt;br /&gt;
These guidelines are here to help you to make your game easy to use by BGA players, and to make sure its going to be validated by the game publisher.&lt;br /&gt;
&lt;br /&gt;
== General guidelines == &lt;br /&gt;
The 3 main important guidelines &lt;br /&gt;
* If a player knows the real board game, they should be able to play your adaptation with no learning.&lt;br /&gt;
* Fidelity to the original game is an absolute requirement.&lt;br /&gt;
* Don&#039;t try to create a video game: make your game interface as close as possible to how the original board game looks like.&lt;br /&gt;
&lt;br /&gt;
== Game layout  ==&lt;br /&gt;
=== I-1 Don&#039;t hide game elements ===&lt;br /&gt;
&lt;br /&gt;
Many board games have a lot of material to display, and computer screens are sometimes too small.&lt;br /&gt;
But you are lucky: your game will be on a webpage with a scrolling functionality. &lt;br /&gt;
Basically, you always have some more space available .&lt;br /&gt;
Don&#039;t hide game elements behind menus, submenus, dialogs, etc, but display them directly on the main page.&lt;br /&gt;
&lt;br /&gt;
Tips: eventually, you can use HTML anchor link to jump between the different elements of the page if the page height is very big. &lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&lt;br /&gt;
In Amyitis, characters cards are elements you don&#039;t have to check all the time. Thus, we placed them at the bottom of the page  and you have to scroll to see them.&lt;br /&gt;
&lt;br /&gt;
In Madeira, additional game board are shown at the bottom, but when player needs to use it it moved up.&lt;br /&gt;
&lt;br /&gt;
Rule: &lt;br /&gt;
* If real game has visible elements on the table it should be visible on the main screen or user mini boards on the right&lt;br /&gt;
&lt;br /&gt;
Exceptions:&lt;br /&gt;
* Showing counts of same elements is sufficient&lt;br /&gt;
* For decks which can be inspected it permitted to show them on demand&lt;br /&gt;
* If some games you can cut off score track and replace with BGA scoring (stars), but keeping it will look nicer (but you have to keep track of score on it as well)&lt;br /&gt;
* Its not necessary to show helper cards such as turn overview or scoring overview. It is nice if you can incorporate that as well, but in most cases, &#039;&#039;&#039;such elements should not be displayed by default&#039;&#039;&#039; (as space should be given in priority to the game itself), and should be made available by &#039;&#039;&#039;a gray &amp;quot;Player aid&amp;quot; button (or help icon)&#039;&#039;&#039; displaying a popup when clicked, like for example in Marco Polo or Terra Mystica.&lt;br /&gt;
&lt;br /&gt;
=== I-2 Make it fluid ===&lt;br /&gt;
&lt;br /&gt;
BGA game interface is «fluid». It means the interface width can vary in order to use extra space on the screen when available.&lt;br /&gt;
HTML and CSS give us a lot of possibilities to adapt a web content to a given browser width.&lt;br /&gt;
You have to use HTML and CSS:&lt;br /&gt;
* To allow players owning a big screen to enjoy the game comfortably without scrolling the page.&lt;br /&gt;
* To allow players with a screen of just 1024px &lt;br /&gt;
&lt;br /&gt;
Tips: for each element of the game, answer this question « how many times during a game do I need to check/use this element? ».Less frequently used elements can be placed below.&lt;br /&gt;
You can listen on display resize in JS to do more sophisticated layouts.&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&lt;br /&gt;
Caylus: when we have a 1024px small width to play the game – even if they have to screen, available buildings are placed scroll on the the right and below the board.&lt;br /&gt;
On larger screen, these tiles are placed   on the right of the board.  This is a very basic usage of the others. « float:left » CSS property.&lt;br /&gt;
&lt;br /&gt;
=== I-3 Use whiteblocks ===&lt;br /&gt;
White blocks are &#039;&#039;&#039;div&#039;&#039;&#039; HTML element with the &#039;&#039;&#039;whiteblock&#039;&#039;&#039; class (white and transparent background). This is the recommended way to gather game elements together in your game interface when they are not directly on a board. Whiteblocks helps you to organize the space in order it can be easily understood by players.&lt;br /&gt;
&lt;br /&gt;
If game contains individual player boards with distinct colors or marking you don&#039;t need these boards inside the whiteblock.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Tips: you can use a &#039;&#039;&#039;h3&#039;&#039;&#039; title inside the whiteblock to help players to understand what is inside or to who it belongs.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
In The Year of the Dragon game interface, with whiteblocks and h3 titles /picture here/&lt;br /&gt;
&lt;br /&gt;
=== I-4 Use player panels ===&lt;br /&gt;
&lt;br /&gt;
BGA players are used to look at player panels when they need an information about a player.&lt;br /&gt;
Using player panels can allow you to save a lot of space on the main game space. In general, the following information is placed in the player panel:&lt;br /&gt;
* Players resources (i.e.  small game elements the player is keeping in front of him in the real game).&lt;br /&gt;
* Summary information about player (i.e. number of cards in hand, number of cards played...).&lt;br /&gt;
* « First player » token.&lt;br /&gt;
* Score. &lt;br /&gt;
&lt;br /&gt;
Player panels in Seasons. /picture/ A lot of useful information can fit into these small spaces :)&lt;br /&gt;
&lt;br /&gt;
Note: for all games, you must always use the standard BGA score counter (with the star). Players are used to check this counter to see who is winning the game.&lt;br /&gt;
&lt;br /&gt;
=== I-5 Use status bar actions ===&lt;br /&gt;
&lt;br /&gt;
When some game action is particular to a specific game state, the good practice is to use a status bar action (HTML link).&lt;br /&gt;
Don&#039;t try to place some icon in your main gameinterface that will be useless 95% of the time: it takes space and makes the interface more complex to understand. &lt;br /&gt;
&lt;br /&gt;
Status bar actions in Tobago /picture/&lt;br /&gt;
&lt;br /&gt;
== Game usability  ==&lt;br /&gt;
&lt;br /&gt;
=== II-1 Use tooltips ===&lt;br /&gt;
&lt;br /&gt;
With BGA Studio its very easy to associate a tooltip on any element of the game. Each time this is possible: add a tooltip to explain to the players:&lt;br /&gt;
* What is this game element?&lt;br /&gt;
* What happens if I click on it?&lt;br /&gt;
However, tooltips should NOT be used to display dynamic information about the current game to save space on the game interface. &lt;br /&gt;
Typically, regular players should be able to play with no tooltips. &lt;br /&gt;
However you can display some dynamic stuff if it&#039;s available otherwise but just annoying to calculate. For example in Lewis and Clark author asked to put&lt;br /&gt;
tooltips of how many river space available ahead of explorer.&lt;br /&gt;
If you need to show user why they cannot interact with element show errors instead (when clicking on it).&lt;br /&gt;
&lt;br /&gt;
Tips: you can place any HTML element in tooltips. So you can make them as rich and beautiful as you need :)&lt;br /&gt;
&lt;br /&gt;
=== II-2 Use left click only ===&lt;br /&gt;
* The whole game should be playable with only simple left button mouse click.&lt;br /&gt;
* Context menus should not be used.&lt;br /&gt;
* Drag-n-drop should be avoided (if you want to use it anyway, you should make a click based alternative available).&lt;br /&gt;
* Mouse icon must change on clickable elements (« cursor:pointer » CSS property). &lt;br /&gt;
&lt;br /&gt;
=== II-3 Make your interface intuitive ===&lt;br /&gt;
If your testers have different opinions about « how to trigger some game action », maybe &lt;br /&gt;
the best is to make several options possible for this game action. In the case there is a complex action to do by the player (ex: select some cards, then click on an action button), design your error messages in order they can guide the player(ex : « please select some cards first »).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Tips: For complex games, it is simple and useful to  highlight the area of the interface where player should focus his attention (using onEnteringState/onLeavingState and CSS class, i.e. &#039;active_slot&#039;).&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
The Boss: when a player clicks on a card with no selected cubes, the interface tells us to select some cube first.&lt;br /&gt;
&lt;br /&gt;
=== II-4 Use the gamelog ===&lt;br /&gt;
With BGA Studio it is very easy to place sometext (or HTML code) in the gamelog.&lt;br /&gt;
Don&#039;t hesitate to use the game log.&lt;br /&gt;
Players are not always in front of the game page when their opponents are making their moves.&lt;br /&gt;
In addition, the computer manipulates game elements faster than you usually do with the real board game and even regular players can get behind of what happened sometimes.&lt;br /&gt;
You should be able to understand the « game story » by reading the game log. &lt;br /&gt;
&lt;br /&gt;
=== II-5 Tell players about automatic actions ===&lt;br /&gt;
Very often, during a game you are in a situation where:&lt;br /&gt;
* Only one action is possible for the activeplayer, or&lt;br /&gt;
* A series of action has to be done (according to the rules) without any players actions.&lt;br /&gt;
In these situation, you must or you may trigger these actions automatically.&lt;br /&gt;
In any case, you must make sure that players understand what is happening, otherwise they will probably report a bug. &lt;br /&gt;
&lt;br /&gt;
Stone Age: people are fed  automatically at the end of the turn, but players can always see what happened exactly in the gamelog.&lt;br /&gt;
&lt;br /&gt;
* Use the game log to trace all actions performed automatically. &lt;br /&gt;
* Use synchronous notifications handlers to slow down the execution of automatic actions,so that players can understand what is happening.&lt;br /&gt;
=== II-6 Avoid move confirmations ===&lt;br /&gt;
As a rule of thumb, don&#039;t require move confirmation. Confirming a move slows down the user interface and thus, the game flow. You can allow a player to confirm a move if this is a very critical step in a game, and if it is possible to trigger an action by accident. If client interactions are very complex and allow cancellation, the final move can be confirmed with a &amp;quot;Done&amp;quot; button.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Hawaii&#039;&#039;: Ending a turn is a critical action that happens only 5 times per player in a game. In this case, it is acceptable (and a good idea) to have a confirmation dialog.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Hive&#039;&#039;: Each move has to be confirmed with click on the location because it is very easy to click by accident.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Russian Railroads&#039;&#039;: Each move involves multiple interactions and can contains dozens of subactions. When the player is done &amp;quot;planning&amp;quot; they presses a &amp;quot;Done&amp;quot; button to submit the move to the server.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Race for the Galaxy&#039;&#039;: There is a card that allows players to draw two cards and discard one card before the Development phase. This requires confirmation when the player selects a development card to discard, as they often means to build that development card instead.&lt;br /&gt;
&lt;br /&gt;
=== II-7 Translatable interface ===&lt;br /&gt;
With BGA Studio its very easy to translate your game in any language, using BGA collaborative translation system. Check the FAQ and the example games to learn how to declare your strings so that every message in your code can be managed by the internationalization system. &lt;br /&gt;
&lt;br /&gt;
Diams 100 % translated in Polish&lt;br /&gt;
&lt;br /&gt;
=== II-8 Use interactive elements ===&lt;br /&gt;
&lt;br /&gt;
Interactive elements are tiles, cubes or board areas user can click on to perform an action. The following guidance apply:&lt;br /&gt;
* If user click on interactive element either action happens or user get a error message. Try to process error message of client side and not send to server for simple errors, such as player is not active. Please be very specific why user cannot interact with element, i.e.&lt;br /&gt;
** This is not your turn&lt;br /&gt;
** You cannot build this building because you don&#039;t have enough resources&lt;br /&gt;
** To select this card you have to select resource first&lt;br /&gt;
If you cannot make errors for all elements at least tooltip should explaining when it interactive vs not&lt;br /&gt;
&lt;br /&gt;
Rule: Every game element should give an explicit error message if clicked at the wrong moment rather than staying silent&lt;br /&gt;
&lt;br /&gt;
Rule: When user can click on element during this turn it should be highlighted if possible (or non-active element de-highlighted in some way)&lt;br /&gt;
&lt;br /&gt;
Hightlighting guidelines:&lt;br /&gt;
* Apply a class to all active/selectable element, i.e. class can be &amp;quot;selectable&amp;quot;, &amp;quot;active_slot&amp;quot;, &amp;quot;interactive&amp;quot;&lt;br /&gt;
* An CSS element with this class can have special rules, i.e&lt;br /&gt;
** outline (use outline, do not use &amp;quot;border&amp;quot; as this changes sizing)&lt;br /&gt;
** OR shadow/glow - use box-shadow or filter: drop-shadow for non-standard tokens&lt;br /&gt;
** recommended color - white, yellow or blue. Do not use red - this is indication of error rather than prompt for action&lt;br /&gt;
** change mouse cursor to action cursor, i.e. cursor: pointer&lt;br /&gt;
&lt;br /&gt;
De-highlighting guidelines:&lt;br /&gt;
* Only use this strategy when there are less inactive element than active&lt;br /&gt;
* Apply a class to all non-interactive element, such as &amp;quot;non-interactive&amp;quot;&lt;br /&gt;
* In css set special rules&lt;br /&gt;
** opacity:0.7 &lt;br /&gt;
** OR filter:contrast(0.6) or grayscale&lt;br /&gt;
* change cursor, i.e. cursor: not-allowed&lt;br /&gt;
&lt;br /&gt;
Rule: If state prompt replaces the interaction with element but elements are visible its better to do both (i.e. can select a button OR they can move element on the board)&lt;br /&gt;
** Example: In Lewis &amp;amp; Clark game offers gain resources via buttons on state prompt, but user can also click on cubes in supply to do the same action&lt;br /&gt;
&lt;br /&gt;
=== II-9 Animate moving elements ===&lt;br /&gt;
If real game have some elements moving during the game it should also animate in your adaptation&lt;br /&gt;
* User gets a resource - move a resource from main board to user mini board&lt;br /&gt;
* User buys a card - move card from main display to user board&lt;br /&gt;
* User draw a card which is revealed on the display - move card from deck to display, maybe add flippy animation to turn it face up (that requires 3d transformations - that is bonus)&lt;br /&gt;
&lt;br /&gt;
It is also nice to animation points or coin collection from specific region of the board (even points collection is not normally visible).&lt;br /&gt;
&lt;br /&gt;
Don&#039;t need to overdo animation - its not first player shooter&lt;br /&gt;
&lt;br /&gt;
=== II-10 Slow down the end of game scoring ===&lt;br /&gt;
&lt;br /&gt;
This is the climax of the game, building up suspense before revealing the winner... Don&#039;t make it too quick! :)&lt;br /&gt;
&lt;br /&gt;
It&#039;s also very helpful if some end of game scoring animations can show where the points are gained, to help players understand (and trust) the scoring.&lt;br /&gt;
&lt;br /&gt;
To achieve this, you can use synchronous notifications for each step of the scoring to slow down the process, and use this.displayScoring ([[Game_interface_logic:_yourgamename.js#Scoring_animated_display]]) to display a nice points animation in the color of the player over the element of the game granting points for this step of the scoring.&lt;br /&gt;
&lt;br /&gt;
For a practical example of a game adaptation where scoring has been done with this idea in mind, you can check a game replay of Terra Mystica for the final scoring (this link will fast forward you right there: [https://boardgamearena.com/archive/replay/200901-1002/?table=112192856&amp;amp;player=84819187&amp;amp;comments=426;&amp;amp;goto=341 replay scoring])&lt;br /&gt;
&lt;br /&gt;
== Original game representation ==&lt;br /&gt;
=== III-1 Use the original art===&lt;br /&gt;
The less you are modifying the original art of the game, the better.&lt;br /&gt;
Its important for publishers that a board game adaptation looks like the real board game. Sometimes it can be useful to modify some elements of the game to save some space on the screen – but try to avoid it.&lt;br /&gt;
Tips: if you have not enough space on the screen, reduce the size of the game elements. &lt;br /&gt;
Try to make sure they are recognizable for players who played regularly, and add a tooltip to help beginners to figure out what they are. &lt;br /&gt;
Gosu : the original cards are used,  with tooltips.&lt;br /&gt;
&lt;br /&gt;
=== III-2 Be careful about player assistance ===&lt;br /&gt;
As a rule of thumb, in order to respect the original board games, you should not introduce any player assistance feature.&lt;br /&gt;
An assistance must not be introduced if it directly helps the player to figure out if his move is good or bad.&lt;br /&gt;
An assistance may be introduced if it can help the player to figure out what moves are available.&lt;br /&gt;
 &lt;br /&gt;
Gygès: the assistance shows you available moves, but is not alerting you about stupid moves (like the upper left one).&lt;br /&gt;
&lt;br /&gt;
Note: You can however do a single choice move for a player, i.e passing on a turn if there is nothing a user can do; It&#039;s quite annoying to wait on a player to pass, while it&#039;s the only action that they can do anyways.&lt;br /&gt;
&lt;br /&gt;
=== III-3 Cancel a move ===&lt;br /&gt;
Most players want to have moves cancelled or undone. Use the following rules to implement it:&lt;br /&gt;
* If any information is revealed which was not known before the action is completed - You CANNOT cancel it.&lt;br /&gt;
* If this is the end of active player action - You CANNOT cancel it&lt;br /&gt;
* If during a player&#039;s turn multiple actions are required but don&#039;t violate the above two rules - You CAN cancel/undo it. i.e. A user picks cubes and drops on a building. Selecting the cubes and building -  are two actions, so user should be able to cancel taking cube.&lt;br /&gt;
This can be implemented using client side states, so cancelling is easy by restoring last server state.&lt;br /&gt;
&lt;br /&gt;
=== III-4 Available information ===&lt;br /&gt;
Every information visible by players in the real game should be accessible in the adaptation. Pay attention to some information like the number of cards in the opponents hand, or the number of remaining cards in the deck. &lt;br /&gt;
If it is explicitly forbidden to count cards in the discard pile, this information is not available.&lt;br /&gt;
&lt;br /&gt;
== Game technical quality ==&lt;br /&gt;
=== IV-1 Don&#039;t use exotic stuff ===&lt;br /&gt;
BGA Studio provides a set of useful tools to build board games adaptations (i.e. card management, confirmation dialog, tooltips,…).&lt;br /&gt;
Use them, and don&#039;t use exotic libraries, plugins or tricks.&lt;br /&gt;
Why? Because BGA Framework will evolve in the future to provide new features to players, and it could make your game incompatible with the new version.&lt;br /&gt;
On the contrary, if you are using standard Haggis using BGA standard card stuff, you will enjoy these enhancements without any effort.&lt;br /&gt;
If you feel that you really need some exotic thing: don&#039;t hesitate to ask us.&lt;br /&gt;
&lt;br /&gt;
=== IV-2 Make sure you can use what you use ===&lt;br /&gt;
&lt;br /&gt;
In particular, do not build your game on top of a technical library without checking that licensing allows you (and BGA) to use it.&lt;br /&gt;
If you use a library, make sure first that its license is really open (MIT style). Otherwise, we may have to ask you to rework your code to use another library.&lt;br /&gt;
In general, please consider that it&#039;s always better to minimize dependencies, so if you can avoid using external libraries, all the better.&lt;br /&gt;
&lt;br /&gt;
=== IV-3 Write in (simple) English ===&lt;br /&gt;
Some other person may have to look at your code, such as:&lt;br /&gt;
* We (the BGA team), who are here to help you if you need us.&lt;br /&gt;
* Some other BGA developer wanting to help you.&lt;br /&gt;
For all these reasons, your code must be written in English (variables, methods, comments...).&lt;br /&gt;
If English is not your mother tongue don&#039;t be afraid: the whole idea here is to be understood, not to write an essay :)&lt;br /&gt;
&lt;br /&gt;
=== IV-4 Page refresh ===&lt;br /&gt;
A page refresh (F5) must allow players to reset the game interface to a stable state at any moment of the game.&lt;br /&gt;
BGA Studio framework allows you to do this with the « getAllDatas » PHP method and the « setup » Javascript method.&lt;br /&gt;
Note: this « refresh » feature is also quite useful during the development process:)&lt;br /&gt;
&lt;br /&gt;
=== IV-5 Private information ===&lt;br /&gt;
A private game element must be visible only to the player owning it. It must not be visible by his opponents, by any means.&lt;br /&gt;
In particular: &lt;br /&gt;
* getAllDatas PHP method must not return any element that are hidden from current player, even if the Javascript « setup » method ignores them.&lt;br /&gt;
* you must not send via the « notifyAllPlayers » function some information that is hidden from one player (use « notifyPlayer » instead). &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Hearts: each player is alerted about his new cards using notifyPlayer, and cards from the other players remains secret&lt;br /&gt;
&lt;br /&gt;
=== IV-6 Game progression ===&lt;br /&gt;
Game progression should be as accurate as possible.&lt;br /&gt;
Of course, its not always easy (or even possible) to compute game progression, but a vague approximation is better than nothing. &lt;br /&gt;
Stone Age: there are 2 different end game conditions (building cards and civilization  cards). &lt;br /&gt;
Both are taken into account to  increase the accuracy of the game  progression.&lt;br /&gt;
&lt;br /&gt;
=== IV-7 Game statistics ===&lt;br /&gt;
Using BGA Studio you can define a set of statistics for your game. Statistics will be displayed at the end of the game, and help players to figure out why they win/lose a game, &lt;br /&gt;
and what they should improve. Try to choose interesting statistics that distinguish the different strategies for your game, in order it can help players to understand their game. &lt;br /&gt;
&lt;br /&gt;
Seasons : statistics&lt;br /&gt;
&lt;br /&gt;
=== IV-8 Namespace recommendations ===&lt;br /&gt;
Your game is not working in complete isolation, it&#039;s included in a page with a lot of elements around (header, footer, logs, chat, player panels, rankings...)&lt;br /&gt;
&lt;br /&gt;
So you should pay attention to naming your DOM elements, CSS classes and PHP constants / classes in a way specific to your game in order to avoid namespace collisions (for example you use a selector for a &amp;quot;selected&amp;quot; class in your .js, and there is also an element of the framework outside of your game with a selected class).&lt;br /&gt;
&lt;br /&gt;
It&#039;s recommended to have:&lt;br /&gt;
* a wrapper div around your game zone with an id specific to your game (&#039;yourgamename_playzone&#039; for example) and to use it in any xpath selector of your .js&lt;br /&gt;
* a prefix for example a trigram for your game that you append to all the css classes of your game (&#039;yrg_selected&#039; for example).&lt;br /&gt;
* a prefix or a namespace for your PHP constants or classes.&lt;br /&gt;
&lt;br /&gt;
Even if everything is working fine today, otherwise your game may break in the future when the framework is updated.&lt;br /&gt;
&lt;br /&gt;
You should not use any global variables (window scope) in your Javascript files. If you need something to be accessible globally, then you should use &amp;lt;code&amp;gt;window.gameui&amp;lt;/code&amp;gt;. You could even make a &amp;lt;code&amp;gt;window.gameui.globals = {}&amp;lt;/code&amp;gt; object to contain any global variables.&lt;br /&gt;
&lt;br /&gt;
== Summary ==&lt;br /&gt;
These guidelines are here to help you to make sure that the players, the game publisher and the game author are going to enjoy your adaptation of the game. We created these guidelines based on our personal experience (which includes many mistakes along the way) implementing a lot of games on BGA platform. Don&#039;t hesitate to contact us if you feel uncomfortable with one of these guidelines in some particular context with your game: these guidelines are here to help and not to prevent you to do smart things, and have fun while programing your game ;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Studio]]&lt;/div&gt;</summary>
		<author><name>Archduke</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Logos_for_printing&amp;diff=17651</id>
		<title>Logos for printing</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Logos_for_printing&amp;diff=17651"/>
		<updated>2023-07-25T18:39:00Z</updated>

		<summary type="html">&lt;p&gt;Archduke: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Board Game Arena logos for printing purposes.&lt;br /&gt;
&lt;br /&gt;
For partnerships and events, you can find there the files and rules on how to use the BGA logo and it&#039;s assets.&lt;br /&gt;
&lt;br /&gt;
For online logos and other assets, find them on this page : [[Logos]]&lt;br /&gt;
&lt;br /&gt;
== Logo and lines ==&lt;br /&gt;
&lt;br /&gt;
==== Presentation of the full vertical version ====&lt;br /&gt;
[[File:BGA logos.jpg|left|thumb|300x300px]]&lt;br /&gt;
&lt;br /&gt;
For full-color prints/supports, the Board Game Arena logo is reproduced in four-color positive (BGA gradient) only.&lt;br /&gt;
&lt;br /&gt;
For plain background colors matching any parts of the original gradient, the all-white version should be used.&lt;br /&gt;
&lt;br /&gt;
For color composition, please refer to the corresponding page.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear: both;&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Protected Areas ====&lt;br /&gt;
[[File:Save space.jpg|left|thumb]]The Board Game Arena logo may be used within the protection zone.&lt;br /&gt;
&lt;br /&gt;
The minimum space is represented by the height and width (shaft) of the bottom-left graphic element.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Exceptions: if the height/width of the protection zone is restricted, the minimum space can be reduced to half the height/width of the graphic element.&lt;br /&gt;
&lt;br /&gt;
The full vertical version of the logo is the prefered one to be used for all needs (Print/Web/etc...).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear: both;&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Logo variations: ====&lt;br /&gt;
[[File:Exemple of both logos.jpg|left|thumb|Logo with a written baseline / Logo with a QR code included.]]&lt;br /&gt;
We offer 2 variations for simple logo display on boxes and rulebooks, the all-use logo print.&lt;br /&gt;
&lt;br /&gt;
The horizontal one offers a text only version which you can change the baseline text, while the vertical one offers a QRcode space to display and to be scanned by users.&lt;br /&gt;
&lt;br /&gt;
The choice is your, but you shouldn&#039;t display both of them in the same page/display space (different box sides or pages are ok)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear: both;&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== The different BGA logos ==&lt;br /&gt;
Depending on your display goals, there&#039;s different sizes and version of the logo you can use. Please refer to these informations whenever you want to promote your BGA version on your games, whether it&#039;s on the box, or in the rules (or anywhere else).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Having a BGA logo or QR code on your box, rules or anywhere helps players find informations about it online.&lt;br /&gt;
&lt;br /&gt;
- Have it on your box sides to lead to your online version of the game directly, helping people try the game or play the tutorial to learn more about the game.&lt;br /&gt;
&lt;br /&gt;
- Have it displayed on your rulebook so once users played it they can find more players to play online or to learn the game in another way.&lt;br /&gt;
&lt;br /&gt;
Note that we provide a lot of informations on our pages about games, and that it&#039;s best for you to check if all languages / informations / packshots are up to date, so users would also find the latest informations about the game.&lt;br /&gt;
&lt;br /&gt;
Don&#039;t hesitate to ask us if there&#039;s any issues.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Printing a BGA logo on board game boxes ==&lt;br /&gt;
If your game is available (or soon to be) on Board Game Arena, you can use these files to add awareness and promotion about your game being playable on our plaform right from the shelves.&lt;br /&gt;
&lt;br /&gt;
If your game is NOT already available on Board Game Arena, you can check this page or send us a message about how to make the best of both worlds (printed games and virtual ones).&lt;br /&gt;
&lt;br /&gt;
Note that now that QR codes are quite common, it&#039;s better for you to use this specific version so users don&#039;t have to type anything to find your game online.&lt;br /&gt;
&lt;br /&gt;
=== Box examples ===&lt;br /&gt;
Depending on your box size/ratio, there&#039;s a few options you can use to display the BGA logo as well as the QR codes which would lead directly to your game page.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== The vertical box ====&lt;br /&gt;
[[File:Verticalbox example.jpg|left|thumb]]&lt;br /&gt;
&lt;br /&gt;
Depending on the orientation of the box art and way it should be displayed on shelves, we recommend not to display the BGA logos/QR codes on the front face.&lt;br /&gt;
&lt;br /&gt;
For the sides, you can use different display versions to fit your needs. We strongly recommend to use as little space as possible, and to have the long horizontal one on the tallest sides, while using the tallest ones on the horizontally-oriented spaces.&lt;br /&gt;
&lt;br /&gt;
Bottom position/Right positions are prefered.&lt;br /&gt;
&lt;br /&gt;
White background should be used on most cases, but you can use the variation to fit your box artwork.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Note that for boxes having a side of less than 3cm width, we don&#039;t recommend using the box sides but the box back.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear: both;&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== The horizontal box ====&lt;br /&gt;
[[File:Horizontalboxexample.jpg|left|thumb]]Placement on horizontal-shaped boxes should be on right and bottom preferably, using our files.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear: both;&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Generate a QR code for your game page on BGA: ==&lt;br /&gt;
In order to generate the right logo file and QR code, here is a few guidelines to help you do it effortlessly:&lt;br /&gt;
*Check twice your game page URL (Which should look like [https://boardgamearena.com/gamepanel?game=bunnykingdom https://boardgamearena.com/gamepanel?game=GAMENAME]) OR you can also ask for a tracked short url by contacting us.&lt;br /&gt;
*We use preferably QR codes generated from online websites (note that ADOBE offer this tool there https://express.adobe.com/fr-FR/tools/qr-code-generator, or this one https://www.the-qrcode-generator.com/ (entierely free) with the SIMPLE GRID eyes or rounded ones (eyes being the rounded shapes on the corners, see below for the screenshot example)[[File:QR code eyes.jpg|thumb|GRID EYES are styling option we would love to prefer, but you can use any QR code generator with regular rectangular shapes.]]Check twice about the offer you&#039;re using : some are paid and don&#039;t allow more than a few scan.&lt;br /&gt;
*Once generated, download an SVG version and remove the white parts so you can apply our gradient on your QR code, using Photoshop.&lt;br /&gt;
*&#039;&#039;&#039;You can download the QR code sample file for Photoshop (PSD) right here:&#039;&#039;&#039; https://drive.google.com/file/d/1TDkdqUVtAjsZqJ45LuTp0-zqytk5vPXp/view?usp=sharing&lt;br /&gt;
*Check with a phone that the code can be scanner (open camera app and point it to the QR code. If any links appears, click to check if it works properly.&lt;br /&gt;
*[[File:Alternative.jpg|thumb|Visuel de QR code carré utilisé comme alternative.]]Import to your printing files.  File is provided as an example if you want to have an immediate recognition by users, but you can do any derivatives that would be a better fit for your brand if you feel the need to.  WHITE Background is mandatory as it allows better scanning results.  An height of a minimum of 2cms (for the QR code only) is mandatory to offer the best scanning results. Don&#039;t hesitate to print a sample to check the size before production.[[File:Effect.jpg|thumb|On our PSD file, you&#039;ll be able to find layers to apply effects or change the text depending on the language you&#039;ll be using.Take care to use the same gradients and sizings!]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If you don&#039;t have enough vertical space for the QR code display, or for some horizontal placement, you can use the horizontal BGA banner that you can download directly here (Photoshop PSD) :&lt;br /&gt;
&lt;br /&gt;
https://drive.google.com/file/d/1u-NDvzoK27UIxTomlZxZpvNMBBO8bI9e/view?usp=sharing&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
You can customize the bottom line using your own link details, and change the color contrast accordingly.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
NOTE that on a white background, you don&#039;t need to import the white rounded frame we provide.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear: both;&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Printing a BGA logo on rulebooks ==&lt;br /&gt;
Next to the mandatory logos you can have on the last page of your rules, you can add on the bottom right the same icons we have displayed here.&lt;br /&gt;
&lt;br /&gt;
They&#039;re the exact same files that you can fit.&lt;br /&gt;
&lt;br /&gt;
Note that a bigger QR code also implies a user scanning from a farther distance than a smaller one, and that a code being too small will not be scanned properly.&lt;br /&gt;
&lt;br /&gt;
So we recommend to keep the QR code between 2cm height (QR Code zone only) up to 8cm height maximum.&lt;br /&gt;
&lt;br /&gt;
Here is an example of what can be done:[[File:Last rule page.jpg|left|thumb|Last page display example. Note that the code can be as big as needed.]]&lt;/div&gt;</summary>
		<author><name>Archduke</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=BGA_Studio_Cookbook&amp;diff=17492</id>
		<title>BGA Studio Cookbook</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=BGA_Studio_Cookbook&amp;diff=17492"/>
		<updated>2023-07-18T08:16:48Z</updated>

		<summary type="html">&lt;p&gt;Archduke: /* Irregular Shapes */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
&lt;br /&gt;
This page is a cookbook of design and implementation recipes for BGA Studio framework.&lt;br /&gt;
For tooling and usage recipes see [[Tools and tips of BGA Studio]].&lt;br /&gt;
If you have your own recipes feel free to edit this page.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
== Visual Effects, Layout and Animation ==&lt;br /&gt;
&lt;br /&gt;
=== DOM manipulatons ===&lt;br /&gt;
&lt;br /&gt;
==== Create pieces dynamically (using template) ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg_ggg.tpl, ggg.js&lt;br /&gt;
&lt;br /&gt;
Note: this method is recommended by BGA guildlines&lt;br /&gt;
&lt;br /&gt;
Declared js template with variables in .tpl file, like this&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;script type=&amp;quot;text/javascript&amp;quot;&amp;gt;&lt;br /&gt;
    // Javascript HTML templates&lt;br /&gt;
    var jstpl_ipiece = &#039;&amp;lt;div class=&amp;quot;${type} ${type}_${color} inlineblock&amp;quot; aria-label=&amp;quot;${name}&amp;quot; title=&amp;quot;${name}&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&amp;lt;/script&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Use it like this in .js file&lt;br /&gt;
  div = this.format_block(&#039;jstpl_ipiece&#039;, {&lt;br /&gt;
                                type : &#039;meeple&#039;,&lt;br /&gt;
                                color : &#039;ff0000&#039;,&lt;br /&gt;
                                name : &#039;Bob&#039;,&lt;br /&gt;
                            });&lt;br /&gt;
  &lt;br /&gt;
Then you do whatever you need to do with that div, this one specifically design to go to log entries, because it has embedded title (otherwise its a picture only) and no id.&lt;br /&gt;
&lt;br /&gt;
Note: you could have place this variable in js itself, but keeping it in .tpl allows you to have your js code be free of HTML. Normally it never happens but&lt;br /&gt;
it is good to strive for it.&lt;br /&gt;
Note: you can also use string concatenation, its less readable. You can also use dojo dom object creation api&#039;s but its brutally verbose and its more unreadable.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Create pieces dynamically (using string concatenation) ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg.js&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  div = &amp;quot;&amp;lt;div class=&#039;meeple_&amp;quot;+color+&amp;quot;&#039;&amp;gt;&amp;lt;/div&amp;gt;&amp;quot;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
or modern way&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  div = `&amp;lt;div class=&#039;meeple_${color}&#039;&amp;gt;&amp;lt;/div&amp;gt;`;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Create all pieces statically ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg_ggg.tpl, ggg.css, ggg.view.php (optional) &lt;br /&gt;
&lt;br /&gt;
* Create ALL game pieces in html template (.tpl)&lt;br /&gt;
* ALL pieces should have unique id, and it should be meaningful, i.e. meeple_red_1&lt;br /&gt;
* Do not use inline styling&lt;br /&gt;
* Id of player&#039;s specific pieces should use some sort of &#039;color&#039; identification, since player id cannot be used in static layout, you can use english color name, hex 6 char value, or color &amp;quot;number&amp;quot; (1,2,3...)&lt;br /&gt;
* Pieces should have separated class for its color, type, etc, so it can be easily styled in groups. In example below you now can style all meeples, all red meeples or all red tokens, or all &amp;quot;first&amp;quot; meeples&lt;br /&gt;
&lt;br /&gt;
ggg.tpl:&lt;br /&gt;
&amp;lt;pre&amp;gt; &lt;br /&gt;
  &amp;lt;div id=&amp;quot;home_red&amp;quot; class=&amp;quot;home_red home&amp;quot;&amp;gt;&lt;br /&gt;
     &amp;lt;div id=&amp;quot;meeple_red_1&amp;quot; class=&amp;quot;meeple red n1&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
     &amp;lt;div id=&amp;quot;meeple_red_2&amp;quot; class=&amp;quot;meeple red n2&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
  &amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ggg.css:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
.meeple {&lt;br /&gt;
	width: 32px;&lt;br /&gt;
	height: 39px;&lt;br /&gt;
	background-image: url(img/78_64_stand_meeples.png);&lt;br /&gt;
	background-size: 352px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.meeple.red {&lt;br /&gt;
	background-position: 30% 0%;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* There should be straight forward mapping between server id and js id (or 1:1)&lt;br /&gt;
* You place objects in different zones of the layout, and setup css to take care of layout&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
.home .meeple{&lt;br /&gt;
   display: inline-block;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* If you need to have a temporary object that look like original you can use dojo.clone (and change id to some temp id)&lt;br /&gt;
* If there is lots of repetition or zone grid you can use template generator, but inject style declaration in css instead of inline style for flexibility&lt;br /&gt;
&lt;br /&gt;
Note:&lt;br /&gt;
* If you use this model you cannot use premade js components such as Stock and Zone&lt;br /&gt;
* You have to use alternative methods of animation (slightly altered) since default method will leave object with inline style attributes which you don&#039;t need&lt;br /&gt;
&lt;br /&gt;
=== Animation ===&lt;br /&gt;
&lt;br /&gt;
==== Attach to new parent without destroying the object ====&lt;br /&gt;
&lt;br /&gt;
BGA function attachToNewParent for some reason destroys the original, if you want similar function that does not you can use this&lt;br /&gt;
ggg.js&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        /**&lt;br /&gt;
         * This method will attach mobile to a new_parent without destroying, unlike original attachToNewParent which destroys mobile and&lt;br /&gt;
         * all its connectors (onClick, etc)&lt;br /&gt;
         */&lt;br /&gt;
        attachToNewParentNoDestroy: function (mobile_in, new_parent_in, relation, place_position) {&lt;br /&gt;
&lt;br /&gt;
            const mobile = $(mobile_in);&lt;br /&gt;
            const new_parent = $(new_parent_in);&lt;br /&gt;
&lt;br /&gt;
            var src = dojo.position(mobile);&lt;br /&gt;
            if (place_position)&lt;br /&gt;
                mobile.style.position = place_position;&lt;br /&gt;
            dojo.place(mobile, new_parent, relation);&lt;br /&gt;
            mobile.offsetTop;//force re-flow&lt;br /&gt;
            var tgt = dojo.position(mobile);&lt;br /&gt;
            var box = dojo.marginBox(mobile);&lt;br /&gt;
            var cbox = dojo.contentBox(mobile);&lt;br /&gt;
            var left = box.l + src.x - tgt.x;&lt;br /&gt;
            var top = box.t + src.y - tgt.y;&lt;br /&gt;
&lt;br /&gt;
            mobile.style.position = &amp;quot;absolute&amp;quot;;&lt;br /&gt;
            mobile.style.left = left + &amp;quot;px&amp;quot;;&lt;br /&gt;
            mobile.style.top = top + &amp;quot;px&amp;quot;;&lt;br /&gt;
            box.l += box.w - cbox.w;&lt;br /&gt;
            box.t += box.h - cbox.h;&lt;br /&gt;
            mobile.offsetTop;//force re-flow&lt;br /&gt;
            return box;&lt;br /&gt;
        },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Animation on oversurface ====&lt;br /&gt;
If you use non-absolute position for your game elements (i.e you use layouts) - you cannot really use BGA animation functions. After years of fidding with different options I use&lt;br /&gt;
techique which I call animation on oversurface that works when parents use different zoom, rotation, etc&lt;br /&gt;
&lt;br /&gt;
* You need another layer on top of everything - oversurface&lt;br /&gt;
* We create copy of the object on oversurface - to move&lt;br /&gt;
* We move the real object on final position - but make it invisible for now&lt;br /&gt;
* We move the phantom to final position applying required zoom and rotation (using css animation), then destroy it&lt;br /&gt;
* When animation is done we make original object visible in new position&lt;br /&gt;
&lt;br /&gt;
The code is bit complex it can be found here&lt;br /&gt;
&lt;br /&gt;
https://codepen.io/VictoriaLa/pen/gORvdJo&lt;br /&gt;
&lt;br /&gt;
Game using it: century, ultimaterailroads&lt;br /&gt;
&lt;br /&gt;
==== Scroll element into view ====&lt;br /&gt;
Ingredients: game.js&lt;br /&gt;
&lt;br /&gt;
This function will scroll given node (div) into view and respect replays and archive mode&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    scrollIntoViewAfter: function (node, delay) {&lt;br /&gt;
      if (this.instantaneousMode || this.inSetup) {&lt;br /&gt;
        return;&lt;br /&gt;
      }&lt;br /&gt;
      if (typeof g_replayFrom != &amp;quot;undefined&amp;quot;) {&lt;br /&gt;
        $(node).scrollIntoView();&lt;br /&gt;
        return;&lt;br /&gt;
      }&lt;br /&gt;
      if (!delay) delay = 0;&lt;br /&gt;
      setTimeout(() =&amp;gt; {&lt;br /&gt;
        $(node).scrollIntoView({ behavior: &amp;quot;smooth&amp;quot;, block: &amp;quot;center&amp;quot; });&lt;br /&gt;
      }, delay);&lt;br /&gt;
    },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Logs ===&lt;br /&gt;
&lt;br /&gt;
==== Inject icon images in the log ====&lt;br /&gt;
&lt;br /&gt;
Here is an example of what was done for Terra Mystica which is simple and straightforward:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
//Define the proper message&lt;br /&gt;
		$message = clienttranslate(&#039;${player_name} gets ${power_income} via Structures&#039;);&lt;br /&gt;
		if ($price &amp;gt; 0) {&lt;br /&gt;
			self::DbQuery(&amp;quot;UPDATE player SET player_score = player_score - $price WHERE player_id = $player_id&amp;quot;);&lt;br /&gt;
			$message = clienttranslate(&#039;${player_name} pays ${vp_price} and gets ${power_income} via Structures&#039;);&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
// Notify&lt;br /&gt;
		self::notifyAllPlayers( &amp;quot;powerViaStructures&amp;quot;, $message, array(&lt;br /&gt;
			&#039;i18n&#039; =&amp;gt; array( ),&lt;br /&gt;
			&#039;player_id&#039; =&amp;gt; $player_id,&lt;br /&gt;
			&#039;player_name&#039; =&amp;gt; self::getUniqueValueFromDb( &amp;quot;SELECT player_name FROM player WHERE player_id = $player_id&amp;quot; ),&lt;br /&gt;
			&#039;power_tokens&#039; =&amp;gt; $power_tokens,&lt;br /&gt;
			&#039;vp_price&#039; =&amp;gt; self::getLogsVPAmount($price),&lt;br /&gt;
			&#039;power_income&#039; =&amp;gt; self::getLogsPowerAmount($power_income),&lt;br /&gt;
			&#039;newScore&#039; =&amp;gt; self::getUniqueValueFromDb( &amp;quot;SELECT player_score FROM player WHERE player_id = $player_id&amp;quot; ),&lt;br /&gt;
			&#039;counters&#039; =&amp;gt; $this-&amp;gt;getGameCounters(null),&lt;br /&gt;
		) );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With some functions to have the needed html added inside the substitution variable, such as:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function getLogsPowerAmount( $amount ) {&lt;br /&gt;
		return &amp;quot;&amp;lt;div class=&#039;tmlogs_icon&#039; title=&#039;Power&#039;&amp;gt;&amp;lt;div class=&#039;power_amount&#039;&amp;gt;$amount&amp;lt;/div&amp;gt;&amp;lt;/div&amp;gt;&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Note: injecting html from php is not ideal but easy, if you want more clean solution, use method below but it is a lot more sophisticated.&lt;br /&gt;
&lt;br /&gt;
==== Inject images and styled html in the log ====&lt;br /&gt;
&lt;br /&gt;
{{InfoBox|title=Warning — Translation|maxWidth=500|topLeftColour=#c00|middleColour=#c00|bottomRightColour=#c00|body=&#039;&#039;&#039;In order to prevent interference with the translation process, keep in mind that you must only apply modifications to the args object, and not try to substitute the keys (the &amp;lt;code&amp;gt;${player_name}&amp;lt;/code&amp;gt; parts of your string) in the log string.&#039;&#039;&#039;}}&lt;br /&gt;
&lt;br /&gt;
So you want nice pictures in the game log. What do you do? The first idea that comes to mind is to send html from php in notifications (see method above). &lt;br /&gt;
&lt;br /&gt;
This is a bad idea for many reasons:&lt;br /&gt;
&lt;br /&gt;
* It&#039;s bad architecture. ui elements leak into the server, and now you have to manage the ui in multiple places.&lt;br /&gt;
* If you decided to change something in the ui in future version, replay logs for old games and tutorials may not work, since they use stored notifications.&lt;br /&gt;
* Log previews for old games become unreadable. (This is the log state before you enter the game replay, which is useful for troubleshooting and game analysis.)&lt;br /&gt;
* It&#039;s more data to transfer and store in the db.&lt;br /&gt;
* It&#039;s a nightmare for translators.&lt;br /&gt;
&lt;br /&gt;
So what else can you do? You can use client side log injection to intercept log arguments (which come from the server) and replace them with html on the client side. Here are three different method you can use to achieve this.&lt;br /&gt;
&lt;br /&gt;
===== First way : Override &amp;lt;code&amp;gt;this.format_string_recursive()&amp;lt;/code&amp;gt; method =====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg.js, ggg.game.php&lt;br /&gt;
&lt;br /&gt;
I use this recipe for &#039;&#039;&#039;client side log injection&#039;&#039;&#039; to intercept log arguments (which come from the server) and replace them with html on the client side.&lt;br /&gt;
&lt;br /&gt;
[[File:clientloginjection.png|left]] &lt;br /&gt;
&lt;br /&gt;
ggg.js&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt; &lt;br /&gt;
&lt;br /&gt;
        /** Override this function to inject html into log items. This is a built-in BGA method.  */&lt;br /&gt;
&lt;br /&gt;
        /* @Override */&lt;br /&gt;
        format_string_recursive : function format_string_recursive(log, args) {&lt;br /&gt;
            try {&lt;br /&gt;
                if (log &amp;amp;&amp;amp; args &amp;amp;&amp;amp; !args.processed) {&lt;br /&gt;
                    args.processed = true;&lt;br /&gt;
                    &lt;br /&gt;
&lt;br /&gt;
                    // list of special keys we want to replace with images&lt;br /&gt;
                    var keys = [&#039;place_name&#039;,&#039;token_name&#039;];&lt;br /&gt;
                    &lt;br /&gt;
                  &lt;br /&gt;
                    for ( var i in keys) {&lt;br /&gt;
                        var key = keys[i];&lt;br /&gt;
                        key in args &amp;amp;&amp;amp; args[key] = this.getTokenDiv(key, args);                            &lt;br /&gt;
&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
            } catch (e) {&lt;br /&gt;
                console.error(log,args,&amp;quot;Exception thrown&amp;quot;, e.stack);&lt;br /&gt;
            }&lt;br /&gt;
            return this.inherited({callee: format_string_recursive}, arguments);&lt;br /&gt;
        },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Important:&#039;&#039;&#039; In the &#039;&#039;format_string_recursive&#039;&#039; method, the &#039;args&#039; parameter will only contain arguments passed to it from the notify method in ggg.game.php (see below).&lt;br /&gt;
&lt;br /&gt;
The &#039;log&#039; parameter is the actual string that is inserted into the logs. You can perform additional js string manipulation on it.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        getTokenDiv : function(key, args) {&lt;br /&gt;
            // ... implement whatever html you want here, example from sharedcode.js&lt;br /&gt;
            var token_id = args[key];&lt;br /&gt;
            var item_type = getPart(token_id,0);&lt;br /&gt;
            var logid = &amp;quot;log&amp;quot; + (this.globalid++) + &amp;quot;_&amp;quot; + token_id;&lt;br /&gt;
            switch (item_type) {&lt;br /&gt;
                case &#039;wcube&#039;:&lt;br /&gt;
                    var tokenDiv = this.format_block(&#039;jstpl_resource_log&#039;, {&lt;br /&gt;
                        &amp;quot;id&amp;quot; : logid,&lt;br /&gt;
                        &amp;quot;type&amp;quot; : &amp;quot;wcube&amp;quot;,&lt;br /&gt;
                        &amp;quot;color&amp;quot; : getPart(token_id,1),&lt;br /&gt;
                    });&lt;br /&gt;
                    return tokenDiv;&lt;br /&gt;
             &lt;br /&gt;
                case &#039;meeple&#039;:&lt;br /&gt;
                    if ($(token_id)) {&lt;br /&gt;
                        var clone = dojo.clone($(token_id));&lt;br /&gt;
    &lt;br /&gt;
                        dojo.attr(clone, &amp;quot;id&amp;quot;, logid);&lt;br /&gt;
                        this.stripPosition(clone);&lt;br /&gt;
                        dojo.addClass(clone, &amp;quot;logitem&amp;quot;);&lt;br /&gt;
                        return clone.outerHTML;&lt;br /&gt;
                    }&lt;br /&gt;
                    break;&lt;br /&gt;
     &lt;br /&gt;
                default:&lt;br /&gt;
                    break;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            return &amp;quot;&#039;&amp;quot; + this.clienttranslate_string(this.getTokenName(token_id)) + &amp;quot;&#039;&amp;quot;;&lt;br /&gt;
       },&lt;br /&gt;
       getTokenName : function(key) {&lt;br /&gt;
           return this.gamedatas.token_types[key].name; // get name for the key, from static table for example&lt;br /&gt;
       },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that in this case the server simply injects token_id as a name, and the client substitutes it for the translated name or the picture.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ggg.game.php:&lt;br /&gt;
&lt;br /&gt;
           $this-&amp;gt;notifyAllPlayers(&#039;playerLog&#039;,clienttranslate(&#039;Game moves ${token_name}&#039;),[&#039;token_name&#039;=&amp;gt;$token_id]);&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Important:&#039;&#039;&#039; As noted above, only arguments actually passed by this method are available to the args parameter received in the client-side &#039;&#039;format_string_recursive&#039;&#039; method.&lt;br /&gt;
&lt;br /&gt;
Sometimes it is the case that you want to pass arguments that are not actually included in the output message. For example, suppose we have a method like this:&lt;br /&gt;
&lt;br /&gt;
           $this-&amp;gt;notifyAllPlayers(&#039;tokenPlaced&#039;,clienttranslate(&#039;Player placed ${token_name}&#039;),array(&lt;br /&gt;
              &#039;token_name&#039; =&amp;gt; $token_id,&lt;br /&gt;
              &#039;zone_played&#039; =&amp;gt; $zone);&lt;br /&gt;
&lt;br /&gt;
This will output &amp;quot;Player placed ${token_name}&amp;quot; in the log, and if we subscribe to a notification method activated by the &amp;quot;tokenPlaced&amp;quot; event in the client-side code, that method can make use of the &#039;zone_played&#039; argument. &lt;br /&gt;
&lt;br /&gt;
Now if you want to make some really cool things with game log, most probably you would need more arguments than are included in log message. The problem with that,&lt;br /&gt;
it will work at first, but if you reload game using F5 or when the game loads in turn based mode, you will loose your additional parameters, why? Because when game reloads it does not actually send same notifications, it sends special &amp;quot;hitstorical_log&amp;quot; notification where all  parameters not listed in the message are removed. In example above, field zone_played would be removed from historical log as it is not included in message of the notification. You can till preserve specific arguments in historical log by adding special field preserve to notification arguments like this:&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
           $this-&amp;gt;notifyAllPlayers(&#039;tokenPlaced&#039;,clienttranslate(&#039;Player placed ${token_name}&#039;),array(&lt;br /&gt;
              &#039;token_name&#039; =&amp;gt; $token_id,&lt;br /&gt;
              &#039;zone_played&#039; =&amp;gt; $zone,&lt;br /&gt;
              &#039;preserve&#039; =&amp;gt; [ &#039;zone_played&#039; ]&lt;br /&gt;
           );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now you can use zone_played in format_string_recursive even in historical logs.&lt;br /&gt;
&lt;br /&gt;
===== Second way: rely on the &amp;lt;code&amp;gt;:formatFunction&amp;lt;/code&amp;gt; option provided by &amp;lt;code&amp;gt;dojo.string.substitute&amp;lt;/code&amp;gt; =====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg.js, ggg.game.php, ggg_ggg.tpl, ggg.css&lt;br /&gt;
&lt;br /&gt;
The above method will work in most of the cases, but if you use dotted keys such as &amp;lt;code&amp;gt;${card.name}&amp;lt;/code&amp;gt; (which is supported by the framework, for private state args), the key won&#039;t be substituted because the &amp;lt;code&amp;gt;key in arg&amp;lt;/code&amp;gt; test will fail. If so you need to rely either on this way, or the one after.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;WARNING:&#039;&#039;&#039; using this method on an already advanced project will require you to go through all your notifications to change keys !&lt;br /&gt;
&lt;br /&gt;
Under the hood, the &#039;&#039;&#039;this.format_string_recursive()&#039;&#039;&#039; function calls the &#039;&#039;&#039;dojo.string.substitute&#039;&#039;&#039; method which substitutes &amp;lt;code&amp;gt;${keys}&amp;lt;/code&amp;gt; with the value provided. If you take a look at the [https://dojotoolkit.org/reference-guide/1.7/dojo/string.html#substitute documentation] and [https://github.com/dojo/dojo/blob/c3ceb017cfa25b703f5662dc83d1c8aae9bc5d81/string.js#L163 source code] you can notice that the key can be suffixed with a colon (&amp;lt;code&amp;gt;:&amp;lt;/code&amp;gt;) followed by a function name. This will allow you to specify directly in the substitution string which keys need HTML injection.&lt;br /&gt;
&lt;br /&gt;
First of all, you need to define your formatting function in the ggg.js file:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
[[ggg.js]]&lt;br /&gt;
        getTokenDiv : function(value, key) {&lt;br /&gt;
            //This is only an example implementation, you need to write your own.&lt;br /&gt;
            //The method should return HTML code&lt;br /&gt;
            switch (key) {&lt;br /&gt;
                case &#039;html_injected_argument1&#039;:&lt;br /&gt;
                    return this.format_block(&#039;jstpl_HTMLLogElement1&#039;,{value: value});&lt;br /&gt;
                case &#039;html_injected_argument2&#039;:&lt;br /&gt;
                    return this.format_block(&#039;jstpl_HTMLLogElement2&#039;,{value: value});&lt;br /&gt;
                ...&lt;br /&gt;
            }&lt;br /&gt;
       }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Obviously you need to define the appropriate templates in the ggg_ggg.tpl file:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
[[ggg_ggg.tpl]]&lt;br /&gt;
let jstpl_HTMLLogElement1 = &#039;&amp;lt;div class=&amp;quot;log-element log-element-1-${value}&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
let jstpl_HTMLLogElement2 = &#039;&amp;lt;div class=&amp;quot;log-element log-element-2-${value}&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
And the appropriate classes in ggg.css.&lt;br /&gt;
&lt;br /&gt;
Then you need to add the &amp;lt;code&amp;gt;dojo/aspect&amp;lt;/code&amp;gt; module at the top of the ggg.js file:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;[[ggg.js]]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
 define([&lt;br /&gt;
     &amp;quot;dojo&amp;quot;, &amp;quot;dojo/_base/declare&amp;quot;,&lt;br /&gt;
     &#039;&#039;&#039;&amp;lt;span style=&amp;quot;color:green;&amp;quot;&amp;gt;&amp;quot;dojo/aspect&amp;quot;,&amp;lt;/span&amp;gt;                 //MUST BE IN THIRD POSITION&#039;&#039;&#039; (see [[#Including your own JavaScript module (II)|below]])&lt;br /&gt;
     &amp;quot;ebg/core/gamegui&amp;quot;,&lt;br /&gt;
     &amp;quot;ebg/counter&amp;quot;,&lt;br /&gt;
 ], function (dojo, declare, &amp;lt;span style=&amp;quot;color:green;&amp;quot;&amp;gt;&#039;&#039;&#039;aspect&#039;&#039;&#039;&amp;lt;/span&amp;gt;) {&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
And you also need to add the following code in your &amp;lt;code&amp;gt;contructor&amp;lt;/code&amp;gt; method in the ggg.js:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;[[ggg.js]]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
         constructor: function(){&lt;br /&gt;
             console.log(&#039;progressevolutiontechnologyswh constructor&#039;);&lt;br /&gt;
               &lt;br /&gt;
             // Here, you can init the global variables of your user interface&lt;br /&gt;
             // Example:&lt;br /&gt;
             // this.myGlobalValue = 0;&lt;br /&gt;
             &amp;lt;&#039;&#039;&#039;let gameObject = this;&#039;&#039;&#039;            //Needed as the this object in aspect.before will not refer to the game object in which the formatting function resides&lt;br /&gt;
             &#039;&#039;&#039;aspect.before(dojo.string, &amp;quot;substitute&amp;quot;, function(template, map, transform) {&#039;&#039;&#039;      //This allows you to modify the arguments of the dojo.string.substitute method before they&#039;re actually passed to it&lt;br /&gt;
                 &#039;&#039;&#039;return [template, map, transform, gameObject];&#039;&#039;&#039;&lt;br /&gt;
             &#039;&#039;&#039;});&#039;&#039;&#039;&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now you&#039;re all set to inject HTML in your logs. To actually achieve this, you must specify the function name with the key like so:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;[[ggg.game.php]]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
 $this-&amp;gt;notifyAllPlayers(&amp;quot;notificationName&amp;quot;, clienttranslate(&amp;quot;This log message contains ${plainTextArgument} and the following will receive HTML injection: ${html_injected_argument1:getTokenDiv}&amp;quot;), [&lt;br /&gt;
     &amp;quot;plainTextArgument&amp;quot; =&amp;gt; &amp;quot;some plain text here&amp;quot;,&lt;br /&gt;
     &amp;quot;html_injected_argument1&amp;quot; =&amp;gt; &amp;quot;some value used by getTokenDiv&amp;quot;,&lt;br /&gt;
 ]);&lt;br /&gt;
&lt;br /&gt;
You&#039;re not limited writing only one function, you can write as many functions as you like, and have them each inject a specific type of HTML. You just need to specify the relevant function name after the column in the substitution key.&lt;br /&gt;
&lt;br /&gt;
===== Third way: rely on the &amp;lt;code&amp;gt;transform&amp;lt;/code&amp;gt; argument of &amp;lt;code&amp;gt;dojo.string.substitute&amp;lt;/code&amp;gt; =====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg.js, ggg.game.php, ggg_ggg.tpl, ggg.css&lt;br /&gt;
&lt;br /&gt;
This method is also relying on the use of &amp;lt;code&amp;gt;dojo.string.substitute&amp;lt;/code&amp;gt; by the framework, and will use the &amp;lt;code&amp;gt;transform&amp;lt;/code&amp;gt; argument, which, accordting to [https://github.com/dojo/dojo/blob/c3ceb017cfa25b703f5662dc83d1c8aae9bc5d81/string.js#L163 source code] and [https://dojotoolkit.org/reference-guide/1.7/dojo/string.html#substitute documentation] will be run on all the messages going through dojo.string.substitute.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;WARNING:&#039;&#039;&#039; This method will be applied to all strings that go through dojo.string.substitute. As such you must take extra care not to substitute keys that may be used by the framework (i.e. ${id}). In order to do so, a good practise would be to prefix all keys that need substitution with a trigram of the game name.&lt;br /&gt;
&lt;br /&gt;
Since all the keys will be fed to the tranform function, by default, it must return the value, substituted or not per your needs. You can define the function like this in the ggg.js file:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;[[ggg.js]]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
         getTokenDiv : function(value, key) {&lt;br /&gt;
             //This is only an example implementation, you need to write your own.&lt;br /&gt;
             //The method should return HTML code&lt;br /&gt;
             switch (key) {&lt;br /&gt;
                 case &#039;html_injected_argument1&#039;:&lt;br /&gt;
                     return this.format_block(&#039;jstpl_HTMLLogElement1&#039;,{value: value});&lt;br /&gt;
                 case &#039;html_injected_argument2&#039;:&lt;br /&gt;
                     return this.format_block(&#039;jstpl_HTMLLogElement2&#039;,{value: value});&lt;br /&gt;
                 ...&lt;br /&gt;
                 &amp;lt;&#039;&#039;&#039;default:&#039;&#039;&#039;&lt;br /&gt;
                     &#039;&#039;&#039;return value;&#039;&#039;&#039;&amp;lt;/span&amp;gt;                  &#039;&#039;&#039;//Needed otherwise regular strings won&#039;t appear since since the value isn&#039;t returned by the function&#039;&#039;&#039;&lt;br /&gt;
             }&lt;br /&gt;
         }&lt;br /&gt;
&lt;br /&gt;
The templates must be defined in the ggg_ggg.tpl file and the corresponding CSS classes in the ggg.css file.&lt;br /&gt;
&lt;br /&gt;
You need to add the following code at the beginning of the ggg.js file:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;[[ggg.js]]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
 define([&lt;br /&gt;
     &amp;quot;dojo&amp;quot;, &amp;quot;dojo/_base/declare&amp;quot;,&lt;br /&gt;
     &#039;&#039;&#039;&amp;lt;span style=&amp;quot;color:green;&amp;quot;&amp;gt;&amp;quot;dojo/aspect&amp;quot;,&amp;lt;/span&amp;gt;                 //MUST BE IN THIRD POSITION&#039;&#039;&#039; (see [[#Including your own JavaScript module (II)|below]])&lt;br /&gt;
     &amp;quot;ebg/core/gamegui&amp;quot;,&lt;br /&gt;
     &amp;quot;ebg/counter&amp;quot;,&lt;br /&gt;
 ], function (dojo, declare, &amp;lt;span style=&amp;quot;color:green;&amp;quot;&amp;gt;&#039;&#039;&#039;aspect&#039;&#039;&#039;&amp;lt;/span&amp;gt;) {&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
And the following code to the &amp;lt;code&amp;gt;constructor&amp;lt;/code&amp;gt; method in ggg.js:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;[[ggg.js]]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
         constructor: function(){&lt;br /&gt;
             console.log(&#039;progressevolutiontechnologyswh constructor&#039;);&lt;br /&gt;
               &lt;br /&gt;
             // Here, you can init the global variables of your user interface&lt;br /&gt;
             // Example:&lt;br /&gt;
             // this.myGlobalValue = 0;&lt;br /&gt;
             &amp;lt;&#039;&#039;&#039;let transformFunction = dojo.hitch(this, &amp;quot;getTokenDiv&amp;quot;);&#039;&#039;&#039;            //Needed as the this object in aspect.before will not refer to the game object in which the formatting function resides&lt;br /&gt;
             &#039;&#039;&#039;aspect.before(dojo.string, &amp;quot;substitute&amp;quot;, function(template, map, transform) {&#039;&#039;&#039;&lt;br /&gt;
                 &#039;&#039;&#039;if (undefined === transform) {&#039;&#039;&#039;                                   //Check for a transform function presence, just in case&lt;br /&gt;
                     &#039;&#039;&#039;return [template, map, transformFunction];&#039;&#039;&#039;&lt;br /&gt;
                 &#039;&#039;&#039;}&#039;&#039;&#039;&lt;br /&gt;
             &#039;&#039;&#039;});&#039;&#039;&#039;&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then you&#039;re all set for log injection, no need to change anything on the PHP side.&lt;br /&gt;
&lt;br /&gt;
==== Processing logs on re-loading ====&lt;br /&gt;
&lt;br /&gt;
You rarely need to process logs when reloading, but if you want to do something fancy you may have to do it after logs are loaded. &lt;br /&gt;
Logs are loaded asyncronously so you have to listen for logs to be fully loaded.&lt;br /&gt;
Unfortunately there is no direct way of doing it so this is the hack.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Hack alert&#039;&#039;&#039; - this extends undocumented function and may be broken when framework is updated&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg.js&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
			/*&lt;br /&gt;
  			* [Undocumented] Override BGA framework functions to call onLoadingLogsComplete when loading is done&lt;br /&gt;
                        @Override&lt;br /&gt;
   			*/&lt;br /&gt;
			setLoader: function(image_progress, logs_progress) {&lt;br /&gt;
				this.inherited(arguments); // required, this is &amp;quot;super()&amp;quot; call, do not remove&lt;br /&gt;
				//console.log(&amp;quot;loader&amp;quot;, image_progress, logs_progress)&lt;br /&gt;
				if (!this.isLoadingLogsComplete &amp;amp;&amp;amp; logs_progress &amp;gt;= 100) {&lt;br /&gt;
					this.isLoadingLogsComplete = true; // this is to prevent from calling this more then once&lt;br /&gt;
					this.onLoadingLogsComplete();&lt;br /&gt;
				}&lt;br /&gt;
			},&lt;br /&gt;
&lt;br /&gt;
			onLoadingLogsComplete: function() {&lt;br /&gt;
				console.log(&#039;Loading logs complete&#039;);&lt;br /&gt;
				// do something here&lt;br /&gt;
			},&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Player Panel ===&lt;br /&gt;
&lt;br /&gt;
==== Inserting non-player panel ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg.js, ggg_ggg.tpl&lt;br /&gt;
&lt;br /&gt;
If you want to insert non-player panel on the right side (for example to hold extra preferences, zooming controls, etc)&lt;br /&gt;
&lt;br /&gt;
this can go pretty much anywhere in template it will be moved later&lt;br /&gt;
&lt;br /&gt;
ggg_ggg.tpl:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	&amp;lt;div class=&#039;player_board_config&#039; id=&amp;quot;player_board_config&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;!-- here is whatever you want, buttons just example --&amp;gt;&lt;br /&gt;
		&amp;lt;button id=&amp;quot;zoom-out&amp;quot; class=&amp;quot; fa fa-search-minus fa-2x config-control&amp;quot;&amp;gt;&amp;lt;/button&amp;gt;&lt;br /&gt;
		&amp;lt;button id=&amp;quot;zoom-in&amp;quot; class=&amp;quot; fa fa-search-plus fa-2x config-control&amp;quot;&amp;gt;&amp;lt;/button&amp;gt;&lt;br /&gt;
		&amp;lt;button id=&amp;quot;show-settings&amp;quot; class=&amp;quot;fa fa-cog fa-2x config-control &amp;quot;&amp;gt;&amp;lt;/button&amp;gt;&lt;br /&gt;
        &amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
some hackery required in js&lt;br /&gt;
&lt;br /&gt;
ggg.js:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/* @Override */&lt;br /&gt;
	updatePlayerOrdering() {&lt;br /&gt;
		this.inherited(arguments);&lt;br /&gt;
		dojo.place(&#039;player_board_config&#039;, &#039;player_boards&#039;, &#039;first&#039;);&lt;br /&gt;
	},&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Images and Icons ===&lt;br /&gt;
&lt;br /&gt;
==== Accessing images from js ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg.js&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt; &lt;br /&gt;
     // your game resources&lt;br /&gt;
     &lt;br /&gt;
     var my_img = &#039;&amp;lt;img src=&amp;quot;&#039;+g_gamethemeurl+&#039;img/cards.jpg&amp;quot;/&amp;gt;&#039;;&lt;br /&gt;
     &lt;br /&gt;
     // shared resources&lt;br /&gt;
     var my_help_img = &amp;quot;&amp;lt;img class=&#039;imgtext&#039; src=&#039;&amp;quot; + g_themeurl + &amp;quot;img/layout/help_click.png&#039; alt=&#039;action&#039; /&amp;gt; &amp;lt;span class=&#039;tooltiptext&#039;&amp;gt;&amp;quot; +&lt;br /&gt;
                    text + &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== High-Definition Graphics ====&lt;br /&gt;
&lt;br /&gt;
Some users will have screens which can display text and images at a greater resolution than the usual 72 dpi, e.g. the &amp;quot;Retina&amp;quot; screens on the 5k iMac, all iPads, and high-DPI screens on laptops from many manufacturers. If you can get art assets at this size, they will make your game look extra beautiful. You &#039;&#039;could&#039;&#039; just use large graphics and scale them down, but that would increase the download time and bandwidth for users who can&#039;t display them. Instead, a good way is to prepare a separate graphics file at exactly twice the size you would use otherwise, and add &amp;quot;@2x&amp;quot; at the end of the filename, e.g. if pieces.png is 240x320, then pieces@2x.png is 480x640.&lt;br /&gt;
&lt;br /&gt;
There are two changes required in order to use the separate graphics files. First in your css, where you use a file, add a media query which overrides the original definition and uses the bigger version on devices which can display them. Ensuring that the &amp;quot;background-size&amp;quot; attribute is set means that the size of the displayed object doesn&#039;t change, but only is drawn at the improved dot pitch.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
.piece {&lt;br /&gt;
    position: absolute;&lt;br /&gt;
    background-image: url(&#039;img/pieces.png&#039;);&lt;br /&gt;
    background-size:240px 320px;&lt;br /&gt;
    z-index: 10;&lt;br /&gt;
}&lt;br /&gt;
@media (-webkit-min-device-pixel-ratio: 2), (min-device-pixel-ratio: 2), (min-resolution: 192dpi)&lt;br /&gt;
{&lt;br /&gt;
    .piece {&lt;br /&gt;
        background-image: url(&#039;img/pieces@2x.png&#039;);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Secondly, in your setup function in javascript, you must ensure than only the appropriate one version of the file gets pre-loaded (otherwise you more than waste the bandwidth saved by maintaining the standard-resolution file). Note that the media query is the same in both cases:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
            var isRetina = &amp;quot;(-webkit-min-device-pixel-ratio: 2), (min-device-pixel-ratio: 2), (min-resolution: 192dpi)&amp;quot;;&lt;br /&gt;
            if (window.matchMedia(isRetina).matches)&lt;br /&gt;
            {&lt;br /&gt;
                this.dontPreloadImage( &#039;pieces.png&#039; );&lt;br /&gt;
                this.dontPreloadImage( &#039;board.jpg&#039; );&lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                this.dontPreloadImage( &#039;pieces@2x.png&#039; );&lt;br /&gt;
                this.dontPreloadImage( &#039;board@2x.jpg&#039; );&lt;br /&gt;
            }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Using CSS to create different colors of game pieces if you have only white piece ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
background-color: #${color}; &lt;br /&gt;
background-blend-mode: multiply;&lt;br /&gt;
background-image: url( &#039;img/mypiece.png&#039;);&lt;br /&gt;
mask: url(&#039;img/mypiece.png&#039;);&lt;br /&gt;
-webkit-mask: url(&#039;img/mypiece.png&#039;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
where ${color} - is color you want&lt;br /&gt;
&lt;br /&gt;
Note: piece has to be white (shades of gray). Sprite can be used too, just add add blackground-position as usual.&lt;br /&gt;
&lt;br /&gt;
==== Accessing player avatar URLs ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
      getPlayerAvatar(playerId) {&lt;br /&gt;
         let avatarURL = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
         if (null != $(&#039;avatar_&#039; + playerId)) {&lt;br /&gt;
            let smallAvatarURL = dojo.attr(&#039;avatar_&#039; + playerId, &#039;src&#039;);&lt;br /&gt;
            avatarURL = smallAvatarURL.replace(&#039;_32.&#039;, &#039;_184.&#039;);&lt;br /&gt;
         }&lt;br /&gt;
         else {&lt;br /&gt;
            avatarURL = &#039;https://x.boardgamearena.net/data/data/avatar/default_184.jpg&#039;;&lt;br /&gt;
         }&lt;br /&gt;
&lt;br /&gt;
         return avatarURL;&lt;br /&gt;
      },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note:  This gets avatar URLs at 184x184 resolution.  You can also use 92, 50, and 32 depending on which resolution you want.&lt;br /&gt;
&lt;br /&gt;
==== Adding Image buttons ====&lt;br /&gt;
&lt;br /&gt;
Its pretty trivial but just in case you need a working function:&lt;br /&gt;
&lt;br /&gt;
ggg.js:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
                addImageActionButton: function (id, div_html, handler) { // div_html is string not node&lt;br /&gt;
                    this.addActionButton(id, div_html, handler, &#039;&#039;, false, &#039;gray&#039;); &lt;br /&gt;
                    dojo.style(id, &amp;quot;border&amp;quot;, &amp;quot;none&amp;quot;); // remove ugly border&lt;br /&gt;
                    dojo.addClass(id, &amp;quot;bgaimagebutton&amp;quot;); // add css class to do more styling&lt;br /&gt;
                    return $(id); // return node for chaining&lt;br /&gt;
                },&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Example of usage:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    this.addImageActionButton(&#039;button_coin&#039;,&amp;quot;&amp;lt;div class=&#039;coin&#039;&amp;gt;&amp;lt;/div&amp;gt;&amp;quot;, ()=&amp;gt;{ alert(&#039;Ha!&#039;); });&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Other Fluff ===&lt;br /&gt;
&lt;br /&gt;
==== Use thematic fonts ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg.css&lt;br /&gt;
&lt;br /&gt;
Sometime game elements use specific fonts of text, if you want to match it up you can load some specific font (IMPORTANT: from some &#039;&#039;&#039;free font&#039;&#039;&#039; source. See notes below).&lt;br /&gt;
&lt;br /&gt;
[[File:Dragonline_font.png]]&lt;br /&gt;
&lt;br /&gt;
.css&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/* latin-ext */&lt;br /&gt;
@font-face {&lt;br /&gt;
  font-family: &#039;Qwigley&#039;;&lt;br /&gt;
  font-style: normal;&lt;br /&gt;
  font-weight: 400;&lt;br /&gt;
  src: local(&#039;Qwigley&#039;), local(&#039;Qwigley-Regular&#039;), url(https://fonts.gstatic.com/s/qwigley/v6/2Dy1Unur1HJoklbsg4iPJ_Y6323mHUZFJMgTvxaG2iE.woff2) format(&#039;woff2&#039;);&lt;br /&gt;
  unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;&lt;br /&gt;
}&lt;br /&gt;
/* latin */&lt;br /&gt;
@font-face {&lt;br /&gt;
  font-family: &#039;Qwigley&#039;;&lt;br /&gt;
  font-style: normal;&lt;br /&gt;
  font-weight: normal;&lt;br /&gt;
  src: local(&#039;Qwigley&#039;), local(&#039;Qwigley-Regular&#039;), url(https://fonts.gstatic.com/s/qwigley/v6/gThgNuQB0o5ITpgpLi4Zpw.woff2) format(&#039;woff2&#039;);&lt;br /&gt;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;&lt;br /&gt;
}&lt;br /&gt;
@font-face {&lt;br /&gt;
  font-family: &#039;Qwigley&#039;;&lt;br /&gt;
  font-style: normal;&lt;br /&gt;
  font-weight: normal;&lt;br /&gt;
  src: local(&#039;Qwigley&#039;), local(&#039;Qwigley-Regular&#039;), url(http://ff.static.1001fonts.net/q/w/qwigley.regular.ttf) format(&#039;ttf&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.zone_title {&lt;br /&gt;
	display: inline-block;&lt;br /&gt;
	position: absolute;&lt;br /&gt;
	font: italic 32px/32px &amp;quot;Qwigley&amp;quot;, cursive;	   &lt;br /&gt;
	height: 32px;&lt;br /&gt;
	width: auto;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NB:&#039;&#039;&#039; if you need to include a font that&#039;s not available online, an extra action will be needed from an admin. Please include the font file(s) in your img directory, and mention it to admins when requesting your game to be moved to alpha. &#039;&#039;&#039;Please remember that the font has to be free, and include a .txt with all appropriate license information about the font.&#039;&#039;&#039;&lt;br /&gt;
You can look for free fonts (for example) on https://fonts.google.com or https://www.fontsquirrel.com/)&lt;br /&gt;
&lt;br /&gt;
===== Content Security Policy =====&lt;br /&gt;
&lt;br /&gt;
BGA runs a Content Security Policy which will limit the origins from which you can load external fonts, in order to prevent license abuse.&lt;br /&gt;
&lt;br /&gt;
The CSP is a whitelist of allowed origins. To see the list, view the response headers of any page on Studio, and look for the &amp;quot;Content-Security-Policy&amp;quot; header.&lt;br /&gt;
&lt;br /&gt;
You will specifically want to check for the font-src token within these headers, and limit any external fonts to these sources.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;This list is subject to change&#039;&#039;&#039; but as of the time of writing, the only acceptabled external sites are use.typekit.net and fonts.gstatic.com.&lt;br /&gt;
&lt;br /&gt;
=== Use player color in template ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg_ggg.tpl, ggg.view.php&lt;br /&gt;
&lt;br /&gt;
.view.php:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    function build_page($viewArgs) {&lt;br /&gt;
        // Get players &amp;amp; players number&lt;br /&gt;
        $players = $this-&amp;gt;game-&amp;gt;loadPlayersBasicInfos();&lt;br /&gt;
        $players_nbr = count($players);&lt;br /&gt;
        /**&lt;br /&gt;
         * ********* Place your code below: ***********&lt;br /&gt;
         */&lt;br /&gt;
        &lt;br /&gt;
        // Set PCOLOR to the current player color hex&lt;br /&gt;
        global $g_user;&lt;br /&gt;
        $cplayer = $g_user-&amp;gt;get_id();&lt;br /&gt;
        if (array_key_exists($cplayer, $players)) { // may be not set if spectator&lt;br /&gt;
            $player_color = $players [$cplayer] [&#039;player_color&#039;];&lt;br /&gt;
        } else {&lt;br /&gt;
            $player_color = &#039;ffffff&#039;; // spectator&lt;br /&gt;
        }&lt;br /&gt;
        $this-&amp;gt;tpl [&#039;PCOLOR&#039;] = $player_color;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Scale to fit for big boards ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg_ggg.tpl, ggg.js&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Lets say you have huge game board, and lets say you want it to be 1400px wide. Besides the board there will be side bar which is 240 and trim. &lt;br /&gt;
My display is 1920 wide so it fits, but there is big chance other people won&#039;t have that width. What do you do?&lt;br /&gt;
&lt;br /&gt;
You have to decide:&lt;br /&gt;
* If board does not fit you want scale whole thing down, the best way is probably use viewport (see https://en.doc.boardgamearena.com/Your_game_mobile_version)&lt;br /&gt;
* You can leave the board as is and make sure it is scrollable horizonatally&lt;br /&gt;
* You add custom scale just for the board (can add user controls  - and hook to transform: scale())&lt;br /&gt;
&lt;br /&gt;
I tried to auto-scale but this just does work, too many variables - browser zoom, 3d mode, viewport, custom bga scaling, devicePixelRatio - all create some impossible coctail of zooming...&lt;br /&gt;
Here is scaling functing for custom user scaling&lt;br /&gt;
&lt;br /&gt;
ggg_ggg.tpl:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   &amp;lt;div id=&amp;quot;thething&amp;quot; class=&amp;quot;thething&amp;quot;&amp;gt;&lt;br /&gt;
            ... everything else you declare ...&lt;br /&gt;
   &amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ggg.js:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    onZoomPlus: function() {&lt;br /&gt;
       this.my_zoom+=0.1;&lt;br /&gt;
       this.zoommy(&#039;thething&#039;,this.my_zoom);&lt;br /&gt;
    },&lt;br /&gt;
&lt;br /&gt;
    zoommy: function(node, zoom) {&lt;br /&gt;
                node=$(node);&lt;br /&gt;
		var width = 100 / zoom;&lt;br /&gt;
		node.style.transformOrigin = &amp;quot;0 0&amp;quot;;&lt;br /&gt;
		node.style.transform = &amp;quot;scale(&amp;quot; + zoom + &amp;quot;)&amp;quot;;&lt;br /&gt;
		node.style.width = width + &amp;quot;%&amp;quot;;&lt;br /&gt;
    },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Dynamic tooltips ===&lt;br /&gt;
&lt;br /&gt;
If you really need a dynamic tooltip you can use this technique. (Only use it if the static tooltips provided by the BGA framework are not sufficient.)&lt;br /&gt;
&lt;br /&gt;
            new dijit.Tooltip({&lt;br /&gt;
                connectId: [&amp;quot;divItemId&amp;quot;],&lt;br /&gt;
                getContent: function(matchedNode){&lt;br /&gt;
                    return &amp;quot;... calculated ...&amp;quot;; &lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This is an out-of-the-box djit.Tooltip. It has a &#039;&#039;getContent&#039;&#039; method which is called dynamically.&lt;br /&gt;
&lt;br /&gt;
The string function return becomes the innerHTML of the tooltip, so it can be anything. In this example matchedNode is a dojo node representing dom object with id of &amp;quot;divItemId&amp;quot; but there are more parameters which I am not posting here which allows more sophisticated subnode queries (i.e. you can attach tooltip to all nodes with class or whatever).&lt;br /&gt;
&lt;br /&gt;
[https://dojotoolkit.org/reference-guide/1.10/dijit/Tooltip.html dijit.Tooltip]&lt;br /&gt;
&lt;br /&gt;
It&#039;s not part of the BGA API so use at your own risk.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Rendering text with players color and proper background ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg.js&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        /* Implementation of proper colored You with background in case of white or light colors  */&lt;br /&gt;
 &lt;br /&gt;
        divYou: function() {&lt;br /&gt;
            var color = this.gamedatas.players[this.player_id].color;&lt;br /&gt;
            var color_bg = &amp;quot;&amp;quot;;&lt;br /&gt;
            if (this.gamedatas.players[this.player_id] &amp;amp;&amp;amp; this.gamedatas.players[this.player_id].color_back) {&lt;br /&gt;
                color_bg = &amp;quot;background-color:#&amp;quot; + this.gamedatas.players[this.player_id].color_back + &amp;quot;;&amp;quot;;&lt;br /&gt;
            }&lt;br /&gt;
            var you = &amp;quot;&amp;lt;span style=\&amp;quot;font-weight:bold;color:#&amp;quot; + color + &amp;quot;;&amp;quot; + color_bg + &amp;quot;\&amp;quot;&amp;gt;&amp;quot; + __(&amp;quot;lang_mainsite&amp;quot;, &amp;quot;You&amp;quot;) + &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;;&lt;br /&gt;
            return you;&lt;br /&gt;
        },&lt;br /&gt;
&lt;br /&gt;
        /* Implementation of proper colored player name with background in case of white or light colors  */&lt;br /&gt;
&lt;br /&gt;
        divColoredPlayer: function(player_id) {&lt;br /&gt;
            var color = this.gamedatas.players[player_id].color;&lt;br /&gt;
            var color_bg = &amp;quot;&amp;quot;;&lt;br /&gt;
            if (this.gamedatas.players[player_id] &amp;amp;&amp;amp; this.gamedatas.players[player_id].color_back) {&lt;br /&gt;
                color_bg = &amp;quot;background-color:#&amp;quot; + this.gamedatas.players[player_id].color_back + &amp;quot;;&amp;quot;;&lt;br /&gt;
            }&lt;br /&gt;
            var div = &amp;quot;&amp;lt;span style=\&amp;quot;color:#&amp;quot; + color + &amp;quot;;&amp;quot; + color_bg + &amp;quot;\&amp;quot;&amp;gt;&amp;quot; + this.gamedatas.players[player_id].name + &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;;&lt;br /&gt;
            return div;&lt;br /&gt;
        },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Cool realistic shadow effect with CSS ===&lt;br /&gt;
&lt;br /&gt;
==== Rectangles and circles ====&lt;br /&gt;
&lt;br /&gt;
It is often nice to have a drop shadow around tiles and tokens, to separate them from the table visually. It is very easy to add a shadow to rectangular elements, just add this to your css:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
.xxx-tile {&lt;br /&gt;
    box-shadow: 3px 3px 3px #000000a0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
box-shadow obeys &#039;&#039;&#039;border-radius&#039;&#039;&#039; of the element, so it will look good for rounded rectangles, and hence also circles (if border-radius is set appropriately).&lt;br /&gt;
&lt;br /&gt;
box-shadow also supports various other parameters and can be used to achieve effects such as glowing, borders, inner shadows etc. If you need to animate a box-shadow, you may be able to get better performance (avoiding redraws) if you attach the shadow to another element (possibly an ::after pseudo-element) and change only the &#039;&#039;&#039;opacity&#039;&#039;&#039; of that element.&lt;br /&gt;
&lt;br /&gt;
==== Irregular Shapes ====&lt;br /&gt;
&lt;br /&gt;
If you wish to make a shadow effect for game pieces that are not a rectangle, but your game pieces are drawn from rectangles in a PNG image, you can apply the shadow to the piece using any art package and save it inside the image. This usually will yield the best performance. Remember to account for the size of the shadow when you lay out images in the sprite sheet.&lt;br /&gt;
&lt;br /&gt;
However that sometimes will not be an option, for example if the image needs to be rotated while the shadow remains offset in the same direction. In this case, one option is to not use box-shadow but use filter, which is supported by recent major browsers.  This way, you can use the alpha channel of your element to drop a shadow.  This even work for transparent backgrounds, so that if you are using the &amp;quot;CSS-sprite&amp;quot; method, it will work!&lt;br /&gt;
&lt;br /&gt;
For instance:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
.xxx-token {&lt;br /&gt;
    filter: drop-shadow(0px 0px 1px #000000);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Beware that some browsers still do not always draw drop-shadow correctly. In particular, Safari frequently leaves bits of shadow behind when objects move around the screen. In Chrome, shadows sometimes flicker badly if another element is animating close by. Some of these correctness issues can be solved by adding &#039;&#039;&#039;isolation: isolate; will-change: filter;&#039;&#039;&#039; to affected elements, but this significantly affects redraw performance.&lt;br /&gt;
&lt;br /&gt;
Beware of performance issues - particularly on Safari (MacOS, iPhone and iPad). Keep in mind that drop-shadow are very GPU intensive. This becomes noticeable once you have about 40 components with drop-shadow filter. If that is your case, you can quite easily implement a user preference to disable shadows for users on slower machines:&lt;br /&gt;
&lt;br /&gt;
gameoptions.inc.php&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
100 =&amp;gt; array(&lt;br /&gt;
			&#039;name&#039; =&amp;gt; totranslate(&#039;Shadows&#039;),&lt;br /&gt;
			&#039;needReload&#039; =&amp;gt; true, // after user changes this preference game interface would auto-reload&lt;br /&gt;
			&#039;values&#039; =&amp;gt; array(&lt;br /&gt;
					1 =&amp;gt; array( &#039;name&#039; =&amp;gt; totranslate( &#039;Enabled&#039; ), &#039;cssPref&#039; =&amp;gt; &#039;&#039; ),&lt;br /&gt;
					2 =&amp;gt; array( &#039;name&#039; =&amp;gt; totranslate( &#039;Disabled&#039; ), &#039;cssPref&#039; =&amp;gt; &#039;no-shadow&#039; )&lt;br /&gt;
			)&lt;br /&gt;
	),&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[game].css&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
.no-shadow * {&lt;br /&gt;
	filter: none !important; &lt;br /&gt;
} &lt;br /&gt;
&amp;lt;/pre&amp;gt;For Safari, it is usually better to simply disable drop-shadow completely: [[Game interface stylesheet: yourgamename.css#Warning: using drop-shadow]].&lt;br /&gt;
&lt;br /&gt;
==== Shadows with clip-path ====&lt;br /&gt;
&lt;br /&gt;
For some reason, a shadow will not work together with clip-path on one element. To use both clip-path (when for example using .svg to cut out cardboard components from your .jpg spritesheet) and drop-shadow, you need to wrap the element into another one, and apply drop-shadow to the outer one, and clip-path to the inner one.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;div class=&#039;my-token-wrap&#039;&amp;gt;&lt;br /&gt;
  &amp;lt;div class=&#039;my-token&#039;&amp;gt;&lt;br /&gt;
  &amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
.my-token-wrap {&lt;br /&gt;
    filter: drop-shadow(0px 0px 1px #000000);&lt;br /&gt;
}&lt;br /&gt;
.my-token-wrap .my-token {&lt;br /&gt;
    clip-path: url(#my-token-path);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Using the CSS classes from the state machine ===&lt;br /&gt;
&lt;br /&gt;
If you need to hide or show stuff depending on the state of your game, you can of course use javascript, but CSS is hand enough for that.  The #overall-content element does change class depending on the game state.  For instance, if you are in state &#039;&#039;playerTurn&#039;&#039;, it will have the class &#039;&#039;gamestate_playerTurn&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
So now, if you want to show the discard pile only during player turns, you may use:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#discard_pile { display: none }&lt;br /&gt;
.gamestate_playerTurn #discard_pile { display: block }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This can be used if you want to change sizing of elements, position, layout or visual appearance.&lt;br /&gt;
&lt;br /&gt;
== Game Model and Database design ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Database for The euro game ===&lt;br /&gt;
Lets say we have a game with workers, dice, tokens, board, resources, money and vp. Workers and dice can be placed in various zones on the board, and you can get resources, money, tokens and vp in your home zone. Also tokens can be flipped or not flipped.&lt;br /&gt;
&lt;br /&gt;
[[File:Madeira board.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Now lets try to map it, we have&lt;br /&gt;
* (meeple,zone)&lt;br /&gt;
* (die, zone, sideup)&lt;br /&gt;
* (resource cube/money token/vp token,player home zone)&lt;br /&gt;
* (token, player home zone, flip state)&lt;br /&gt;
We can notice that resource and money are uncountable, and don&#039;t need to be track individually so we can replace our mapping to&lt;br /&gt;
* (resource type/money,player home zone, count)&lt;br /&gt;
And vp stored already for us in player table, so we can remove it from that list.&lt;br /&gt;
&lt;br /&gt;
Now when we get to encode it we can see that everything can be encoded as (object,zone,state) form, where object and zone is string and state is integer. The resource mapping is slightly different semantically so you can go with two table, or counting using same table with state been used as count for resources.&lt;br /&gt;
&lt;br /&gt;
So the piece mapping for non-grid based games can be in most case represented by (string: token_key, string: token_location, int: token_state), example of such database schema can be found here: [https://github.com/elaskavaia/bga-sharedcode/blob/master/dbmodel.sql dbmodel.sql] and class implementing access to it here [https://github.com/elaskavaia/bga-sharedcode/blob/master/modules/tokens.php table.game.php].&lt;br /&gt;
&lt;br /&gt;
Variant 1: Minimalistic&lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE IF NOT EXISTS `token` (&lt;br /&gt;
  `token_key` varchar(32) NOT NULL,&lt;br /&gt;
  `token_location` varchar(32) NOT NULL,&lt;br /&gt;
  `token_state` int(10),&lt;br /&gt;
  PRIMARY KEY (`token_key`)&lt;br /&gt;
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+token&lt;br /&gt;
! token_key&lt;br /&gt;
! token_location&lt;br /&gt;
! token_state&lt;br /&gt;
|-&lt;br /&gt;
|meeple_red_1&lt;br /&gt;
|home_red&lt;br /&gt;
|0&lt;br /&gt;
|-&lt;br /&gt;
|dice_black_2&lt;br /&gt;
|board_guard&lt;br /&gt;
|1&lt;br /&gt;
|-&lt;br /&gt;
|dice_green_1&lt;br /&gt;
|board_action_mayor&lt;br /&gt;
|3&lt;br /&gt;
|-&lt;br /&gt;
|bread&lt;br /&gt;
|home_red&lt;br /&gt;
|5&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Now how we represent resource counters such as bread?&lt;br /&gt;
Using same table from we simply add special counter token for bread and use state to indicate the count. Note to keep first column unique we have to add player identification for that counter, i.e. ff0000 is red player.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+token&lt;br /&gt;
! token_key&lt;br /&gt;
! token_location&lt;br /&gt;
! token_state&lt;br /&gt;
|-&lt;br /&gt;
|bread_ff0000&lt;br /&gt;
|tableau_ff0000&lt;br /&gt;
|5&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
See php module for this table here https://github.com/elaskavaia/bga-sharedcode/blob/master/modules/tokens.php&lt;br /&gt;
&lt;br /&gt;
Variant 2: Additional resource table, resource count for each player id&lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE IF NOT EXISTS `resource` (&lt;br /&gt;
  `player_id` int(10) unsigned NOT NULL,&lt;br /&gt;
  `resource_key` varchar(32) NOT NULL,&lt;br /&gt;
  `resource_count` int(10) signed NOT NULL,&lt;br /&gt;
  PRIMARY KEY (`player_id`,`resource_key`)&lt;br /&gt;
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;&lt;br /&gt;
&lt;br /&gt;
 ALTER TABLE resource ADD CONSTRAINT fk_player_id FOREIGN KEY (player_id) REFERENCES player(player_id);&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+resource&lt;br /&gt;
! player_id&lt;br /&gt;
! resource_key&lt;br /&gt;
! resource_count&lt;br /&gt;
|-&lt;br /&gt;
|123456&lt;br /&gt;
|bread&lt;br /&gt;
|5&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Variant 3: More normalised&lt;br /&gt;
&lt;br /&gt;
This version is similar to &amp;quot;card&amp;quot; table from hearts tutorial, you can also use exact cards database schema and Deck implementation for most purposes (even you not dealing with cards). &lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE IF NOT EXISTS `token` (&lt;br /&gt;
  `token_id` int(10) unsigned NOT NULL AUTO_INCREMENT,&lt;br /&gt;
  `token_type` varchar(16) NOT NULL,&lt;br /&gt;
  `token_arg` int(11) NOT NULL,&lt;br /&gt;
  `token_location` varchar(32) NOT NULL,&lt;br /&gt;
  `token_state` int(10),&lt;br /&gt;
  PRIMARY KEY (`token_id`)&lt;br /&gt;
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+token&lt;br /&gt;
! token_id&lt;br /&gt;
! token_type&lt;br /&gt;
! token_arg&lt;br /&gt;
! token_location&lt;br /&gt;
! token_state&lt;br /&gt;
|-&lt;br /&gt;
|22&lt;br /&gt;
|meeple&lt;br /&gt;
|123456&lt;br /&gt;
|home_123456&lt;br /&gt;
|0&lt;br /&gt;
|-&lt;br /&gt;
|23&lt;br /&gt;
|dice&lt;br /&gt;
|2&lt;br /&gt;
|board_guard&lt;br /&gt;
|1&lt;br /&gt;
|-&lt;br /&gt;
|26&lt;br /&gt;
|dice&lt;br /&gt;
|1&lt;br /&gt;
|board_action_mayor&lt;br /&gt;
|3&lt;br /&gt;
|-&lt;br /&gt;
|49&lt;br /&gt;
|bread&lt;br /&gt;
|0&lt;br /&gt;
|home_123456&lt;br /&gt;
|5&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Advantages of this would be is a bit more straightforward to do some queries in db, disadvantage its hard to read (as you can compare with previous example, you&lt;br /&gt;
cannot just look at say, ah I know what it means). Another questionable advantage is it allows you to do id randomisation, so it hard to do crafted queries to &lt;br /&gt;
cheat, the down side of that you cannot understand it either, and handcraft db states for debugging or testing.&lt;br /&gt;
&lt;br /&gt;
=== Database for The card game ===&lt;br /&gt;
&lt;br /&gt;
Lets say you have a standard card game, player have hidden cards in hand, you can draw card from draw deck, play card on tableau and discard to discard pile.&lt;br /&gt;
We have to design database for such game.&lt;br /&gt;
&lt;br /&gt;
In real word to &amp;quot;save&amp;quot; the game we take a picture a play area, save cards from it, then put away draw deck, discard and hand of each player separately and mark it, also we will record current scoring (if any) and who&#039;s turn was it.&lt;br /&gt;
&lt;br /&gt;
* Framework handles state machine transition, so you don&#039;t have to worry about database design for that (i.e. who&#039;s turn it is, what phase of the game we are at, you still have to design it but part of state machine step)&lt;br /&gt;
* Also framework supports basic player information, color, order around the table, basic scoring, etc, so you don&#039;t have to worry about it either&lt;br /&gt;
* The only thing you need in our database is state of the &amp;quot;board&amp;quot;, which is &amp;quot;where each pieces is, and in what state&amp;quot;, or (position,rotation) pair.&lt;br /&gt;
&lt;br /&gt;
Lets see what we have for that:&lt;br /&gt;
* The card state is very simple, its usually &amp;quot;face up/face down&amp;quot;, &amp;quot;tapped/untapped&amp;quot;, &amp;quot;right side up/up side down&amp;quot;&lt;br /&gt;
* As position go we never need real coordinates x,y,z. We need to know what &amp;quot;zone&amp;quot; card was, and depending on the zone it may sometimes need an extra &amp;quot;z&amp;quot; or &amp;quot;x&amp;quot; as card order. The zone position usually static or irrelevant.&lt;br /&gt;
* So our model is: we have cards, which have some attributes, at any given point in time they belong to a &amp;quot;zone&amp;quot;, and can also have order and state&lt;br /&gt;
* Now for mapping we should consider what information changes and what information is static, later is always candidate for material file&lt;br /&gt;
* For dynamic information we should try to reduce amount of fields we need&lt;br /&gt;
**  we need at least a field for card, so its one&lt;br /&gt;
**  we need to know what zone cards belong to, its 2&lt;br /&gt;
**  and we have possibly few other fields, if you look closely at you game you may find out that most of the zone only need one attribute at a time, i.e. draw pile always have cards face down, hand always face up, also for hand and discard order does not matter at all (but for draw it does matter). So in majority of cases we can get away with one single extra integer field representing state or order&lt;br /&gt;
* In real database both card and zone will be integers as primary keys referring to additional tables, but in our case its total overkill, so they can be strings as easily&lt;br /&gt;
&lt;br /&gt;
Variant 1: Minimalistic&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE TABLE IF NOT EXISTS `card` (&lt;br /&gt;
  `card_key` varchar(32) unsigned NOT NULL,&lt;br /&gt;
  `card_location` varchar(32) NOT NULL,&lt;br /&gt;
  `card_state` int(11) NOT NULL,&lt;br /&gt;
  PRIMARY KEY (`card_id`)&lt;br /&gt;
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Variant 2: More normalised&lt;br /&gt;
&lt;br /&gt;
This version supported by Deck php class, so unless you want to rewrite db access layer go with this one&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE TABLE IF NOT EXISTS `card` (&lt;br /&gt;
  `card_id` int(10) unsigned NOT NULL AUTO_INCREMENT,&lt;br /&gt;
  `card_type` varchar(16) NOT NULL,&lt;br /&gt;
  `card_type_arg` int(11) NOT NULL,&lt;br /&gt;
  `card_location` varchar(16) NOT NULL,&lt;br /&gt;
  `card_location_arg` int(11) NOT NULL,&lt;br /&gt;
  PRIMARY KEY (`card_id`)&lt;br /&gt;
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: if you using this schema, some zones/locations have special semantic. The &#039;hand&#039; location is actually multiple locations - one per player, but player id is encoded as card_location_arg. If &#039;hand&#039; in your game is ordered, visible or can have some other card states, you cannot use hand location (replacement is hand_&amp;lt;player_id&amp;gt; or hand_&amp;lt;color_id&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
== Code Organization ==&lt;br /&gt;
&lt;br /&gt;
=== Including your own JavaScript module ===&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg.js, modules/ggg_other.js&lt;br /&gt;
&lt;br /&gt;
* Create ggg_other.js in modules/ folder and sync&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
define([&lt;br /&gt;
    &amp;quot;dojo&amp;quot;, &amp;quot;dojo/_base/declare&amp;quot;&lt;br /&gt;
], function( dojo, declare )&lt;br /&gt;
{&lt;br /&gt;
return declare(&amp;quot;bgagame.other&amp;quot;, null, { // null here if we don&#039;t want to inherit from anything&lt;br /&gt;
        constructor: function(){},&lt;br /&gt;
        mystuff: function(){},&lt;br /&gt;
    });&lt;br /&gt;
        &lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Modify ggg.js to include it&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  define([ &amp;quot;dojo&amp;quot;, &amp;quot;dojo/_base/declare&amp;quot;, &amp;quot;ebg/core/gamegui&amp;quot;, &amp;quot;ebg/counter&amp;quot;,&lt;br /&gt;
    g_gamethemeurl + &amp;quot;modules/ggg_other.js&amp;quot;     // load my own module!!!&lt;br /&gt;
  ], function(dojo,&lt;br /&gt;
        declare) {&lt;br /&gt;
     &lt;br /&gt;
&lt;br /&gt;
use it&lt;br /&gt;
&lt;br /&gt;
  foo = new bgagame.other();&lt;br /&gt;
&lt;br /&gt;
=== Including your own JavaScript module (II) ===&lt;br /&gt;
&lt;br /&gt;
* Create ggg_other.js in modules/ folder and sync&lt;br /&gt;
&lt;br /&gt;
  define([], function () {&lt;br /&gt;
    return &amp;quot;value&amp;quot;;&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
* Modify ggg.js to include it&lt;br /&gt;
&lt;br /&gt;
  define([ &lt;br /&gt;
    &amp;quot;dojo&amp;quot;, &lt;br /&gt;
    &amp;quot;dojo/_base/declare&amp;quot;, &lt;br /&gt;
    &amp;quot;bgagame/modules/ggg_other&amp;quot;, &lt;br /&gt;
    &amp;quot;ebg/core/gamegui&amp;quot;, &lt;br /&gt;
    &amp;quot;ebg/counter&amp;quot;&lt;br /&gt;
  ], function(dojo, declare, other) {&lt;br /&gt;
  &lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  &lt;br /&gt;
This is maybe a little bit more the idea of the AMD Loader than the first option, although the first option should work as well.&lt;br /&gt;
&lt;br /&gt;
A little explanation to this:&lt;br /&gt;
The define function loads all the modules listed in the array and calls the following function with these loaded modules as parameters.&lt;br /&gt;
By putting your module at the third position in the array it is passed as the third parameter to the function. Be aware that the modules are resolved by position only, not by name. So you can load the module &#039;&#039;&#039;ggg_other&#039;&#039;&#039; and pass it as a parameter with the name &#039;&#039;&#039;other&#039;&#039;&#039;. &#039;&#039;&#039;gamegui&#039;&#039;&#039; and &#039;&#039;&#039;counter&#039;&#039;&#039; are passed in as well, but when the parameters are not defined they are just skipped. Because these modules put their content into the global scope it does not matter and you can use them from there.&lt;br /&gt;
&lt;br /&gt;
In the example above the string &amp;quot;value&amp;quot; is passed for the parameter &#039;&#039;&#039;other&#039;&#039;&#039;, but the function in your module can return whatever you want. It can be an object, an array, something you declared with dojo.declare, you can return even functions. &lt;br /&gt;
Your module can load other modules. Just put them in the array at the beginning and pass them as parameters to your function.&lt;br /&gt;
The advantage of passing the values as parameter is that you do not need to put these values in the global scope, so they can&#039;t be collisions with values defined in other scripts or the BGA Framework.&lt;br /&gt;
&lt;br /&gt;
The dojo toolkit provides good documentation to all of its components, the complete documentation for the AMD-Loader is here:&lt;br /&gt;
https://dojotoolkit.org/documentation/tutorials/1.10/modules/index.html It should be still correct, even as it seems to be only for version 1.10&lt;br /&gt;
&lt;br /&gt;
=== Including your own PHP module ===&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg.game.php, modules/ggg_other.php&lt;br /&gt;
&lt;br /&gt;
* Create ggg_other.php in modules/ folder and sync&lt;br /&gt;
* Modify ggg.game.php to include it&lt;br /&gt;
&lt;br /&gt;
 require_once (&#039;modules/ggg_other.php&#039;);&lt;br /&gt;
&lt;br /&gt;
=== Creating a test class to run PHP locally ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg.game.php, stubs&lt;br /&gt;
For this you need stubs of other method you can use this for example&lt;br /&gt;
https://github.com/elaskavaia/bga-sharedcode/raw/master/misc/module/table/table.game.php&lt;br /&gt;
&lt;br /&gt;
Create another php files, i.e ggg_test.php&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
define(&amp;quot;APP_GAMEMODULE_PATH&amp;quot;, &amp;quot;misc/&amp;quot;); // include path to stubs, which defines &amp;quot;table.game.php&amp;quot; and other classes&lt;br /&gt;
require_once (&#039;eminentdomaine.game.php&#039;);&lt;br /&gt;
&lt;br /&gt;
class MyGameTest1 extends MyGame { // this is your game class defined in ggg.game.php&lt;br /&gt;
    function __construct() {&lt;br /&gt;
        parent::__construct();&lt;br /&gt;
        include &#039;../material.inc.php&#039;;// this is how this normally included, from constructor&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // override/stub methods here that access db and stuff&lt;br /&gt;
    function getGameStateValue($var) {&lt;br /&gt;
        if ($var == &#039;round&#039;)&lt;br /&gt;
            return 3;&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
$x = new MyGameTest1(); // instantiate your class&lt;br /&gt;
$p = $x-&amp;gt;getGameProgression(); // call one of the methods to test&lt;br /&gt;
if ($p != 50)&lt;br /&gt;
    echo &amp;quot;Test1: FAILED&amp;quot;;&lt;br /&gt;
else&lt;br /&gt;
    echo &amp;quot;Test1: PASSED&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Run from command line like&lt;br /&gt;
 php7 ggg_test.php&lt;br /&gt;
&lt;br /&gt;
If you do it this way - you can also use local php debugger (i.e. integrated with IDE or command line).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Avoiding code in dojo declare style ===&lt;br /&gt;
Dojo class declarations are rather bizzare and do not work with most IDEs.&lt;br /&gt;
If you want to write in plain JS with classes, you can stub all the dojo define/declare stuff&lt;br /&gt;
and hook your class into that, so the classes are outside of this mess.&lt;br /&gt;
&lt;br /&gt;
NOTE: this technique is for experienced developers, do not try it if you do not understand&lt;br /&gt;
the consequences.&lt;br /&gt;
&lt;br /&gt;
This is complete example of game .js class&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  // Testla is game name is has to be changed&lt;br /&gt;
class Testla {&lt;br /&gt;
	constructor(game) {&lt;br /&gt;
		console.log(&#039;game constructor&#039;);&lt;br /&gt;
		this.game = game;&lt;br /&gt;
		this.varfoo = new MyFoo(); // this example of class from custom module&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	setup(gamedatas) {&lt;br /&gt;
		console.log(&amp;quot;Starting game setup&amp;quot;, this.varfoo);&lt;br /&gt;
		this.gamedatas = gamedatas;&lt;br /&gt;
		this.dojo.create(&amp;quot;div&amp;quot;, { class: &#039;whiteblock&#039;, innerHTML: _(&amp;quot;hello&amp;quot;) }, &#039;thething&#039;);&lt;br /&gt;
		console.log(&amp;quot;Ending game setup&amp;quot;);&lt;br /&gt;
	};&lt;br /&gt;
	onEnteringState(stateName, args) {&lt;br /&gt;
		console.log(&#039;onEnteringState : &#039; + stateName, args);&lt;br /&gt;
		this.game.addActionButton(&#039;b1&#039;,_(&#039;Click Me&#039;), (e)=&amp;gt;this.onButtonClick(e));&lt;br /&gt;
	};&lt;br /&gt;
	onLeavingState(stateName) {&lt;br /&gt;
		console.log(&#039;onLeavingState : &#039; + stateName, args);&lt;br /&gt;
	};&lt;br /&gt;
	onUpdateActionButtons(stateName, args) {&lt;br /&gt;
		console.log(&#039;onUpdateActionButtons : &#039; + stateName, args);&lt;br /&gt;
	};&lt;br /&gt;
	onButtonClick(event) {&lt;br /&gt;
		console.log(&#039;onButtonClick&#039;,event);&lt;br /&gt;
	};&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
define([&lt;br /&gt;
	&amp;quot;dojo&amp;quot;, &amp;quot;dojo/_base/declare&amp;quot;,&lt;br /&gt;
	&amp;quot;ebg/core/gamegui&amp;quot;,&lt;br /&gt;
	&amp;quot;ebg/counter&amp;quot;,&lt;br /&gt;
	g_gamethemeurl + &#039;/modules/foo.js&#039; // custom module if needed&lt;br /&gt;
],&lt;br /&gt;
	function(dojo, declare) {&lt;br /&gt;
                // testla is game name is has to be changed&lt;br /&gt;
		return declare(&amp;quot;bgagame.testla&amp;quot;, ebg.core.gamegui, {&lt;br /&gt;
			constructor: function() {&lt;br /&gt;
				this.xapp = new Testla(this);&lt;br /&gt;
				this.xapp.dojo = dojo;&lt;br /&gt;
			},&lt;br /&gt;
			setup: function(gamedatas) {&lt;br /&gt;
				this.xapp.setup(gamedatas);&lt;br /&gt;
			},&lt;br /&gt;
			onEnteringState: function(stateName, args) {&lt;br /&gt;
				this.xapp.onEnteringState(stateName, args?.args);&lt;br /&gt;
			},&lt;br /&gt;
			onLeavingState: function(stateName) {&lt;br /&gt;
				this.xapp.onLeavingState(stateName, args);&lt;br /&gt;
			},&lt;br /&gt;
			onUpdateActionButtons: function(stateName, args) {&lt;br /&gt;
				this.xapp.onUpdateActionButtons(stateName, args);&lt;br /&gt;
			},&lt;br /&gt;
		});&lt;br /&gt;
	});&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== More readable JS: onEnteringState ===&lt;br /&gt;
&lt;br /&gt;
If you have a lot of states in onEnteringState or onUpdateActionButtons and friends - it becomes rather wild, you can do this trick to call some methods dynamically.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
     onEnteringState: function(stateName, args) {&lt;br /&gt;
       console.log(&#039;Entering state: &#039; + stateName, args);&lt;br /&gt;
&lt;br /&gt;
       // Call appropriate method&lt;br /&gt;
       var methodName = &amp;quot;onEnteringState_&amp;quot; + stateName;&lt;br /&gt;
       if (this[methodName] !== undefined) {             &lt;br /&gt;
          console.log(&#039;Calling &#039; + methodName, args.args);&lt;br /&gt;
          this[methodName](args.args);&lt;br /&gt;
       }&lt;br /&gt;
     },&lt;br /&gt;
&lt;br /&gt;
     onEnteringState_playerTurn: function(args) { // this is args directly, not args.args &lt;br /&gt;
         // process&lt;br /&gt;
     },&lt;br /&gt;
&lt;br /&gt;
     onEnteringState_playerSomethingElse: function(args) { &lt;br /&gt;
         // process&lt;br /&gt;
     },&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: since its ignores the undefined functions you don&#039;t have define function for each state, but on the other hand you cannot make typos.&lt;br /&gt;
Same applies to onUpdateActionButtons except you pass &#039;args&#039; to method, not args.args, and for onLeavingState where you don&#039;t pass anything.&lt;br /&gt;
&lt;br /&gt;
=== Frameworks and Preprocessors ===&lt;br /&gt;
&lt;br /&gt;
* [[Using Vue]] - work-in-progress guide on using the modern framework Vue.js to create a game&lt;br /&gt;
* [[Using Typescript and Scss]] - How to auto-build Typescript and SCSS files to make your code cleaner&lt;br /&gt;
&lt;br /&gt;
== Assorted Stuff ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Out-of-turn actions: Un-pass ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg.js, ggg.game.php, ggg.action.php, states.inc.php&lt;br /&gt;
&lt;br /&gt;
In multiplayer game sometimes players passes but than they think more and want to un-Pass and redo their choice. &lt;br /&gt;
To re-active a player who passes some trickery required.&lt;br /&gt;
&lt;br /&gt;
Define a special action that does that and hook it up.&lt;br /&gt;
&lt;br /&gt;
In states.inc.php add an action to mmultipleactiveplayer state to &amp;quot;unpass&amp;quot;, lets call it &amp;quot;actionCancel&amp;quot;&lt;br /&gt;
&lt;br /&gt;
In ggg.action.php add action hook&lt;br /&gt;
    public function actionCancel() {&lt;br /&gt;
        self::setAjaxMode();&lt;br /&gt;
        $this-&amp;gt;game-&amp;gt;actionCancel();&lt;br /&gt;
        self::ajaxResponse();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
In ggg.game.php add action handler&lt;br /&gt;
    function actionCancel() {&lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;checkPossibleAction(&#039;actionCancel&#039;);&lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;setPlayersMultiactive(array ($this-&amp;gt;getCurrentPlayerId() ), &#039;error&#039;, false);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Finally to call this in client ggg.js you would do something like:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 onUpdateActionButtons:  function(stateName, args) {&lt;br /&gt;
   if (this.isCurrentPlayerActive()) { &lt;br /&gt;
     // ...&lt;br /&gt;
   } else if (!this.isSpectator) { // player is NOT active but not spectator&lt;br /&gt;
       switch (stateName) {&lt;br /&gt;
          case &#039;playerTurnMultiPlayerState&#039;:&lt;br /&gt;
		this.addActionButton(&#039;button_unpass&#039;, _(&#039;Oh no!&#039;), &#039;onUnpass&#039;);&lt;br /&gt;
		break;&lt;br /&gt;
	}&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
				&lt;br /&gt;
 onUnpass: function(e) {&lt;br /&gt;
    this.ajaxcall(&amp;quot;/&amp;quot; + this.game_name + &amp;quot;/&amp;quot; +  this.game_name + &amp;quot;/actionCancel.html&amp;quot;, {}, this); // no checkAction!&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Although be careful that if the turn comes back to the player while he is about to click cancel, the action buttons will be updated and the player will misclick which can be quite frustrating. To avoid this, move the cancel button to another position, like to the left of pagemaintitletext:&lt;br /&gt;
  dojo.place(&#039;button_unpass&#039;, &#039;pagemaintitletext&#039;, &#039;before&#039;);&lt;br /&gt;
Being out of the generalactions div, it won&#039;t be automatically destroyed like normal buttons, so you&#039;ll have to handle that yourself in onLeavingState. You might also want to change the button color to red (blue buttons for active player only, red buttons also for inactive players?)&lt;br /&gt;
&lt;br /&gt;
Note: same technique can be used to do other out-of-turn actions, such as re-arranging cards in hand, exchanging resources, etc (i.e. if permitted by rules, such as &amp;quot;at any time player can...&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
=== Multi Step Interactions: Select Worker/Place Worker - Using Selection ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg.js&lt;br /&gt;
&lt;br /&gt;
Simple way to implement something like that without extra states is to use &amp;quot;selection&amp;quot; mechanism. When user click on worker add some sort of class into that element i.e. &#039;selected&#039; (which also have to have some indication by css i.e. outline).&lt;br /&gt;
&lt;br /&gt;
Than user can click on placement zone, you can use dojo.query for &amp;quot;selected&amp;quot; element and use it along with zone id to send data to server. If proper worker is not selected yet can give a error message using this.showMessage(...) function.&lt;br /&gt;
&lt;br /&gt;
Extra code required to properly cleanup selection between states.&lt;br /&gt;
Also when you do that sometimes you want to change the state prompt, see below &#039;Change state prompt&#039;&lt;br /&gt;
&lt;br /&gt;
=== Multi Step Interactions: Select Worker/Place Worker - Using Client States ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg.js&lt;br /&gt;
&lt;br /&gt;
I don&#039;t think its documented feature but there is a way to do client-only states, which is absolutely wonderful for few reasons&lt;br /&gt;
* When player interaction is two step process, such as select worker, place worker, or place worker, pick one of two resources of your choice&lt;br /&gt;
* When multi-step process can result of impossible situation and has to be undone (by rules)&lt;br /&gt;
* When multi-step process is triggered from multiple states (such as you can do same thing as activated card action, pass action or main action)&lt;br /&gt;
&lt;br /&gt;
So lets do Select Worker/Place Worker&lt;br /&gt;
&lt;br /&gt;
Define your server state as usual, i.e. playerMainTurn -&amp;gt; &amp;quot;You must pick up a worker&amp;quot;.&lt;br /&gt;
Now define a client state, we only need &amp;quot;name&amp;quot; and &amp;quot;descriptionmyturn&amp;quot;, lets say &amp;quot;client_playerPicksLocation&amp;quot;. Always prefix names of client state with &amp;quot;client_&amp;quot; to avoid confusion. Now we have to do the following:&lt;br /&gt;
* Have a handler for onUpdateActionButtons for playerMainTurn to activate all possible workers he can pick&lt;br /&gt;
* When player clicks workers, remember the worker in one of the members of the main class, I usually use one called this.clientStateArgs.&lt;br /&gt;
* Transition to new client state&lt;br /&gt;
  onWorker: function(e) {&lt;br /&gt;
      var id = event.currentTarget.id;&lt;br /&gt;
      dojo.stopEvent(event);&lt;br /&gt;
      ... // do validity checks&lt;br /&gt;
      this.clientStateArgs.worker_id = id;&lt;br /&gt;
      this.setClientState(&amp;quot;client_playerPicksLocation&amp;quot;, {&lt;br /&gt;
                                descriptionmyturn : _(&amp;quot;${you} must select location&amp;quot;),&lt;br /&gt;
                            });&lt;br /&gt;
   }&lt;br /&gt;
* Have a handler for onUpdateActionButtons for client_playerPicksLocation to activate all possible locations this worker can go AND add Cancel button (see below)&lt;br /&gt;
* Have a location handler which will eventually send a server request, using stored this.clientStateArgs.worker_id as worker id&lt;br /&gt;
* The cancel button should call a method to restore server state, also if you doing it for more than one state you can add this universally using this.on_client_state check&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
        if (this.isCurrentPlayerActive()) {&lt;br /&gt;
          if (this.on_client_state &amp;amp;&amp;amp; !$(&#039;button_cancel&#039;)) {&lt;br /&gt;
               this.addActionButton(&#039;button_cancel&#039;, _(&#039;Cancel&#039;), dojo.hitch(this, function() {&lt;br /&gt;
                                             this.restoreServerGameState();&lt;br /&gt;
               }));&lt;br /&gt;
          }&lt;br /&gt;
        } &lt;br /&gt;
Note: usually I call my own function call this.cancelLocalStateEffects() which will do more stuff first then call restoreServerGameState(), same function is usually needs to be called when server request has failed (i.e. invalid move)&lt;br /&gt;
&lt;br /&gt;
Note: If you need more than 2 steps, you may have to do client side animation to reflect the new state, which gets trickier because you have to undo that also on cancellation.&lt;br /&gt;
&lt;br /&gt;
Code is available here [https://github.com/elaskavaia/bga-sharedcode/blob/master/sharedcode.js sharedcode.js] (its using playerTurnPlayCubes and client_selectCubeLocation).&lt;br /&gt;
&lt;br /&gt;
=== Action Stack - Using Client States ===&lt;br /&gt;
&lt;br /&gt;
Action stack required where game is very complex and use triggered effects that can &amp;quot;stack&amp;quot;. It not always actual stack, it can be queue or random access&lt;br /&gt;
Examples:&lt;br /&gt;
* Magic the Gathering - classic card game where effects go on Stack, that allows to counter spell and counter spell of counter spell (not on bga - it just example of mechanics)&lt;br /&gt;
* Ultimate Railroads - action taking game where effects can be executed in any order&lt;br /&gt;
* Lewis and Clark - card game where actions executed as queue&lt;br /&gt;
&lt;br /&gt;
There is two ways of implementing it - on the server or the client.&lt;br /&gt;
For the server see article below.&lt;br /&gt;
The requirement for client side stack implementation is - all action can be undone, which means&lt;br /&gt;
* No dice rolls&lt;br /&gt;
* No card drawn&lt;br /&gt;
* No other players interaction&lt;br /&gt;
&lt;br /&gt;
No snippets are here, as this will be too complex but basically flow is:&lt;br /&gt;
* You have a action/effect stack (queue/list) as js object attached to &amp;quot;this&amp;quot;, i.e. this.unprocessed_actions&lt;br /&gt;
* When player plays a card, worker, etc, you read the effect of that card from the material file (client copy), and place into stack&lt;br /&gt;
* Then we call dispatch method which pulls the next action from the stack and change client state accordinly, i.e. this.setClientState(&amp;quot;client_playerGainsCubes&amp;quot;)&lt;br /&gt;
* When players acts on it - the action is removed from the stack and added to &amp;quot;server action arguments&amp;quot; list, this is another object which be used to send ajax call, i.e. this.clientStateArgs&lt;br /&gt;
* If nothing left in stack we can submit the ajax call assembling parameters from collected arguments (that can include action name)&lt;br /&gt;
* This method allows cheap undo - by restoring server state you will wipe out all user actions (but if you need intermediate aninmation you have to handle it yourself)&lt;br /&gt;
&lt;br /&gt;
Code can be found in Ultimate Railroads game (but it is random access list - so it a bit complex) and Lewis and Clark (complexity - user can always deny part of any effect)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Action Stack - Using Server States ===&lt;br /&gt;
&lt;br /&gt;
See definition of Action Stack above.&lt;br /&gt;
&lt;br /&gt;
To implement you usually need another db table that has the following fields: index of effect - which is used for sorted access, type - which is essense of the effect (i.e. collect resource), some extra arguments (i.e. resource type and resource count), and usually owner of the effect (i.e. player id)&lt;br /&gt;
The flow is:&lt;br /&gt;
* There is some initial player state, where player can play card for example&lt;br /&gt;
* Player main action - pushes the card effect on stack, which also can cause triggered effects which also go on stack&lt;br /&gt;
* After action processing is finished switch to game state which is &amp;quot;dispatcher&amp;quot;&lt;br /&gt;
* Dispatcher pulls the top effect (whatever definition of the top is), changes the active player and changes the state to appropriate player state to collect response&lt;br /&gt;
* Player state knows about the stack and pulls arguments (argX) from the effect arguments of the db&lt;br /&gt;
* Player action should clear up the top effect, and can possibly add more effects, then switch to &amp;quot;dispatcher&amp;quot; state again&lt;br /&gt;
* If stack is empty, dispatcher can either pick next player itself or use another game state which responsible for picking next player&lt;br /&gt;
&lt;br /&gt;
Code can be found in Tapestry.&lt;br /&gt;
&lt;br /&gt;
=== Changing state prompt ===&lt;br /&gt;
&lt;br /&gt;
State prompt is message displayed for player which usually comes from state description.&lt;br /&gt;
Sometimes you want to change it without changing state (one way is change state but locally, see client states above).&lt;br /&gt;
&lt;br /&gt;
Simple way just change the html&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        setMainTitle: function(text) {&lt;br /&gt;
            $(&#039;pagemaintitletext&#039;).innerHTML = text;&lt;br /&gt;
        },&lt;br /&gt;
         // usage&lt;br /&gt;
        onMeeple: function(event) {&lt;br /&gt;
              //... &lt;br /&gt;
              this.setMainTitle(_(&#039;You must select where meeple is going&#039;));&lt;br /&gt;
        },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This however will not work with parameters and will not draw You in color, if you want this its more sophisticated:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        setDescriptionOnMyTurn : function(text) {&lt;br /&gt;
            this.gamedatas.gamestate.descriptionmyturn = text;&lt;br /&gt;
            var tpl = dojo.clone(this.gamedatas.gamestate.args);&lt;br /&gt;
            if (tpl === null) {&lt;br /&gt;
                tpl = {};&lt;br /&gt;
            }&lt;br /&gt;
            var title = &amp;quot;&amp;quot;;&lt;br /&gt;
            if (this.isCurrentPlayerActive() &amp;amp;&amp;amp; text !== null) {&lt;br /&gt;
                tpl.you = this.divYou(); &lt;br /&gt;
            }&lt;br /&gt;
            title = this.format_string_recursive(text, tpl);&lt;br /&gt;
&lt;br /&gt;
            if (!title) {&lt;br /&gt;
                this.setMainTitle(&amp;quot;&amp;amp;nbsp;&amp;quot;);&lt;br /&gt;
            } else {&lt;br /&gt;
                this.setMainTitle(title);&lt;br /&gt;
            }&lt;br /&gt;
        },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: this method uses &#039;&#039;&#039;setMainTitle&#039;&#039;&#039; defined above and &#039;&#039;&#039;divYou&#039;&#039;&#039; defined in another section of this wiki.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Assigning Player Order ===&lt;br /&gt;
Normally when game starts there is &amp;quot;natural&amp;quot; player order assigned randomly.&lt;br /&gt;
&lt;br /&gt;
If you want to deliberatly assign player order at the start of the game (for example, in a game with teams options), you can do so by retrieving the initialization-only player attribute &#039;&#039;&#039;player_table_order&#039;&#039;&#039; and using it to assign values to &#039;&#039;&#039;player_no&#039;&#039;&#039; (which is normally assigned at the start of a game in the order in which players come to the table). (See [https://en.doc.boardgamearena.com/Game_database_model:_dbmodel.sql#The_player_table Game database model] for more details.)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
                // Retrieve inital player order ([0=&amp;gt;playerId1, 1=&amp;gt;playerId2, ...])&lt;br /&gt;
		$playerInitialOrder = [];&lt;br /&gt;
		foreach ($players as $playerId =&amp;gt; $player) {&lt;br /&gt;
			$playerInitialOrder[$player[&#039;player_table_order&#039;]] = $playerId;&lt;br /&gt;
		}&lt;br /&gt;
		ksort($playerInitialOrder);&lt;br /&gt;
		$playerInitialOrder = array_flip(array_values($playerInitialOrder));&lt;br /&gt;
&lt;br /&gt;
		// Player order based on &#039;playerTeams&#039; option&lt;br /&gt;
		$playerOrder = [0, 1, 2, 3];&lt;br /&gt;
		switch (self::getGameStateValue(&#039;playerTeams&#039;)) {&lt;br /&gt;
			case self::TEAM_1_2:&lt;br /&gt;
				$playerOrder = [0, 2, 1, 3];&lt;br /&gt;
				break;&lt;br /&gt;
			case self::TEAM_1_4:&lt;br /&gt;
				$playerOrder = [0, 1, 3, 2];&lt;br /&gt;
				break;&lt;br /&gt;
			case self::TEAM_RANDOM:&lt;br /&gt;
				shuffle($playerOrder);&lt;br /&gt;
				break;&lt;br /&gt;
			default:&lt;br /&gt;
			case self::TEAM_1_3:&lt;br /&gt;
				// Default order&lt;br /&gt;
				break;&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
                // Create players&lt;br /&gt;
		// Note: if you added some extra field on &amp;quot;player&amp;quot; table in the database (dbmodel.sql), you can initialize it there.&lt;br /&gt;
		$sql =&lt;br /&gt;
			&#039;INSERT INTO player (player_id, player_color, player_canal, player_name, player_avatar, player_no) VALUES &#039;;&lt;br /&gt;
		$values = [];&lt;br /&gt;
&lt;br /&gt;
		foreach ($players as $playerId =&amp;gt; $player) {&lt;br /&gt;
			$color = array_shift($default_colors);&lt;br /&gt;
			$values[] =&lt;br /&gt;
				&amp;quot;(&#039;&amp;quot; .&lt;br /&gt;
				$playerId .&lt;br /&gt;
				&amp;quot;&#039;,&#039;$color&#039;,&#039;&amp;quot; .&lt;br /&gt;
				$player[&#039;player_canal&#039;] .&lt;br /&gt;
				&amp;quot;&#039;,&#039;&amp;quot; .&lt;br /&gt;
				addslashes($player[&#039;player_name&#039;]) .&lt;br /&gt;
				&amp;quot;&#039;,&#039;&amp;quot; .&lt;br /&gt;
				addslashes($player[&#039;player_avatar&#039;]) .&lt;br /&gt;
				&amp;quot;&#039;,&#039;&amp;quot; .&lt;br /&gt;
				$playerOrder[$playerInitialOrder[$playerId]] .&lt;br /&gt;
				&amp;quot;&#039;)&amp;quot;;&lt;br /&gt;
		}&lt;br /&gt;
		$sql .= implode(&#039;,&#039;, $values);&lt;br /&gt;
		self::DbQuery($sql);&lt;br /&gt;
		self::reattributeColorsBasedOnPreferences(&lt;br /&gt;
			$players,&lt;br /&gt;
			$gameinfos[&#039;player_colors&#039;]&lt;br /&gt;
		);&lt;br /&gt;
		self::reloadPlayersBasicInfos();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Send different notifications to active player vs everybody else ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg.js&lt;br /&gt;
&lt;br /&gt;
Hack alert. This is a hack. We were hoping for proper solution by bga framework.&lt;br /&gt;
&lt;br /&gt;
This will allow you to send notification with two message one for specific player and one for everybody else including spectators.&lt;br /&gt;
Note that this does not split the data - all data must be shared.&lt;br /&gt;
&lt;br /&gt;
Add this to .js file (if you already overriding it merge obviously)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/** @Override */&lt;br /&gt;
format_string_recursive: function(log, args) {&lt;br /&gt;
   if (typeof args.log_others != &#039;undefined&#039; &amp;amp;&amp;amp; typeof args.player_id != &#039;undefined&#039; &amp;amp;&amp;amp; this.player_id != args.player_id)&lt;br /&gt;
	log = args.log_others;&lt;br /&gt;
   return this.inherited(arguments); // you must call this to call super &lt;br /&gt;
},&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example of usage (from eminentdomain)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    $this-&amp;gt;notifyAllPlayers(&#039;tokenMoved&#039;, &lt;br /&gt;
             clienttranslate(&#039;${player_name} adds +2 Colonies to ${place_name}&#039;), // notification with show for player with player_id&lt;br /&gt;
             [&#039;player_id&#039;=&amp;gt;$player_id, // this is mandatory&lt;br /&gt;
             &#039;log_others&#039;=&amp;gt;clienttranslate(&#039;${player_name} adds +2 Colonies to an unknown planet&#039;), // notification will show for others&lt;br /&gt;
              ...&lt;br /&gt;
             ]);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Send transient notifications without incrementing move ID ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg.php&lt;br /&gt;
&lt;br /&gt;
Hack alert. This is a hack.&lt;br /&gt;
&lt;br /&gt;
Use this if you need to send some transient notification that should not create a new move ID. The notification should be idempotent -- it should have no practical effect on the game state and would be &#039;&#039;&#039;safe to drop&#039;&#039;&#039; (e.g., it would not matter if a player never received this notification). For example, in a co-op game you want all players to see a real-time preview of some action, before the active player commits their turn.&lt;br /&gt;
&lt;br /&gt;
Doing this mainly affects the instant replay &amp;amp; archive modes. During replay, the BGA framework automatically inserts a 1.5-second pause between each &amp;quot;move&amp;quot;. With this hack, your transient notifications are not considered to be a &amp;quot;move&amp;quot;, so no pause gets added.&lt;br /&gt;
&lt;br /&gt;
; In ggg.php&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$this-&amp;gt;not_a_move_notification = true; // note: do not increase the move counter&lt;br /&gt;
$this-&amp;gt;notifyAllPlayers(&#039;cardsPreview&#039;, &#039;&#039;, $args);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: you cannot have code that send notification or even changes state after this, and you cannot reset this variable back either because it only takes effect when you exit action handling function&lt;br /&gt;
&lt;br /&gt;
=== Ajax Call wrapper ===&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg.js&lt;br /&gt;
&lt;br /&gt;
The current ajaxcall is super vebose and prone to errors, I suggest using a helper function. It does a lot of stuff you must do anyways.&lt;br /&gt;
Most beginner mistakes come from missing part of this code (which is understandstandable - this is a huge snippet to clone every time).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	ajaxcallwrapper: function(action, args, handler) {&lt;br /&gt;
		if (!args) args = []; // this allows to skip args parameter for action which do not require them&lt;br /&gt;
			&lt;br /&gt;
		args.lock = true; // this allows to avoid rapid action clicking which can cause race condition on server&lt;br /&gt;
		if (this.checkAction(action)) { // this does all the proper check that player is active and action is declared&lt;br /&gt;
			this.ajaxcall(&amp;quot;/&amp;quot; + this.game_name + &amp;quot;/&amp;quot; + this.game_name + &amp;quot;/&amp;quot; + action + &amp;quot;.html&amp;quot;, args, // this is mandatory fluff &lt;br /&gt;
				this, (result) =&amp;gt; { },  // success result handler is empty - it is never needed&lt;br /&gt;
                                               handler); // this is real result handler - it called both on success and error, it has optional param  &amp;quot;is_error&amp;quot; - you rarely need it&lt;br /&gt;
			}&lt;br /&gt;
		},&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Usage:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   this.ajaxcallwrapper(&#039;pass&#039;); // no args&lt;br /&gt;
   this.ajaxcallwrapper(&#039;playCard&#039;, {card: card_id}); // with args&lt;br /&gt;
   this.ajaxcallwrapper(&#039;playCard&#039;, {card: card_id}, (is_error)=&amp;gt;{if (!is_error) dojo.query(&amp;quot;.selected&amp;quot;).removeClass(&#039;selected&#039;);}) // with handler that cleans up &#039;selected&#039; class on success&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: this always will lock interface and always check for action, you can modify this method to do it optionally, i.e&lt;br /&gt;
  if (args.lock!==false) args.lock = true; else delete args.lock; // it does not work with false value - it has to be removed&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Custom error/exception handling in JavaScript ===&lt;br /&gt;
&lt;br /&gt;
; In ggg.php&lt;br /&gt;
We intentionally throw BgaUserException to rollback database transaction and cancel all changes. Note that any notifications are also cancelled!&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    function foo(bool $didConfirm = false): void&lt;br /&gt;
    {&lt;br /&gt;
        // do processing for the user&#039;s move&lt;br /&gt;
        // afterwards, you determine this move will end the game&lt;br /&gt;
        // so you want to rollback the transaction and require the user to confirm the move first&lt;br /&gt;
&lt;br /&gt;
        if ($gameIsEnding &amp;amp;&amp;amp; !$didConfirm) {&lt;br /&gt;
            throw new BgaUserException(&#039;!!!endGameWarning&#039;);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; In ggg.js&lt;br /&gt;
We define a global variable at the top to store the last error code&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  var lastErrorCode = null;&lt;br /&gt;
  return declare(&amp;quot;bgagame.ggg&amp;quot;, ebg.core.gamegui, {&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We override framework function showMessage to populate the last error code and suppress the red banner message and log message&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    /* @Override */&lt;br /&gt;
    showMessage: function (msg, type) {&lt;br /&gt;
      if (type == &amp;quot;error&amp;quot;) {&lt;br /&gt;
        lastErrorCode = msg.startsWith(&amp;quot;!!!&amp;quot;) ? msg.substring(3) : null;&lt;br /&gt;
        if (lastErrorCode) {&lt;br /&gt;
          return; // suppress red banner and log message&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
      this.inherited(arguments);&lt;br /&gt;
    },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Since the framework calls showMessage before your ajaxcall error handler, you can deal with the error in-place:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    fooAction: function (didConfirm) {&lt;br /&gt;
      var data = {&lt;br /&gt;
        foo: &amp;quot;bar&amp;quot;,&lt;br /&gt;
        didConfirm: !!didConfirm,&lt;br /&gt;
      };&lt;br /&gt;
      this.ajaxcallwrapper(&amp;quot;fooAction&amp;quot;, data, function (error) {&lt;br /&gt;
        if (lastErrorCode == &amp;quot;endGameWarning&amp;quot;) {&lt;br /&gt;
          // your custom error handling goes here&lt;br /&gt;
          // for example, show a confirmation dialog and repeat the action with additional param&lt;br /&gt;
          this.confirmationDialog(&lt;br /&gt;
            _(&amp;quot;Doing the foo action now will end the game&amp;quot;),&lt;br /&gt;
            () =&amp;gt; {&lt;br /&gt;
              this.fooAction(true);&lt;br /&gt;
            }&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
      });&lt;br /&gt;
    },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Disable / lock table creation for new deploy ===&lt;br /&gt;
&lt;br /&gt;
If you are deploying a major new game version, especially if it involves upgrading production game databases, you may have a lot of angry players if you break their tables.  Depending on your changes, you may be able to restore the previous version and fix the tables easily.&lt;br /&gt;
&lt;br /&gt;
However, if a new deploy turns out bad and players created turn-based tables while it was live, it may be quite difficult to fix those tables, since they were created from a bad deploy.&lt;br /&gt;
&lt;br /&gt;
The solution?  You can announce in your game group that you are locking table creation, and then in your new version, add an impossible startcondition to an existing option.  Here is an example of an option with only 2 values:&lt;br /&gt;
&lt;br /&gt;
; In gameoptions.inc.php&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// TODO NEXT remove after testing deploy to upgrade&lt;br /&gt;
&#039;startcondition&#039; =&amp;gt; [&lt;br /&gt;
   OPT_VALUE_DISABLE =&amp;gt; [ [ &#039;type&#039; =&amp;gt; &#039;minplayers&#039;, &#039;value&#039; =&amp;gt; 32, &#039;message&#039; =&amp;gt; totranslate(&#039;Maintenance in progress.  Table creation disabled.&#039;) ] ],&lt;br /&gt;
   OPT_VALUE_ENABLE =&amp;gt; [ [ &#039;type&#039; =&amp;gt; &#039;minplayers&#039;, &#039;value&#039; =&amp;gt; 32, &#039;message&#039; =&amp;gt; totranslate(&#039;Maintenance in progress.  Table creation disabled.&#039;) ] ],&lt;br /&gt;
],&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Be sure to click &amp;quot;Reload game options configuration&amp;quot; after making this change.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Now, when a player attempts to create a new lobby, they will see a red error bar with your &amp;quot;Maintenance in progress&amp;quot; message.  Once you confirm the new deploy looks good, you can revert the change in gameoptions.inc.php and do another deploy.&lt;br /&gt;
&lt;br /&gt;
== Algorithms ==&lt;br /&gt;
&lt;br /&gt;
=== Generate permutations in lexicographic order ===&lt;br /&gt;
&lt;br /&gt;
Use this when you have an array like [1, 2, 3, 4] and need to loop over some/all 24 permutations of possible ordering. This type of [https://www.php.net/manual/en/language.generators.syntax.php generator function] computes each possibility one at a time, making it vastly more efficient than either a normal iteration or recursive function that produce all possibilities up front.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function generatePermutations(array $array): Generator&lt;br /&gt;
{&lt;br /&gt;
    // https://en.wikipedia.org/wiki/Permutation#Generation_in_lexicographic_order&lt;br /&gt;
    // Sort the array and this is the first permutation&lt;br /&gt;
    sort($array);&lt;br /&gt;
    yield $array;&lt;br /&gt;
&lt;br /&gt;
    $count = count($array);&lt;br /&gt;
    do {&lt;br /&gt;
        // Find the largest index k where a[k] &amp;lt; a[k + 1]&lt;br /&gt;
        // End when no such index exists&lt;br /&gt;
        $found = false;&lt;br /&gt;
        for ($k = $count - 2; $k &amp;gt;= 0; $k--) {&lt;br /&gt;
            $kvalue = $array[$k];&lt;br /&gt;
            $knext = $array[$k + 1];&lt;br /&gt;
            if ($kvalue &amp;lt; $knext) {&lt;br /&gt;
                // Find the largest index l greater than k where a[k] &amp;lt; a[l]&lt;br /&gt;
                for ($l = $count - 1; $l &amp;gt; $k; $l--) {&lt;br /&gt;
                    $lvalue = $array[$l];&lt;br /&gt;
                    if ($kvalue &amp;lt; $lvalue) {&lt;br /&gt;
                        // Swap a[k] and a[l]&lt;br /&gt;
                        [$array[$k], $array[$l]] = [$array[$l], $array[$k]];&lt;br /&gt;
&lt;br /&gt;
                        // Reverse the sequence from a[k + 1] up to and including the final element&lt;br /&gt;
                        $reverse = array_reverse(array_slice($array, $k + 1));&lt;br /&gt;
                        array_splice($array, $k + 1, $count, $reverse);&lt;br /&gt;
                        yield $array;&lt;br /&gt;
&lt;br /&gt;
                        // Restart with the new array to find the next permutation&lt;br /&gt;
                        $found = true;&lt;br /&gt;
                        break 2;&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    } while ($found);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Usage:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$cash = [4, 1, 2, 3, 4];&lt;br /&gt;
foreach ($this-&amp;gt;generatePermutations($cash) as $p) {&lt;br /&gt;
    // your code here to evaluate permutation $p&lt;br /&gt;
    // first iteration: $p = [1, 2, 3, 4, 4]&lt;br /&gt;
    // last (60th) iteration: $p = [4, 4, 3, 2, 1]&lt;br /&gt;
    // break from loop once you achieve your goal&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:Studio]]&lt;/div&gt;</summary>
		<author><name>Archduke</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Studio&amp;diff=17382</id>
		<title>Studio</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Studio&amp;diff=17382"/>
		<updated>2023-07-05T09:11:08Z</updated>

		<summary type="html">&lt;p&gt;Archduke: /* Software Versions */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Studio_Framework_Navigation}}&lt;br /&gt;
&lt;br /&gt;
[[File:Bga_studio_small.jpg]]&lt;br /&gt;
&lt;br /&gt;
Note: Please DO NOT translate Studio Documentation, so that there can be one place where you can find the latest information available.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
== What is Board Game Arena Studio? ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Board Game Arena Studio&#039;&#039;&#039; is a platform to build online board game adaptations using the Board Game Arena platform.&lt;br /&gt;
&lt;br /&gt;
It is open to any gamer with software development skills :)&lt;br /&gt;
&lt;br /&gt;
BGA Studio website: https://studio.boardgamearena.com&lt;br /&gt;
&lt;br /&gt;
Original announcement on BGA forum: https://forum.boardgamearena.com/viewtopic.php?f=10&amp;amp;t=1973&lt;br /&gt;
&lt;br /&gt;
== Discover BGA Studio in 5 presentations ==&lt;br /&gt;
&lt;br /&gt;
Why, how, what... to start discovering BGA Studio, we prepared 5 &amp;quot;powerpoint&amp;quot; presentations for you:&lt;br /&gt;
&lt;br /&gt;
* [http://www.slideshare.net/boardgamearena/5-reasons-why-you-should-use-bga-studio-for-your-online-board-game 5 reasons why you should use BGA Studio for your online board game] (or [http://en.doc.boardgamearena.com/images/5/58/1-why-developing.pdf ‎Download as PDF])&lt;br /&gt;
* [http://www.slideshare.net/boardgamearena/the-8-steps-to-create-a-board-game-on-board-game-arena The 8 steps to create a board game on Board Game Arena] (or [http://en.doc.boardgamearena.com/images/1/1e/2-8-steps-to-realize.pdf Download as PDF])&lt;br /&gt;
* [http://www.slideshare.net/boardgamearena/the-bga-framework-at-a-glance The BGA Framework at a glance] (or [http://en.doc.boardgamearena.com/images/7/79/3-thebgaframework.pdf Download as PDF])&lt;br /&gt;
* [http://www.slideshare.net/boardgamearena/bga-studio-focus-on-bga-game-state-machine Focus on BGA game state machine] (or [http://en.doc.boardgamearena.com/images/9/98/4-gamestates.pdf Download as PDF])&lt;br /&gt;
* [http://www.slideshare.net/boardgamearena/bga-studio-guidelines BGA developers guidelines] (or [http://en.doc.boardgamearena.com/images/7/76/5-guidelines.pdf ‎Download as PDF])&lt;br /&gt;
&lt;br /&gt;
== How to join the BGA developer team? ==&lt;br /&gt;
&lt;br /&gt;
Please see this page: [[How to join BGA developer team?]]&lt;br /&gt;
&lt;br /&gt;
== Great, I&#039;m in! ... How should I start? ==&lt;br /&gt;
&lt;br /&gt;
If you didn&#039;t already, check the presentations at the top of this page to get the basics.&lt;br /&gt;
&lt;br /&gt;
Then, you should checkout the [[First steps with BGA Studio]] to make sure that runs fine.&lt;br /&gt;
&lt;br /&gt;
After that, we strongly advise you to take one of these game creation tutorials:&lt;br /&gt;
* [[Tutorial reversi]] - an abstract strategy game played on an 8×8 uncheckered board for 2 players&lt;br /&gt;
* [[Tutorial gomoku]] - an abstract strategy game tic-tac-toe style for 2 players&lt;br /&gt;
* [[Tutorial hearts]] - a card game for 4 players&lt;br /&gt;
&lt;br /&gt;
Then start editing files and see what happens! ;)&lt;br /&gt;
&lt;br /&gt;
Once you&#039;re done with tutorials, you can start a real game (or join existing project)&lt;br /&gt;
* [[Create a game in BGA Studio: Complete Walkthrough]] &lt;br /&gt;
&lt;br /&gt;
If you have any questions, please check out the [[Studio FAQ]] or [[Contact BGA Studio]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
To search wiki pages on studio enter this text in search bar: &lt;br /&gt;
  &amp;quot;Category:Studio&amp;quot; white rabbit &lt;br /&gt;
That is if you want to search for white rabbit&lt;br /&gt;
&lt;br /&gt;
== BGA Studio documentation ==&lt;br /&gt;
&lt;br /&gt;
=== BGA Studio Framework reference ===&lt;br /&gt;
&lt;br /&gt;
This part of the documentation focuses on the development framework itself: functions and methods available to build your game.&lt;br /&gt;
&lt;br /&gt;
[[Studio file reference|File structure of a BGA game]]&lt;br /&gt;
&lt;br /&gt;
==== Game logic (Server side) ====&lt;br /&gt;
&lt;br /&gt;
* [[Main game logic: yourgamename.game.php]]&lt;br /&gt;
* [[Your game state machine: states.inc.php]]&lt;br /&gt;
* [[Game database model: dbmodel.sql]]&lt;br /&gt;
* [[Players actions: yourgamename.action.php]]&lt;br /&gt;
* [[Game material description: material.inc.php]]&lt;br /&gt;
* [[Game statistics: stats.inc.php]]&lt;br /&gt;
&lt;br /&gt;
==== Game interface (Client side) ====&lt;br /&gt;
&lt;br /&gt;
* [[Game interface logic: yourgamename.js]]&lt;br /&gt;
* [[Game art: img directory]]&lt;br /&gt;
* [[Game interface stylesheet: yourgamename.css]]&lt;br /&gt;
* [[Game layout: view and template: yourgamename.view.php and yourgamename_yourgamename.tpl]]&lt;br /&gt;
* [[Your game mobile version]]&lt;br /&gt;
&lt;br /&gt;
==== Other components ====&lt;br /&gt;
&lt;br /&gt;
* [[Translations]] (how to make your game translatable)&lt;br /&gt;
* [[Game options and preferences: gameoptions.inc.php]]&lt;br /&gt;
* [[Game meta-information: gameinfos.inc.php]]&lt;br /&gt;
* [[Game replay]]&lt;br /&gt;
* [[3D]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== BGA Studio game components reference ===&lt;br /&gt;
&lt;br /&gt;
Game components are useful tools you can use in your game adaptations.&lt;br /&gt;
&lt;br /&gt;
JS:&lt;br /&gt;
&lt;br /&gt;
* [[Counter]]: a JS component to manage a counter that can increase/decrease (ex: player&#039;s score).&lt;br /&gt;
* [[Scrollmap]]: a JS component to manage a scrollable game area (useful when the game area can be infinite. Examples:  Saboteur or Takenoko games).&lt;br /&gt;
* [[Stock]]: a JS component to manage and display a set of game elements displayed at a position.&lt;br /&gt;
* [[Zone]]: a JS component to manage a zone of the board where several game elements can come and leave, but should be well displayed together (See for example: token&#039;s places at Can&#039;t Stop).&lt;br /&gt;
* [[Draggable]]: a JS component to manage drag&#039;n&#039;drop actions.&lt;br /&gt;
* [[ExpandableSection]]: a JS component to manage a rectangular block of HTML than can be displayed/hidden.&lt;br /&gt;
* [[Anti-Stock]]:Code snippets in ValinaJS/HTML5 to do what stock does (that is if you cannot beat Stock into submission)&lt;br /&gt;
&lt;br /&gt;
PHP:&lt;br /&gt;
* [[Deck]]: a PHP component to manage cards (deck, hands, picking cards, moving cards, shuffle deck, ...).&lt;br /&gt;
&lt;br /&gt;
Reference for classes in game class hierarchy&lt;br /&gt;
&lt;br /&gt;
* [[Table]]: a PHP class that you inherit from for the game php&lt;br /&gt;
&lt;br /&gt;
=== BGA Studio user guide ===&lt;br /&gt;
&lt;br /&gt;
This part of the documentation is a user guide for the BGA Studio online development environment.&lt;br /&gt;
&lt;br /&gt;
Lifecycle&lt;br /&gt;
&lt;br /&gt;
* [[BGA game Lifecycle]]&lt;br /&gt;
* [[Create a game in BGA Studio: Complete Walkthrough]]&lt;br /&gt;
* [[Pre-release checklist]] - Go throught this list if you think you done development&lt;br /&gt;
* [[Post-release phase]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Tools and Advice&lt;br /&gt;
* [[BGA Studio Guidelines]]&lt;br /&gt;
* [[Tutorials checklist]]&lt;br /&gt;
* [[I wish I knew this when I started]] - one liners on most common missed features, mistakes, etc with further doc references&lt;br /&gt;
* [[Tools and tips of BGA Studio]] - Tips and instructions on setting up development environment&lt;br /&gt;
** [[Setting up BGA Development environment using VSCode]]&lt;br /&gt;
** [[Practical debugging]] - Tips focused on debugging&lt;br /&gt;
** [[Testing by developer]]&lt;br /&gt;
** [[Studio logs]] - Instructions for log access&lt;br /&gt;
** [[Troubleshooting]] - Most common &amp;quot;I am really stuck&amp;quot; situations&lt;br /&gt;
* [[BGA Studio Cookbook]] - Tips and instructions on using API&#039;s, libraries and frameworks&lt;br /&gt;
** [[Using Vue]] - work-in-progress guide on using the modern framework Vue.js to create a game&lt;br /&gt;
** [[Using Typescript and Scss]] - How to auto-build Typescript and SCSS files to make your code cleaner&lt;br /&gt;
** [[Bots and Artificial Intelligence]] - How to add AI/Bots to the game&lt;br /&gt;
* [[Studio FAQ]]&lt;br /&gt;
&lt;br /&gt;
Sharing&lt;br /&gt;
* [[Common board game elements image resources]] - Dice, meeples, cubes, etc&lt;br /&gt;
* [[BGA Code Sharing]] - Shared resources, projects on git hub, common code, other links&lt;br /&gt;
&lt;br /&gt;
== Software Versions ==&lt;br /&gt;
&lt;br /&gt;
Versions currently used by BGA framework:&lt;br /&gt;
&lt;br /&gt;
* Dojo Toolkit 1.15&lt;br /&gt;
* PHP: 7.4&lt;br /&gt;
* SQL: MySQL 5.7&lt;br /&gt;
* JS/CSS/HTML: limited by what minimization tools support [[Game_interface_logic:_yourgamename.js#Javascript_minimization_.28after_July_2020.29]]&lt;br /&gt;
* Font Awesome: 4.7 https://fontawesome.com/v4.7/icons/ (available as &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;&amp;lt;i class=&amp;quot;fa fa-clock&amp;quot; /&amp;gt;&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;)&lt;br /&gt;
* Font Awesome: 6.4.0 https://fontawesome.com/v6/search?o=r&amp;amp;m=free (available as &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;&amp;lt;i class=&amp;quot;fa6 fa6-clock&amp;quot; /&amp;gt;&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
=== PHP Extensions Used ===&lt;br /&gt;
&lt;br /&gt;
The following PHP extensions are - as of May 8th, 2022 - in use in BGA Studio and available:&lt;br /&gt;
&lt;br /&gt;
date, libxml, openssl, pcre, zlib, filter, hash, Reflection, SPL, session, standard, sodium, apache2handler, mysqlnd, PDO, xml, apcu, bz2, calendar, ctype, curl, dom, mbstring, FFI, fileinfo, ftp, gd, gettext, gmp, iconv, igbinary, json, exif, msgpack, mysqli, pdo_mysql, apc, posix, readline, shmop, SimpleXML, sockets, sysvmsg, sysvsem, sysvshm, tokenizer, v8js, xmlreader, xmlwriter, xsl, zip, Phar, memcached, Zend OPcache&lt;br /&gt;
&lt;br /&gt;
== Other resources ==&lt;br /&gt;
&lt;br /&gt;
[http://forum.boardgamearena.com/viewforum.php?f=12 Development forum]&lt;br /&gt;
&lt;br /&gt;
[https://studio.boardgamearena.com/bugs Bug tracking system FOR STUDIO issues and APIs]&lt;br /&gt;
&lt;br /&gt;
DISCORD chat server/room invite link https://discord.gg/YxEUacY if it does not work check this topic https://forum.boardgamearena.com/viewtopic.php?f=12&amp;amp;t=17403&amp;amp;hilit=discord&lt;br /&gt;
&lt;br /&gt;
Developer BLOGS https://bga-devs.github.io/blog/&lt;br /&gt;
&lt;br /&gt;
[[Contact BGA Studio]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Studio]]&lt;/div&gt;</summary>
		<author><name>Archduke</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Template:Studio_Framework_Navigation&amp;diff=17052</id>
		<title>Template:Studio Framework Navigation</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Template:Studio_Framework_Navigation&amp;diff=17052"/>
		<updated>2023-05-31T08:13:59Z</updated>

		<summary type="html">&lt;p&gt;Archduke: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;!-- Do not use heading tags, or else these sidebar headings appear in the page TOCs --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;studio-framework-navigation&amp;quot; style=&amp;quot;float: right; width: 300px; border: solid #000 1px; padding: 1em; margin-left: 1em; background: #fff;&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-weight:bold;font-size:1.2em;margin-top:0.3em;line-height:1.6;padding-top:0.5em;&amp;quot;&amp;gt;&amp;lt;center&amp;gt;&#039;&#039;&#039;Game File Reference&#039;&#039;&#039;&amp;lt;/center&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-weight:bold;font-size:1.2em;margin-top:0.3em;line-height:1.6;padding-top:0.5em;&amp;quot;&amp;gt;&amp;lt;center&amp;gt;&#039;&#039;&#039;[[Studio file reference|Overview]]&#039;&#039;&#039;&amp;lt;/center&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* [[Game database model: dbmodel.sql|&amp;lt;b&amp;gt;dbmodel.sql&amp;lt;/b&amp;gt;]] - database model&lt;br /&gt;
* [[Game meta-information: gameinfos.inc.php|&amp;lt;b&amp;gt;gameinfos.inc.php&amp;lt;/b&amp;gt;]] - meta-information&lt;br /&gt;
* [[Game options and preferences: gameoptions.inc.php|&amp;lt;b&amp;gt;gameoptions.inc.php&amp;lt;/b&amp;gt;]] - game options &amp;amp; user preferences&lt;br /&gt;
* [[Game art: img directory|&amp;lt;b&amp;gt;img/&amp;lt;/b&amp;gt;]] - game art&lt;br /&gt;
* [[Game_metadata_manager|&amp;lt;b&amp;gt;Game Metadata Manager&amp;lt;/b&amp;gt;]] - tags and metadata media&lt;br /&gt;
* [[Game material description: material.inc.php|&amp;lt;b&amp;gt;material.inc.php&amp;lt;/b&amp;gt;]] - static data&lt;br /&gt;
* &amp;lt;b&amp;gt;misc/&amp;lt;/b&amp;gt; - studio-only storage&lt;br /&gt;
* &amp;lt;b&amp;gt;modules/&amp;lt;/b&amp;gt; - additional game code&lt;br /&gt;
* [[Your game state machine: states.inc.php|&amp;lt;b&amp;gt;states.inc.php&amp;lt;/b&amp;gt;]] - state machine&lt;br /&gt;
* [[Game statistics: stats.inc.php|&amp;lt;b&amp;gt;stats.inc.php&amp;lt;/b&amp;gt;]] - statistics&lt;br /&gt;
* [[Players actions: yourgamename.action.php|X.&amp;lt;b&amp;gt;action.php&amp;lt;/b&amp;gt;]] - player actions&lt;br /&gt;
* [[Game interface stylesheet: yourgamename.css|X&amp;lt;b&amp;gt;.css&amp;lt;/b&amp;gt;]] - interface stylesheet&lt;br /&gt;
* [[Main game logic: yourgamename.game.php|X.&amp;lt;b&amp;gt;game.php&amp;lt;/b&amp;gt;]] - main logic&lt;br /&gt;
* [[Game interface logic: yourgamename.js|X.&amp;lt;b&amp;gt;js&amp;lt;/b&amp;gt;]] - interface logic&lt;br /&gt;
* [[Game layout: view and template: yourgamename.view.php and yourgamename_yourgamename.tpl|X.&amp;lt;b&amp;gt;view.php&amp;lt;/b&amp;gt;]] - dynamic game layout&lt;br /&gt;
* [[Game layout: view and template: yourgamename.view.php and yourgamename_yourgamename.tpl|X_X.&amp;lt;b&amp;gt;tpl&amp;lt;/b&amp;gt;]] - static game layout&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
-----&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-weight:bold;font-size:1.2em;margin-top:0.3em;line-height:1.6;padding-top:0.5em;&amp;quot;&amp;gt;&amp;lt;center&amp;gt;&#039;&#039;&#039;Useful Components&#039;&#039;&#039;&amp;lt;/center&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Official&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* [[Deck]]: a PHP component to manage cards (deck, hands, picking cards, moving cards, shuffle deck, ...).&lt;br /&gt;
* [[Draggable]]: a JS component to manage drag&#039;n&#039;drop actions.&lt;br /&gt;
* [[Counter]]: a JS component to manage a counter that can increase/decrease (ex: player&#039;s score).&lt;br /&gt;
* [[ExpandableSection]]: a JS component to manage a rectangular block of HTML than can be displayed/hidden.&lt;br /&gt;
* [[Scrollmap]]: a JS component to manage a scrollable game area (useful when the game area can be infinite. Examples:  Saboteur or Takenoko games).&lt;br /&gt;
* [[Stock]]: a JS component to manage and display a set of game elements displayed at a position.&lt;br /&gt;
* [[Zone]]: a JS component to manage a zone of the board where several game elements can come and leave, but should be well displayed together (See for example: token&#039;s places at Can&#039;t Stop).&lt;br /&gt;
&lt;br /&gt;
Undocumented component (if somebody knows please help with docs)&lt;br /&gt;
* [[Wrapper]]: a JS component to wrap a  &amp;amp;lt;div&amp;amp;gt; element around its child, even if these elements are absolute positioned.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Unofficial&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* [[BGA Code Sharing]] - Shared resources, projects on git hub, common code, other links&lt;br /&gt;
* [[BGA Studio Cookbook]] - Tips and instructions on using API&#039;s, libraries and frameworks&lt;br /&gt;
* [[Some usual board game elements image ressources]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
-----&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-weight:bold;font-size:1.2em;margin-top:0.3em;line-height:1.6;padding-top:0.5em;&amp;quot;&amp;gt;&amp;lt;center&amp;gt;&#039;&#039;&#039;Game Development Process&#039;&#039;&#039;&amp;lt;/center&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* [[First steps with BGA Studio]]&lt;br /&gt;
* [[Create a game in BGA Studio: Complete Walkthrough]]&lt;br /&gt;
* [[Tutorial reversi]] &lt;br /&gt;
* [[Tutorial gomoku]] &lt;br /&gt;
* [[Tutorial hearts]]&lt;br /&gt;
* [[BGA Studio Guidelines]]&lt;br /&gt;
* [[BGA game Lifecycle]]&lt;br /&gt;
* [[Pre-release checklist]]&lt;br /&gt;
* [[Post-release phase]]&lt;br /&gt;
* [[Help|Player Resources]] - add player help/rules to your game page&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
-----&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-weight:bold;font-size:1.2em;margin-top:0.3em;line-height:1.6;padding-top:0.5em;&amp;quot;&amp;gt;&amp;lt;center&amp;gt;&#039;&#039;&#039;Guides for Common Topics&#039;&#039;&#039;&amp;lt;/center&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* [[Translations]] - make your game translatable&lt;br /&gt;
* [[Game replay|Game Replay]]&lt;br /&gt;
* [[Your game mobile version|Mobile Users]]&lt;br /&gt;
* [[3D]]&lt;br /&gt;
* [[Compatibility]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
-----&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-weight:bold;font-size:1.2em;margin-top:0.3em;line-height:1.6;padding-top:0.5em;&amp;quot;&amp;gt;&amp;lt;center&amp;gt;&#039;&#039;&#039;Miscellaneous Resources&#039;&#039;&#039;&amp;lt;/center&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* [[Studio FAQ]]&lt;br /&gt;
* [[Tools and tips of BGA Studio]] - Tips and instructions on setting up development environment&lt;br /&gt;
* [[Studio logs]] - Instructions for log access&lt;br /&gt;
* [[Practical debugging]] - Tips focused on debugging&lt;br /&gt;
* [[Troubleshooting]] - Most common &amp;quot;I am really stuck&amp;quot; situations&lt;br /&gt;
* [https://studio.boardgamearena.com/bugs Studio Bugs] - Reports against Studio itself (not BGA!)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Archduke</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Compatibility&amp;diff=17051</id>
		<title>Compatibility</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Compatibility&amp;diff=17051"/>
		<updated>2023-05-31T08:13:45Z</updated>

		<summary type="html">&lt;p&gt;Archduke: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Studio_Framework_Navigation}}&lt;br /&gt;
&lt;br /&gt;
The mainsite is built with compatibility for several old browsers.&lt;br /&gt;
&lt;br /&gt;
We use a [https://browsersl.ist/#q=last+2+versions%2C+not+dead%2C+%3E+0.2%25 browserslist] config to define the targeted browsers: &amp;lt;code&amp;gt;last 2 versions, not dead, &amp;gt; 0.2%&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
There are currently no hard rules about what you should target, but it is recommended to follow the same targets as the mainsite. You can use [https://babeljs.io/ babel] to compile your modern JavaScript code into backwards compatible code. Babel accepts a browserslist targets string, so you can use the targets above.&lt;br /&gt;
&lt;br /&gt;
== Current list ==&lt;br /&gt;
&lt;br /&gt;
At time of writing, &amp;lt;code&amp;gt;last 2 versions, not dead, &amp;gt; 0.2%&amp;lt;/code&amp;gt; refers to:&lt;br /&gt;
&lt;br /&gt;
* and_chr 113&lt;br /&gt;
* and_ff 113&lt;br /&gt;
* and_qq 13.1&lt;br /&gt;
* and_uc 13.4&lt;br /&gt;
* android 113&lt;br /&gt;
* android 4.4.3-4.4.4&lt;br /&gt;
* chrome 113&lt;br /&gt;
* chrome 112&lt;br /&gt;
* chrome 111&lt;br /&gt;
* chrome 110&lt;br /&gt;
* chrome 109&lt;br /&gt;
* chrome 108&lt;br /&gt;
* chrome 103&lt;br /&gt;
* chrome 79&lt;br /&gt;
* edge 113&lt;br /&gt;
* edge 112&lt;br /&gt;
* edge 111&lt;br /&gt;
* firefox 113&lt;br /&gt;
* firefox 112&lt;br /&gt;
* firefox 111&lt;br /&gt;
* ie 11&lt;br /&gt;
* ios_saf 16.4&lt;br /&gt;
* ios_saf 16.3&lt;br /&gt;
* ios_saf 16.2&lt;br /&gt;
* ios_saf 16.1&lt;br /&gt;
* ios_saf 16.0&lt;br /&gt;
* ios_saf 15.6&lt;br /&gt;
* ios_saf 15.5&lt;br /&gt;
* ios_saf 14.5-14.8&lt;br /&gt;
* ios_saf 14.0-14.4&lt;br /&gt;
* ios_saf 12.2-12.5&lt;br /&gt;
* kaios 3.0-3.1&lt;br /&gt;
* kaios 2.5&lt;br /&gt;
* op_mini all&lt;br /&gt;
* op_mob 73&lt;br /&gt;
* opera 98&lt;br /&gt;
* opera 97&lt;br /&gt;
* opera 96&lt;br /&gt;
* safari 16.4&lt;br /&gt;
* safari 16.3&lt;br /&gt;
* safari 16.2&lt;br /&gt;
* safari 16.1&lt;br /&gt;
* safari 15.6&lt;br /&gt;
* safari 14.1&lt;br /&gt;
* samsung 20&lt;br /&gt;
* samsung 19.0&lt;br /&gt;
&lt;br /&gt;
[[Category:Studio]]&lt;/div&gt;</summary>
		<author><name>Archduke</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Compatibility&amp;diff=17050</id>
		<title>Compatibility</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Compatibility&amp;diff=17050"/>
		<updated>2023-05-31T08:12:12Z</updated>

		<summary type="html">&lt;p&gt;Archduke: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Studio_Framework_Navigation}}&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
The mainsite is built with compatibility for several old browsers.&lt;br /&gt;
&lt;br /&gt;
We use a [https://browsersl.ist/#q=last+2+versions%2C+not+dead%2C+%3E+0.2%25 browserslist] config to define the targeted browsers: &amp;lt;code&amp;gt;last 2 versions, not dead, &amp;gt; 0.2%&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
There are currently no hard rules about what you should target, but it is recommended to follow the same targets as the mainsite. You can use [https://babeljs.io/ babel] to compile your modern JavaScript code into backwards compatible code. Babel accepts a browserslist targets string, so you can use the targets above.&lt;br /&gt;
&lt;br /&gt;
== Current list ==&lt;br /&gt;
&lt;br /&gt;
At time of writing, &amp;lt;code&amp;gt;last 2 versions, not dead, &amp;gt; 0.2%&amp;lt;/code&amp;gt; refers to:&lt;br /&gt;
&lt;br /&gt;
and_chr 113&lt;br /&gt;
and_ff 113&lt;br /&gt;
and_qq 13.1&lt;br /&gt;
and_uc 13.4&lt;br /&gt;
android 113&lt;br /&gt;
android 4.4.3-4.4.4&lt;br /&gt;
chrome 113&lt;br /&gt;
chrome 112&lt;br /&gt;
chrome 111&lt;br /&gt;
chrome 110&lt;br /&gt;
chrome 109&lt;br /&gt;
chrome 108&lt;br /&gt;
chrome 103&lt;br /&gt;
chrome 79&lt;br /&gt;
edge 113&lt;br /&gt;
edge 112&lt;br /&gt;
edge 111&lt;br /&gt;
firefox 113&lt;br /&gt;
firefox 112&lt;br /&gt;
firefox 111&lt;br /&gt;
ie 11&lt;br /&gt;
ios_saf 16.4&lt;br /&gt;
ios_saf 16.3&lt;br /&gt;
ios_saf 16.2&lt;br /&gt;
ios_saf 16.1&lt;br /&gt;
ios_saf 16.0&lt;br /&gt;
ios_saf 15.6&lt;br /&gt;
ios_saf 15.5&lt;br /&gt;
ios_saf 14.5-14.8&lt;br /&gt;
ios_saf 14.0-14.4&lt;br /&gt;
ios_saf 12.2-12.5&lt;br /&gt;
kaios 3.0-3.1&lt;br /&gt;
kaios 2.5&lt;br /&gt;
op_mini all&lt;br /&gt;
op_mob 73&lt;br /&gt;
opera 98&lt;br /&gt;
opera 97&lt;br /&gt;
opera 96&lt;br /&gt;
safari 16.4&lt;br /&gt;
safari 16.3&lt;br /&gt;
safari 16.2&lt;br /&gt;
safari 16.1&lt;br /&gt;
safari 15.6&lt;br /&gt;
safari 14.1&lt;br /&gt;
samsung 20&lt;br /&gt;
samsung 19.0&lt;br /&gt;
&lt;br /&gt;
[[Category:Studio]]&lt;/div&gt;</summary>
		<author><name>Archduke</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Compatibility&amp;diff=17049</id>
		<title>Compatibility</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Compatibility&amp;diff=17049"/>
		<updated>2023-05-31T08:07:20Z</updated>

		<summary type="html">&lt;p&gt;Archduke: Created page with &amp;quot;{{Studio_Framework_Navigation}}  __TOC__  The mainsite is built with compatibility for several old browsers.  We use a browserslist config to define the targeted browsers: `last 2 versions, not dead, &amp;gt; 0.2%`.  == File structure ==  Category:Studio&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Studio_Framework_Navigation}}&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
The mainsite is built with compatibility for several old browsers.&lt;br /&gt;
&lt;br /&gt;
We use a browserslist config to define the targeted browsers: `last 2 versions, not dead, &amp;gt; 0.2%`.&lt;br /&gt;
&lt;br /&gt;
== File structure ==&lt;br /&gt;
&lt;br /&gt;
[[Category:Studio]]&lt;/div&gt;</summary>
		<author><name>Archduke</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Game_replay&amp;diff=16873</id>
		<title>Game replay</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Game_replay&amp;diff=16873"/>
		<updated>2023-05-09T13:18:13Z</updated>

		<summary type="html">&lt;p&gt;Archduke: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Studio_Framework_Navigation}}&lt;br /&gt;
&lt;br /&gt;
Game replay is managed by the framework. You do not need to do anything special about it in your code, except taking care of updating the client interface through the framework notification system (and not for example, by using the callback function of an ajaxcall).&lt;br /&gt;
&lt;br /&gt;
The game replay works like this:&lt;br /&gt;
* The static files for the game at the time of the game start are archived&lt;br /&gt;
* All notifications sent to the browser are added to the archive&lt;br /&gt;
* When replaying, the static files are loaded in the browser, then notifications are sent back to replay the game moves.&lt;br /&gt;
&lt;br /&gt;
So in essence, the replay works like an exact recording.&lt;br /&gt;
&lt;br /&gt;
NB: the game replay feature is now available on the studio (since December 2020). Please note that there may be a delay before the replay becomes available.&lt;br /&gt;
&lt;br /&gt;
=== Preview Videos ===&lt;br /&gt;
Example games are periodically selected from which videos are generated to show off the game on the game panel.&lt;br /&gt;
&lt;br /&gt;
Wingspan: https://x.boardgamearena.net/data/gamepreviews/1635/en-w640.webm&lt;br /&gt;
&lt;br /&gt;
These previews are generated with a query variable set &amp;lt;code&amp;gt;target=video&amp;lt;/code&amp;gt; in order that you can hide parts of the UI for this video. This should only be done in specific cases, such as to remove modal popups which the player would normally manually dismiss. These modal popups will otherwise remain visible and obscure the video preview.&lt;br /&gt;
 const searchParams = new URLSearchParams(window.location.search);&lt;br /&gt;
 if (searchParams) {&lt;br /&gt;
     const target = searchParams.get(&#039;target&#039;);&lt;br /&gt;
     if (target === &amp;quot;video&amp;quot;) {&lt;br /&gt;
         // Hide modal popups...&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
[[Category:Studio]]&lt;/div&gt;</summary>
		<author><name>Archduke</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=File:KoT_Major_Variant.png&amp;diff=15598</id>
		<title>File:KoT Major Variant.png</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=File:KoT_Major_Variant.png&amp;diff=15598"/>
		<updated>2022-12-22T07:15:54Z</updated>

		<summary type="html">&lt;p&gt;Archduke: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Example major variant image for KoT&lt;/div&gt;</summary>
		<author><name>Archduke</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Gamehelppuzzlestriketwo&amp;diff=13794</id>
		<title>Gamehelppuzzlestriketwo</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Gamehelppuzzlestriketwo&amp;diff=13794"/>
		<updated>2022-06-28T11:55:04Z</updated>

		<summary type="html">&lt;p&gt;Archduke: Created blank page&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Archduke</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Translations&amp;diff=13472</id>
		<title>Translations</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Translations&amp;diff=13472"/>
		<updated>2022-06-06T16:47:35Z</updated>

		<summary type="html">&lt;p&gt;Archduke: /* On client side (Javascript) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Studio_Framework_Navigation}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Using BGA Studio, the game you create is ready to be translated to each language by the BGA community. To make this possible, you only need to specify which string must be translated and how to combine them.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
== Localization Overview ==&lt;br /&gt;
&lt;br /&gt;
Localization for BGA games happens largely on the CLIENT. Games must be developed in English and English strings are sent to the client.&lt;br /&gt;
&lt;br /&gt;
It&#039;s only at the client that your English strings will be displayed with the translation for the user&#039;s language, when such a translation exists.&lt;br /&gt;
&lt;br /&gt;
For anyone who has worked on a system where translation happens at the server and localized strings are sent to the client: you must unlearn what you have learned. Just stick with English and send the untranslated English strings. The magic happens at the client.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== How will my strings be translated? ==&lt;br /&gt;
&lt;br /&gt;
When developing your game, all strings must be in English. Strings must be coherent with the English version of the game.&lt;br /&gt;
&lt;br /&gt;
Once your game enters Beta, the BGA player community will descend upon your game like a plague of locusts and translate it into dozens of languages before you can say &amp;quot;Je ne parle pas anglais&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== What do I have to do from a programming standpoint? ==&lt;br /&gt;
&lt;br /&gt;
Not as much as you think. Read on for full details, but the golden rules are:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# Make sure that any string on the server side that needs to be translated on the client side is wrapped in a clienttranslate() function when defined. For example: $my_response = clienttranslate(&#039;Hey translators, please translate this string&#039;). clienttranslate doesn&#039;t actually do anything at all (it just passes the text through) but the translation engine searches your code for strings wrapped in that function and uses them to build the list of strings that need to be translated.&lt;br /&gt;
# On the client side, just display your text, but wrap it in _().&lt;br /&gt;
## If you pass a string constant to _() - such as _(&#039;This is my string&#039;) then the parser will automatically detect and add your string to the list of strings that need to be translated, AND it will display the local translation for it when displaying.&lt;br /&gt;
## If you pass a variable to _() - such as _(args.my_message) then MAKE SURE that the variable is set to an English string that is either defined somewhere in your PHP code in a clienttranslate() function or somewhere else in your javascript code in a _() function. As long as it is, the translators will provide translations for it, and the _() function will display the local translation of your English string.&lt;br /&gt;
# A string used as the message for notifyAllPlayers or notifyPlayer will automatically have its translation displayed on the client - you don&#039;t need to do anything EXCEPT make sure that it is wrapped in a clienttranslate() on the server, so that it gets translated.&lt;br /&gt;
# A string used as the &amp;quot;description&amp;quot; or &amp;quot;descriptionmyturn&amp;quot; for a state in your state machine will also be automatically translated on the client - you don&#039;t need to do anything EXCEPT make sure that it is wrapped in a clienttranslate() on the server, so that it gets translated.&lt;br /&gt;
# A string used in the pre-games option screen will also automatically have any translation displayed at the client - you don&#039;t need to do anything EXCEPT make sure that it is wrapped in a totranslate() on the server (nota bene: you should not use clienttranslate() here as this file is processed specifically and those strings will not be included in the game translation file but in the main site translation file - with a prefix to keep translations isolated by module - as they have to be translated on main site pages. If you need exactly the same string in your game for a client side translation, it should be declared somewhere else in your code wrapped inside a clienttranslate() to be included in the game translation file.&lt;br /&gt;
# A string used in the statistics screen will operate like a string in the pre-game options screen. It will automatically have any translation displayed at the client as long as you make sure that it is wrapped in a totranslate() on the server.&lt;br /&gt;
# If you are using parameters for a call to notifyAllPlayers or notifyPlayers, or for a state&#039;s &amp;quot;description&amp;quot; or &amp;quot;descriptionmyturn&amp;quot; and those parameters contain text that needs to be translated, you will need to tell the system to display the translated versions of them by using the &#039;i18n&#039; argument. See below for full details.&lt;br /&gt;
&lt;br /&gt;
== What strings should be translated? ==&lt;br /&gt;
&lt;br /&gt;
Every text that can be visible by the player when the game is running normally. This includes tooltips, texts on cards, error messages.&lt;br /&gt;
&lt;br /&gt;
This does NOT include error messages that are not supposed to happen (unexpected errors).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== What rules should I follow for the original English strings? ==&lt;br /&gt;
&lt;br /&gt;
For a coherent and homogeneous interface, here are some rules about ending a sentence with a final period &#039;.&#039;&lt;br /&gt;
&lt;br /&gt;
* As a general rule:&lt;br /&gt;
** If a sentence is displayed isolated in the interface =&amp;gt; no final period&lt;br /&gt;
** If a sentence is followed or could be followed by another sentence in the same interface space =&amp;gt; final period.&lt;br /&gt;
&lt;br /&gt;
* In detail:&lt;br /&gt;
** No final period:&lt;br /&gt;
*** button labels&lt;br /&gt;
*** section titles&lt;br /&gt;
*** menu elements&lt;br /&gt;
*** links triggering an isolated action&lt;br /&gt;
*** anything that is not a full sentence&lt;br /&gt;
*** current actions in the status bar&lt;br /&gt;
** Final period:&lt;br /&gt;
*** complete sentences (e.g., explanations and descriptions) that can be chained with other sentences&lt;br /&gt;
** Either a period or no period is acceptable (but this should be consistent throughout the game) for:&lt;br /&gt;
*** isolated tooltips / small sentences&lt;br /&gt;
*** game logs (no period is usually preferable)&lt;br /&gt;
*** error messages (unless there is more than one sentence in the error message; final period is mandatory in this case)&lt;br /&gt;
&lt;br /&gt;
Otherwise, you should try to follow as closely as possible the general style and format (including capitalization) used in the published English rulebook and game materials.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Focus on translating notifications ==&lt;br /&gt;
&lt;br /&gt;
Usually, translating a website is simple: you just call a function on every string you have to translate, and the string is translated in the player&#039;s language. On Board Game Arena, this is exactly the same with the &amp;quot;_( string )&amp;quot; function.&lt;br /&gt;
&lt;br /&gt;
However, there is one difference on BGA: notifications. The server is sending notifications to players, and most of the time the notifications are the same for every players, no matter what language each player is using. This is why notifications are translated on client side in the proper language, even if the strings are defined on server side.&lt;br /&gt;
&lt;br /&gt;
== How to not make translators crazy ;) ==&lt;br /&gt;
&lt;br /&gt;
* Try to reuse the exact same strings (with the same case, etc.) to minimize the number of strings to translate.&lt;br /&gt;
** &#039;&#039;&#039;Example&#039;&#039;&#039;: Consider replacing &amp;lt;pre&amp;gt;self::_(&amp;quot;Winner&amp;quot;)&amp;lt;/pre&amp;gt; and &amp;lt;pre&amp;gt;self::_(&amp;quot;Winners&amp;quot;)&amp;lt;/pre&amp;gt; (two strings to translate) with &amp;lt;pre&amp;gt;self::_(&amp;quot;Winner(s)&amp;quot;)&amp;lt;/pre&amp;gt;&lt;br /&gt;
** &#039;&#039;&#039;Example 2&#039;&#039;&#039;: &amp;lt;pre&amp;gt;clienttranslate(&amp;quot;play a card&amp;quot;)&amp;lt;/pre&amp;gt; and &amp;lt;pre&amp;gt;clienttranslate(&amp;quot;Play a card&amp;quot;)&amp;lt;/pre&amp;gt; means there will be two strings to translate.&lt;br /&gt;
* Do not mark as translatable a game element that does not have to be translated (e.g., if the name of a monster on a card is &amp;quot;Zzzzz&amp;quot;, maybe there&#039;s no need to translate it).&lt;br /&gt;
* Words does not come in the same order in each language. Thus, when you have to translate a string with an argument, do not write something like:&lt;br /&gt;
&amp;lt;pre&amp;gt;self::_(&amp;quot;First part of the string, &amp;quot;).$argument.&#039; &#039;.self::_(&amp;quot;second part of the string&amp;quot;)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Write instead:&lt;br /&gt;
&amp;lt;pre&amp;gt;sprintf( self::_(&amp;quot;First part of the string, %s second part of the string&amp;quot;), $argument )&amp;lt;/pre&amp;gt;&lt;br /&gt;
(or the equivalent &amp;quot;dojo.string.substitute&amp;quot; in Javascript)&lt;br /&gt;
* When translators are going to translate your game, the most difficult task for them is to get the context of the string to be translated. The shorter the string is, the more difficult the task is for them. As a rule of thumb, try to avoid short, insignificant strings that require knowledge of their surrounding context. You can also leave a comment on the context of the string in the translation program (English to English) if you are the developer of the game.&lt;br /&gt;
* The BGA translation policy is to be flexible on grammar. We prefer to write &amp;quot;player gets 1 coin(s)&amp;quot; rather than write two versions of the same string for plural and singular - it reduces the number of strings to translate.&lt;br /&gt;
* Instead of writing elaborate strings like &amp;quot;With the effect of ZZZ, player XXX gains a new YYY&amp;quot;, which is very difficult to translate, write strings like &amp;quot;ZZZ: XXX gets YYY&amp;quot;.&lt;br /&gt;
* Use present tense instead of past. E.g., &amp;quot;player gets wood&amp;quot; instead of &amp;quot;player got wood&amp;quot;.&lt;br /&gt;
* Avoid using gender-specific wording as much as possible. If needed be aware that [[https://forum.boardgamearena.com/viewtopic.php?f=11&amp;amp;t=19432&amp;amp;start=10#p88592 a pronoun replacement system]] is in place, and cannot work if your use &amp;quot;their&amp;quot; as a singular genderless pronoun, as it removes the information that it&#039;s singular. E.g., you should write &amp;quot;playerX returns card to *his* hand&amp;quot; or &amp;quot;playerX returns card to *his/her* hand&amp;quot; and not &amp;quot;playerX returns card to *their* hand&amp;quot; as in the 2 first case the system will substitute the proper pronoun his/her/their depending on playerX declared/undeclared gender, but in the second case it will always stay &amp;quot;their&amp;quot; whatever the player preference setting.&lt;br /&gt;
* Where two strings are identical apart from (say) a number, use the same string with a ${parameter}, and call format_string_recursive (on the client) or use args (for notifications and state descriptions) to provide the details. But *never* do that for composing multiple sentences with words: other languages have different grammar and it would most likely create untranslatable strings.&lt;br /&gt;
&lt;br /&gt;
== WARNING: Make sure your strings will be translated! ==&lt;br /&gt;
&lt;br /&gt;
For each game, our translation tool does a full scan of the code, looking for translation markers like &amp;quot;_()&amp;quot; or &amp;quot;clienttranslate()&amp;quot;. (See below for the full list of translation markers.)&lt;br /&gt;
&lt;br /&gt;
If your original string is not completely contained inside one of these markers, it won&#039;t be translated.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    // Examples: the following strings will be translated:&lt;br /&gt;
    var mystring_translated = _(&amp;quot;my string&amp;quot;);       // JS&lt;br /&gt;
    $mystring_translated = self::_(&amp;quot;my string&amp;quot;);    // PHP&lt;br /&gt;
    $mystring_translated = sprintf( self::_(&amp;quot;my string with an %s argument&amp;quot;), $argument );   // PHP&lt;br /&gt;
&lt;br /&gt;
    // Examples: the following strings WILL NOT be translated:&lt;br /&gt;
    $my_string = &amp;quot;my string&amp;quot;;&lt;br /&gt;
    $not_translated = self::_( $my_string );   // The original string is not contained within a translator marker =&amp;gt; no translation&lt;br /&gt;
    $not_translated = self::_( sprintf( &amp;quot;my string with a %s argument&amp;quot;, $argument ) ); // Ditto&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== On client side (Javascript) ==&lt;br /&gt;
&lt;br /&gt;
On client side, things are quite simple: you just have to use the &amp;quot;_()&amp;quot; function for all strings you want to translate.&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// Get a string in player&#039;s language:&lt;br /&gt;
var translated = _(&amp;quot;original english string&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
// Get a string in player&#039;s language with parameter:&lt;br /&gt;
var translated = dojo.string.substitute( _(&amp;quot;You can pick ${p} cards and discard ${d}&amp;quot;), {&lt;br /&gt;
    p: 2,&lt;br /&gt;
    d: 4&lt;br /&gt;
} );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;WARNING:&#039;&#039;&#039; in Javascript strings to translate, you should never use &#039;\n&#039;, &#039;\t&#039; or such, as it will break the translation bundle and result in all the Javascript translation to fail. In any case, the strings will result in HTML code, and such character codes won&#039;t have any impact on the HTML rendering. You should use HTML markup instead.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ANOTHER WARNING:&#039;&#039;&#039; you cannot use this function _() in the javascript object constructor, but you can achieve the same if you use it the setup method&lt;br /&gt;
&lt;br /&gt;
=== Formatting on client side ===&lt;br /&gt;
&lt;br /&gt;
Sometimes you will want to apply some formatting on the client side, but don&#039;t want to put HTML tags within the source string (which may be confusing for translators).&lt;br /&gt;
&lt;br /&gt;
This can be achieved with the &amp;lt;code&amp;gt;bga_format&amp;lt;/code&amp;gt; function and Markdown-style syntax.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * @function bga_format&lt;br /&gt;
 * Replaces delimiters with HTML tags in translated text&lt;br /&gt;
 * @param {string} translated string&lt;br /&gt;
 * @param {Object} map of replacements to make, should be of the form&lt;br /&gt;
 *     {&lt;br /&gt;
 *         &#039;*&#039;: (t) =&amp;gt; t,&lt;br /&gt;
 *         &#039;_&#039;: &#039;classname&#039;,&lt;br /&gt;
 *     }&lt;br /&gt;
 *     keys are delimiters within the translated string&lt;br /&gt;
 *     values are either strings (classname of surrounding span) or function (flexible replacements)&lt;br /&gt;
 * @returns {string} Returns the original string, with replacements made.&lt;br /&gt;
 */&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// Get a string in player&#039;s language:&lt;br /&gt;
bga_format(_(&#039;You receive a *special* _tile_&#039;), {&lt;br /&gt;
    &#039;*&#039;: (t) =&amp;gt; &#039;&amp;lt;b&amp;gt;&#039; + t + &#039;&amp;lt;/b&amp;gt;&#039;,&lt;br /&gt;
    &#039;_&#039;: &#039;tile-name&#039;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The above will return something along the lines of:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
You receive a &amp;lt;b&amp;gt;special&amp;lt;/b&amp;gt; &amp;lt;span class=&amp;quot;tile-name&amp;quot;&amp;gt;tile&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Or, if the user is playing in Spanish, for example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Recibes una &amp;lt;span class=&amp;quot;tile-name&amp;quot;&amp;gt;loseta&amp;lt;/span&amp;gt; &amp;lt;b&amp;gt;especial&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Notes:&lt;br /&gt;
* The text passed to &amp;lt;code&amp;gt;bga_format&amp;lt;/code&amp;gt; must still be translated using &amp;lt;code&amp;gt;_()&amp;lt;/code&amp;gt;, don&#039;t forget it!&lt;br /&gt;
* Good characters to demarcate formatting are: &amp;lt;code&amp;gt;[&#039;*&#039;, &#039;_&#039;]&amp;lt;/code&amp;gt; (other single characters will work, just make sure it will be clear to a translator)&lt;br /&gt;
* If the replacements object is a string, the inner text will be placed within a &amp;lt;code&amp;gt;&amp;amp;lt;span&amp;amp;gt;&amp;lt;/code&amp;gt; tag with the string as a class&lt;br /&gt;
* If the replacements object is a function, the inner text will be passed as an argument to the function, and the return value will replace the text and the delimiters&lt;br /&gt;
&lt;br /&gt;
== On server side (PHP) ==&lt;br /&gt;
&lt;br /&gt;
On PHP side, you can use 3 different functions to specify that a string must be translated.&lt;br /&gt;
&lt;br /&gt;
=== Function clienttranslate ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;clienttranslate( &#039;string to translate&#039; ):&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This function is &#039;&#039;transparent&#039;&#039;: it will return the original English string without any change. Its only purpose is to mark this string as &amp;quot;must be translated&amp;quot;, and to make sure the translated version of the string will be available on client side.&lt;br /&gt;
&lt;br /&gt;
In general, you use clienttranslate:&lt;br /&gt;
* In your &#039;&#039;&#039;states.inc.php&#039;&#039;&#039;, for the fields &amp;quot;description&amp;quot; and &amp;quot;descriptionmyturn&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
      &amp;quot;description&amp;quot; =&amp;gt; clienttranslate(&#039;${card_name}: ${actplayer} must discard 4 identical energies&#039;),&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* In &#039;&#039;&#039;material.inc.php&#039;&#039;&#039;, when defining text for game materials that must be displayed on the client side.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$this-&amp;gt;card_types = array(&lt;br /&gt;
&lt;br /&gt;
     1 =&amp;gt; array(&lt;br /&gt;
        &#039;name&#039; =&amp;gt; clienttranslate(&#039;Amulet of Air&#039;), // Thus, we can use &amp;quot;_( card_name )&amp;quot; on Javascript side.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* When sending a notification with &#039;&#039;notifyAllPlayers&#039;&#039; or &#039;&#039;notifyPlayer&#039;&#039;, in the game log string and all game log arguments that need a translation.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
     // A game log string with no argument:&lt;br /&gt;
     self::notifyAllPlayers( &#039;pickLibraryCards&#039;, clienttranslate(&#039;Everyone draw cards from their library&#039;), [] );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As a consequence there is no point passing variables to this function. E.g.:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    notif=&amp;quot;foo&amp;quot;;&lt;br /&gt;
    self::notifyAllPlayers( &#039;log&#039;, clienttranslate(notif),[]); // BAD&lt;br /&gt;
    &lt;br /&gt;
    notif=clienttranslate(&amp;quot;foo&amp;quot;);&lt;br /&gt;
    self::notifyAllPlayers( &#039;log&#039;, notif,[]); // GOOD&lt;br /&gt;
&lt;br /&gt;
    self::notifyAllPlayers( &#039;log&#039;, clienttranslate(&amp;quot;player gains ${num} gems&amp;quot;),[num=&amp;gt;2]); // BAD it is dynamic string enterpreted by php &lt;br /&gt;
    self::notifyAllPlayers( &#039;log&#039;, clienttranslate(&#039;player gains ${num} gems&#039;),[num=&amp;gt;2]); // GOOD, difference is single quotes&lt;br /&gt;
&lt;br /&gt;
    self::notifyAllPlayers( &#039;log&#039;, clienttranslate(&amp;quot;player gains &amp;quot;.${num}.&amp;quot; gems&amp;quot;),[num=&amp;gt;2]); // BAD concatenation &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Translating arguments is a little bit more complex. This uses the &#039;&#039;&#039;i18n&#039;&#039;&#039; special argument as below:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 // In the following example, we translate the game log itself, but also the &amp;quot;card_name&amp;quot; argument:&lt;br /&gt;
&lt;br /&gt;
 self::notifyAllPlayers( &#039;winPoints&#039;, clienttranslate(&#039;${card_name}: ${player_name} gains ${points} point(s)&#039;), array(&lt;br /&gt;
                &#039;i18n&#039; =&amp;gt; array( &#039;card_name&#039; ),     // &amp;lt;===== We specify here that &amp;quot;card_name&amp;quot; argument must be translated&lt;br /&gt;
                &#039;player_id&#039; =&amp;gt; $player_id,&lt;br /&gt;
                &#039;player_name&#039; =&amp;gt; self::getActivePlayerName(),&lt;br /&gt;
                &#039;points&#039; =&amp;gt; $points,&lt;br /&gt;
                &#039;card_name&#039; =&amp;gt; $this-&amp;gt;card_types[8][&#039;name&#039;] // &amp;lt;==== Here, we provide original English string.&lt;br /&gt;
            ) ); &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To ensure the translation of the i18n argument will be made, clienttranslate must have been used somewhere, for instance:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$this-&amp;gt;card_types = array(&lt;br /&gt;
...&lt;br /&gt;
     8 =&amp;gt; array(&lt;br /&gt;
        &#039;name&#039; =&amp;gt; clienttranslate(&amp;quot;Amulet of Fire&amp;quot;),&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Pay attention when using the &#039;&#039;&#039;i18n&#039;&#039;&#039; argument when translating arguments for the client: do NOT use same argument for both translations AND key codes for client-side actions (like using &#039;card_name&#039; to move it on the player board as described in the example). It&#039;s pretty obvious in the example, but it can be very tricky when translation is made at the end of the development (which is often the case). Use explicit argument names like &#039;card_name_translated&#039; by example.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;WARNING:&#039;&#039;&#039; you should NEVER use concatenation with &#039;&#039;clienttranslate&#039;&#039;, as it would result in a different string to translate at runtime than the one retrieved statically in the translation system, and so translation would not be applied. If you need to compose a string, use substitution and the i18n parameter (but you also have to pay attention not to compose sentences in a way that is dependent upon the English language specific syntax, or it may be impossible to translate correctly in another language: sometimes, you need multiple full sentences rather than relying on substitution).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Method _ (underscore) ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;self::_( &amp;quot;my string to translate&amp;quot; ):&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This function returns a string translated in the language of CURRENT user (i.e. player who send the request to the server) (be careful, this is NOT the active player).&lt;br /&gt;
&lt;br /&gt;
This can be used like self::_(&#039;bla&#039;) or this-&amp;gt;(&#039;bla&#039;). You cannot use static underscore function _(&#039;bla&#039;) in php, it is not the same, it will not translate strings from your game.&lt;br /&gt;
&lt;br /&gt;
The returned string will be surrounded by HTML tags, so you cannot use it in places where pure text is required or your string already has another html markup.&lt;br /&gt;
&lt;br /&gt;
Most of the time, you don&#039;t need to translate strings on server side, except on the following situations:&lt;br /&gt;
* Throwing user exceptions&lt;br /&gt;
* Creating the labels for the game interface used in your template&lt;br /&gt;
* Rarely, in your material.inc.php, if for example you need to use some string elements in your exceptions&lt;br /&gt;
* Rarely, in your &amp;quot;getAllDatas&amp;quot; PHP method, as the data return by this method is used only by current user&lt;br /&gt;
&lt;br /&gt;
Imporant! This function does two things:&lt;br /&gt;
* Mark string for translation&lt;br /&gt;
* Translates in runtime&lt;br /&gt;
As a consequence you absolutely cannot have $var in there! Or string concatenations.&lt;br /&gt;
I.e.&lt;br /&gt;
  $food=self::_(&amp;quot;Banana&amp;quot;);// good&lt;br /&gt;
  self::_(&amp;quot;User gives $food to a cat&amp;quot;); // bad&lt;br /&gt;
For the translator we will have two strings &amp;quot;Banana&amp;quot; and &amp;quot;User gives $food to a cat&amp;quot;, but in runtime we will be&lt;br /&gt;
&amp;quot;Banana&amp;quot; and &amp;quot;User gives Banana to a cat&amp;quot; and second string would not match anything. And this is as bad&lt;br /&gt;
  self::_(&amp;quot;User gives &amp;quot;.$food.&amp;quot; to a cat&amp;quot;);// bad&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Throwing an exception because the player did a forbidden move ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// This will display a translatable red message to the player that just did some wrong action:&lt;br /&gt;
throw new BgaUserException( self::_(&#039;You must choose 3 cards&#039;) );&lt;br /&gt;
&lt;br /&gt;
// ... notice the use of BgaUserException that signals that this exception is &amp;quot;expected&amp;quot;. In theory, all exception that are expected should be translated.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Creating labels ====&lt;br /&gt;
&lt;br /&gt;
In &amp;quot;yourgame.view.php&amp;quot;, when creating the labels for the game interface used in your template (.tpl) file.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$this-&amp;gt;tpl[&#039;CARDS_FOR_YEAR_2&#039;] = self::_(&amp;quot;Your cards for year II&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Nota bene:&#039;&#039;&#039; it is recommended to set translated text in your interface client side rather than use template variables and server translation, so that translation works natively in replays (that don&#039;t have server side translations). For simple strings, the framework will handle moving the translation client side, but for more complex strings it may not work. In particular, you should not use server side translation for templates with substitution variables (or use the specific function &amp;quot;gameview_str_replace( $search, $replace, $string )&amp;quot; if not possible otherwise or for old code compatibility). Also, you should never use a &amp;quot;to_translate&amp;quot; class in your .tpl as it is used internally by the framework.&lt;br /&gt;
&lt;br /&gt;
Example with view.php:&lt;br /&gt;
in .tpl:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  &amp;lt;div id=&amp;quot;empire_title_{COLOR}&amp;quot; class=&amp;quot;side_title color_{COLOR}&amp;quot;&amp;gt;{EMPIRE_LABEL}&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
in view.php:&lt;br /&gt;
        $this-&amp;gt;page-&amp;gt;insert_block(&amp;quot;player_board&amp;quot;, array (&amp;quot;COLOR&amp;quot; =&amp;gt; $color,&amp;quot;PLAYER_NAME&amp;quot; =&amp;gt; $name,&amp;quot;PLAYER_NO&amp;quot; =&amp;gt; $no,&lt;br /&gt;
                &amp;quot;PLAYER_ID&amp;quot; =&amp;gt; $player_id, &amp;quot;CLASSES&amp;quot; =&amp;gt; $own?&amp;quot;own&amp;quot;:&amp;quot;&amp;quot;, &lt;br /&gt;
                &amp;quot;EMPIRE_LABEL&amp;quot; =&amp;gt; self::raw(gameview_str_replace(&#039;${player_name}&#039;, $name, self::_(&#039;${player_name}\&#039;s EMPIRE&#039;)))&lt;br /&gt;
              ));&lt;br /&gt;
Example with client side:&lt;br /&gt;
in .tpl:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  &amp;lt;div id=&amp;quot;empire_title_{COLOR}&amp;quot; class=&amp;quot;side_title color_{COLOR}&amp;quot;&amp;gt;Stub&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
in .js:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  for (var player_id in this.gamedatas.players) {&lt;br /&gt;
      var player_color = this.gamedatas.players[player_id].color;&lt;br /&gt;
      var player_name = this.gamedatas.players[player_id].name;&lt;br /&gt;
      $(&#039;empire_title_&#039;+player_color).innerHTML=this.format_string_recursive(_(&amp;quot;${player_name}&#039;s EMPIRE&amp;quot;), {player_name: player_name});&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Translating strings in material file ====&lt;br /&gt;
&lt;br /&gt;
Rarely, in your material.inc.php, if for example you need to use some string elements in your exceptions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// In material.inc.php, $this-&amp;gt;energies[n][&#039;nametr&#039;] has been created with the self::_() method. Now we can do this:&lt;br /&gt;
throw new BgaUserException( self::_(&amp;quot;To execute this action you need more: &amp;quot;).&#039; &#039;.$this-&amp;gt;energies[$resource_id][&#039;nametr&#039;] );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: you could also do this, so you don&#039;t need to pollute your material file&lt;br /&gt;
   throw new BgaUserException( self::_(&amp;quot;To execute this action you need more: &amp;quot;).&#039; &#039;.self::_($this-&amp;gt;energies[$resource_id][&#039;name&#039;]) );&lt;br /&gt;
&lt;br /&gt;
where $this-&amp;gt;energies[$resource_id][&#039;name&#039;] were marked in material file using regular clienttranslate function&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  $this-&amp;gt;energies = [&lt;br /&gt;
      22 =&amp;gt; [&lt;br /&gt;
          &#039;name&#039; =&amp;gt; clienttranslate(&#039;Sun&#039;)&lt;br /&gt;
          ...&lt;br /&gt;
      ]&lt;br /&gt;
  ];&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Strings in getAllDatas ====&lt;br /&gt;
&lt;br /&gt;
Rarely, in your &amp;quot;getAllDatas&amp;quot; PHP method, as the data return by this method is used only by current user.&lt;br /&gt;
&lt;br /&gt;
Note: not sure why would you send strings from the server in this case, as same can be achieved on the client usually.&lt;br /&gt;
&lt;br /&gt;
=== Function totranslate ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;totranslate( &amp;quot;my string to translate&amp;quot; ):&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This function works exactly like &#039;clienttranslate&#039;, except it tells BGA that the string is not needed on client side.&lt;br /&gt;
&lt;br /&gt;
You should not use this function, except on the following cases:&lt;br /&gt;
* Statistics name in stats.inc.php&lt;br /&gt;
* Option names and option values name in gameoptions.inc.php&lt;br /&gt;
&lt;br /&gt;
== Top Secret Undocumented Features ==&lt;br /&gt;
&lt;br /&gt;
If your string contains the clause &#039;$${value}&#039; (such as &#039;You gain $${value}.&#039;) then the translation system seems to move the position of the $ to a localized location (eg $5 in English but 5$ in French). This only seems to occur when using the argument &#039;value&#039;.&lt;br /&gt;
&lt;br /&gt;
In JavaScript, you can get the current user&#039;s language by retrieving the translation for the special string &amp;quot;$locale&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
    var lang = _(&#039;$locale&#039;); // en, fr, etc.&lt;br /&gt;
&lt;br /&gt;
== On server side - advanced (PHP) ==&lt;br /&gt;
&lt;br /&gt;
If you want to use translation system in your custom static modules, you will first need to expose the _() function :&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class mygame extends Table {&lt;br /&gt;
  // Exposing protected method translation&lt;br /&gt;
  public static function totranslate($text) {&lt;br /&gt;
    return self::_($text);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then you&#039;ll be able to use this directly in other modules by doing&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
throw new BgaUserException(mygame::totranslate(&amp;quot;Translated error from my awesome module file&amp;quot;));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Notice how the &amp;quot;totranslate&amp;quot; is also used by the static analysis to detect your string. So the following will not work :&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$msg = &amp;quot;Translated error from my awesome module file&amp;quot;;&lt;br /&gt;
throw new BgaUserException(mygame::totranslate($msg));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Analyze your project ==&lt;br /&gt;
&lt;br /&gt;
It looks super complex but there is help!&lt;br /&gt;
On studio control panel you can find a button &amp;quot;Check project&amp;quot; - it runs bunch of static analysis on your project including scanning for bad translations and missing translations.&lt;br /&gt;
It also will extact all you translation keys as translator will see them so you can double check - and run spell checker on them.&lt;br /&gt;
&lt;br /&gt;
== Other Useful Links ==&lt;br /&gt;
&lt;br /&gt;
* BLOG post about translations https://bga-devs.github.io/blog/posts/translations-summary/&lt;br /&gt;
&lt;br /&gt;
[[Category:Studio]]&lt;/div&gt;</summary>
		<author><name>Archduke</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Translations&amp;diff=13471</id>
		<title>Translations</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Translations&amp;diff=13471"/>
		<updated>2022-06-06T16:46:51Z</updated>

		<summary type="html">&lt;p&gt;Archduke: /* On client side (Javascript) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Studio_Framework_Navigation}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Using BGA Studio, the game you create is ready to be translated to each language by the BGA community. To make this possible, you only need to specify which string must be translated and how to combine them.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
== Localization Overview ==&lt;br /&gt;
&lt;br /&gt;
Localization for BGA games happens largely on the CLIENT. Games must be developed in English and English strings are sent to the client.&lt;br /&gt;
&lt;br /&gt;
It&#039;s only at the client that your English strings will be displayed with the translation for the user&#039;s language, when such a translation exists.&lt;br /&gt;
&lt;br /&gt;
For anyone who has worked on a system where translation happens at the server and localized strings are sent to the client: you must unlearn what you have learned. Just stick with English and send the untranslated English strings. The magic happens at the client.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== How will my strings be translated? ==&lt;br /&gt;
&lt;br /&gt;
When developing your game, all strings must be in English. Strings must be coherent with the English version of the game.&lt;br /&gt;
&lt;br /&gt;
Once your game enters Beta, the BGA player community will descend upon your game like a plague of locusts and translate it into dozens of languages before you can say &amp;quot;Je ne parle pas anglais&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== What do I have to do from a programming standpoint? ==&lt;br /&gt;
&lt;br /&gt;
Not as much as you think. Read on for full details, but the golden rules are:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# Make sure that any string on the server side that needs to be translated on the client side is wrapped in a clienttranslate() function when defined. For example: $my_response = clienttranslate(&#039;Hey translators, please translate this string&#039;). clienttranslate doesn&#039;t actually do anything at all (it just passes the text through) but the translation engine searches your code for strings wrapped in that function and uses them to build the list of strings that need to be translated.&lt;br /&gt;
# On the client side, just display your text, but wrap it in _().&lt;br /&gt;
## If you pass a string constant to _() - such as _(&#039;This is my string&#039;) then the parser will automatically detect and add your string to the list of strings that need to be translated, AND it will display the local translation for it when displaying.&lt;br /&gt;
## If you pass a variable to _() - such as _(args.my_message) then MAKE SURE that the variable is set to an English string that is either defined somewhere in your PHP code in a clienttranslate() function or somewhere else in your javascript code in a _() function. As long as it is, the translators will provide translations for it, and the _() function will display the local translation of your English string.&lt;br /&gt;
# A string used as the message for notifyAllPlayers or notifyPlayer will automatically have its translation displayed on the client - you don&#039;t need to do anything EXCEPT make sure that it is wrapped in a clienttranslate() on the server, so that it gets translated.&lt;br /&gt;
# A string used as the &amp;quot;description&amp;quot; or &amp;quot;descriptionmyturn&amp;quot; for a state in your state machine will also be automatically translated on the client - you don&#039;t need to do anything EXCEPT make sure that it is wrapped in a clienttranslate() on the server, so that it gets translated.&lt;br /&gt;
# A string used in the pre-games option screen will also automatically have any translation displayed at the client - you don&#039;t need to do anything EXCEPT make sure that it is wrapped in a totranslate() on the server (nota bene: you should not use clienttranslate() here as this file is processed specifically and those strings will not be included in the game translation file but in the main site translation file - with a prefix to keep translations isolated by module - as they have to be translated on main site pages. If you need exactly the same string in your game for a client side translation, it should be declared somewhere else in your code wrapped inside a clienttranslate() to be included in the game translation file.&lt;br /&gt;
# A string used in the statistics screen will operate like a string in the pre-game options screen. It will automatically have any translation displayed at the client as long as you make sure that it is wrapped in a totranslate() on the server.&lt;br /&gt;
# If you are using parameters for a call to notifyAllPlayers or notifyPlayers, or for a state&#039;s &amp;quot;description&amp;quot; or &amp;quot;descriptionmyturn&amp;quot; and those parameters contain text that needs to be translated, you will need to tell the system to display the translated versions of them by using the &#039;i18n&#039; argument. See below for full details.&lt;br /&gt;
&lt;br /&gt;
== What strings should be translated? ==&lt;br /&gt;
&lt;br /&gt;
Every text that can be visible by the player when the game is running normally. This includes tooltips, texts on cards, error messages.&lt;br /&gt;
&lt;br /&gt;
This does NOT include error messages that are not supposed to happen (unexpected errors).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== What rules should I follow for the original English strings? ==&lt;br /&gt;
&lt;br /&gt;
For a coherent and homogeneous interface, here are some rules about ending a sentence with a final period &#039;.&#039;&lt;br /&gt;
&lt;br /&gt;
* As a general rule:&lt;br /&gt;
** If a sentence is displayed isolated in the interface =&amp;gt; no final period&lt;br /&gt;
** If a sentence is followed or could be followed by another sentence in the same interface space =&amp;gt; final period.&lt;br /&gt;
&lt;br /&gt;
* In detail:&lt;br /&gt;
** No final period:&lt;br /&gt;
*** button labels&lt;br /&gt;
*** section titles&lt;br /&gt;
*** menu elements&lt;br /&gt;
*** links triggering an isolated action&lt;br /&gt;
*** anything that is not a full sentence&lt;br /&gt;
*** current actions in the status bar&lt;br /&gt;
** Final period:&lt;br /&gt;
*** complete sentences (e.g., explanations and descriptions) that can be chained with other sentences&lt;br /&gt;
** Either a period or no period is acceptable (but this should be consistent throughout the game) for:&lt;br /&gt;
*** isolated tooltips / small sentences&lt;br /&gt;
*** game logs (no period is usually preferable)&lt;br /&gt;
*** error messages (unless there is more than one sentence in the error message; final period is mandatory in this case)&lt;br /&gt;
&lt;br /&gt;
Otherwise, you should try to follow as closely as possible the general style and format (including capitalization) used in the published English rulebook and game materials.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Focus on translating notifications ==&lt;br /&gt;
&lt;br /&gt;
Usually, translating a website is simple: you just call a function on every string you have to translate, and the string is translated in the player&#039;s language. On Board Game Arena, this is exactly the same with the &amp;quot;_( string )&amp;quot; function.&lt;br /&gt;
&lt;br /&gt;
However, there is one difference on BGA: notifications. The server is sending notifications to players, and most of the time the notifications are the same for every players, no matter what language each player is using. This is why notifications are translated on client side in the proper language, even if the strings are defined on server side.&lt;br /&gt;
&lt;br /&gt;
== How to not make translators crazy ;) ==&lt;br /&gt;
&lt;br /&gt;
* Try to reuse the exact same strings (with the same case, etc.) to minimize the number of strings to translate.&lt;br /&gt;
** &#039;&#039;&#039;Example&#039;&#039;&#039;: Consider replacing &amp;lt;pre&amp;gt;self::_(&amp;quot;Winner&amp;quot;)&amp;lt;/pre&amp;gt; and &amp;lt;pre&amp;gt;self::_(&amp;quot;Winners&amp;quot;)&amp;lt;/pre&amp;gt; (two strings to translate) with &amp;lt;pre&amp;gt;self::_(&amp;quot;Winner(s)&amp;quot;)&amp;lt;/pre&amp;gt;&lt;br /&gt;
** &#039;&#039;&#039;Example 2&#039;&#039;&#039;: &amp;lt;pre&amp;gt;clienttranslate(&amp;quot;play a card&amp;quot;)&amp;lt;/pre&amp;gt; and &amp;lt;pre&amp;gt;clienttranslate(&amp;quot;Play a card&amp;quot;)&amp;lt;/pre&amp;gt; means there will be two strings to translate.&lt;br /&gt;
* Do not mark as translatable a game element that does not have to be translated (e.g., if the name of a monster on a card is &amp;quot;Zzzzz&amp;quot;, maybe there&#039;s no need to translate it).&lt;br /&gt;
* Words does not come in the same order in each language. Thus, when you have to translate a string with an argument, do not write something like:&lt;br /&gt;
&amp;lt;pre&amp;gt;self::_(&amp;quot;First part of the string, &amp;quot;).$argument.&#039; &#039;.self::_(&amp;quot;second part of the string&amp;quot;)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Write instead:&lt;br /&gt;
&amp;lt;pre&amp;gt;sprintf( self::_(&amp;quot;First part of the string, %s second part of the string&amp;quot;), $argument )&amp;lt;/pre&amp;gt;&lt;br /&gt;
(or the equivalent &amp;quot;dojo.string.substitute&amp;quot; in Javascript)&lt;br /&gt;
* When translators are going to translate your game, the most difficult task for them is to get the context of the string to be translated. The shorter the string is, the more difficult the task is for them. As a rule of thumb, try to avoid short, insignificant strings that require knowledge of their surrounding context. You can also leave a comment on the context of the string in the translation program (English to English) if you are the developer of the game.&lt;br /&gt;
* The BGA translation policy is to be flexible on grammar. We prefer to write &amp;quot;player gets 1 coin(s)&amp;quot; rather than write two versions of the same string for plural and singular - it reduces the number of strings to translate.&lt;br /&gt;
* Instead of writing elaborate strings like &amp;quot;With the effect of ZZZ, player XXX gains a new YYY&amp;quot;, which is very difficult to translate, write strings like &amp;quot;ZZZ: XXX gets YYY&amp;quot;.&lt;br /&gt;
* Use present tense instead of past. E.g., &amp;quot;player gets wood&amp;quot; instead of &amp;quot;player got wood&amp;quot;.&lt;br /&gt;
* Avoid using gender-specific wording as much as possible. If needed be aware that [[https://forum.boardgamearena.com/viewtopic.php?f=11&amp;amp;t=19432&amp;amp;start=10#p88592 a pronoun replacement system]] is in place, and cannot work if your use &amp;quot;their&amp;quot; as a singular genderless pronoun, as it removes the information that it&#039;s singular. E.g., you should write &amp;quot;playerX returns card to *his* hand&amp;quot; or &amp;quot;playerX returns card to *his/her* hand&amp;quot; and not &amp;quot;playerX returns card to *their* hand&amp;quot; as in the 2 first case the system will substitute the proper pronoun his/her/their depending on playerX declared/undeclared gender, but in the second case it will always stay &amp;quot;their&amp;quot; whatever the player preference setting.&lt;br /&gt;
* Where two strings are identical apart from (say) a number, use the same string with a ${parameter}, and call format_string_recursive (on the client) or use args (for notifications and state descriptions) to provide the details. But *never* do that for composing multiple sentences with words: other languages have different grammar and it would most likely create untranslatable strings.&lt;br /&gt;
&lt;br /&gt;
== WARNING: Make sure your strings will be translated! ==&lt;br /&gt;
&lt;br /&gt;
For each game, our translation tool does a full scan of the code, looking for translation markers like &amp;quot;_()&amp;quot; or &amp;quot;clienttranslate()&amp;quot;. (See below for the full list of translation markers.)&lt;br /&gt;
&lt;br /&gt;
If your original string is not completely contained inside one of these markers, it won&#039;t be translated.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    // Examples: the following strings will be translated:&lt;br /&gt;
    var mystring_translated = _(&amp;quot;my string&amp;quot;);       // JS&lt;br /&gt;
    $mystring_translated = self::_(&amp;quot;my string&amp;quot;);    // PHP&lt;br /&gt;
    $mystring_translated = sprintf( self::_(&amp;quot;my string with an %s argument&amp;quot;), $argument );   // PHP&lt;br /&gt;
&lt;br /&gt;
    // Examples: the following strings WILL NOT be translated:&lt;br /&gt;
    $my_string = &amp;quot;my string&amp;quot;;&lt;br /&gt;
    $not_translated = self::_( $my_string );   // The original string is not contained within a translator marker =&amp;gt; no translation&lt;br /&gt;
    $not_translated = self::_( sprintf( &amp;quot;my string with a %s argument&amp;quot;, $argument ) ); // Ditto&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== On client side (Javascript) ==&lt;br /&gt;
&lt;br /&gt;
On client side, things are quite simple: you just have to use the &amp;quot;_()&amp;quot; function for all strings you want to translate.&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// Get a string in player&#039;s language:&lt;br /&gt;
var translated = _(&amp;quot;original english string&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
// Get a string in player&#039;s language with parameter:&lt;br /&gt;
var translated = dojo.string.substitute( _(&amp;quot;You can pick ${p} cards and discard ${d}&amp;quot;), {&lt;br /&gt;
    p: 2,&lt;br /&gt;
    d: 4&lt;br /&gt;
} );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;WARNING:&#039;&#039;&#039; in Javascript strings to translate, you should never use &#039;\n&#039;, &#039;\t&#039; or such, as it will break the translation bundle and result in all the Javascript translation to fail. In any case, the strings will result in HTML code, and such character codes won&#039;t have any impact on the HTML rendering. You should use HTML markup instead.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ANOTHER WARNING:&#039;&#039;&#039; you cannot use this function _() in the javascript object constructor, but you can achieve the same if you use it the setup method&lt;br /&gt;
&lt;br /&gt;
=== Formatting on client side ===&lt;br /&gt;
&lt;br /&gt;
Sometimes you will want to apply some formatting on the client side, but don&#039;t want to put HTML tags within the source string (which may be confusing for translators).&lt;br /&gt;
&lt;br /&gt;
This can be achieved with the &amp;lt;code&amp;gt;bga_format&amp;lt;/code&amp;gt; function and Markdown-style syntax.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * @function bga_format&lt;br /&gt;
 * Replaces delimiters with HTML tags in translated text&lt;br /&gt;
 * @param {string} translated string&lt;br /&gt;
 * @param {Object} map of replacements to make, should be of the form&lt;br /&gt;
 *     {&lt;br /&gt;
 *         &#039;*&#039;: (t) =&amp;gt; t,&lt;br /&gt;
 *         &#039;_&#039;: &#039;classname&#039;,&lt;br /&gt;
 *     }&lt;br /&gt;
 *     keys are delimiters within the translated string&lt;br /&gt;
 *     values are either strings (classname of surrounding span) or function (flexible replacements)&lt;br /&gt;
 * @returns {string} Returns the original string, with replacements made.&lt;br /&gt;
 */&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// Get a string in player&#039;s language:&lt;br /&gt;
bga_format(_(&#039;You receive a *special* _tile_&#039;), {&lt;br /&gt;
    &#039;*&#039;: (t) =&amp;gt; &#039;&amp;lt;b&amp;gt;&#039; + t + &#039;&amp;lt;/b&amp;gt;&#039;,&lt;br /&gt;
    &#039;_&#039;: &#039;tile-name&#039;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The above will return something along the lines of:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
You receive a &amp;lt;b&amp;gt;special&amp;lt;/b&amp;gt; &amp;lt;span class=&amp;quot;tile-name&amp;quot;&amp;gt;tile&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Or, if the user is playing in Spanish, for example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Recibes una &amp;lt;span class=&amp;quot;tile-name&amp;quot;&amp;gt;loseta&amp;lt;/span&amp;gt; &amp;lt;b&amp;gt;especial&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Notes:&lt;br /&gt;
* The text passed to &amp;lt;code&amp;gt;bga_format&amp;lt;/code&amp;gt; must still be translated using &amp;lt;code&amp;gt;_()&amp;lt;/code&amp;gt;, don&#039;t forget it!&lt;br /&gt;
* Good characters to demarcate formatting are: &amp;lt;code&amp;gt;[&#039;-&#039;, &#039;*&#039;, &#039;+&#039;, &#039;_&#039;]&amp;lt;/code&amp;gt;&lt;br /&gt;
* If the replacements object is a string, the inner text will be placed within a &amp;lt;code&amp;gt;&amp;amp;lt;span&amp;amp;gt;&amp;lt;/code&amp;gt; tag with the string as a class&lt;br /&gt;
* If the replacements object is a function, the inner text will be passed as an argument to the function, and the return value will replace the text and the delimiters&lt;br /&gt;
&lt;br /&gt;
== On server side (PHP) ==&lt;br /&gt;
&lt;br /&gt;
On PHP side, you can use 3 different functions to specify that a string must be translated.&lt;br /&gt;
&lt;br /&gt;
=== Function clienttranslate ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;clienttranslate( &#039;string to translate&#039; ):&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This function is &#039;&#039;transparent&#039;&#039;: it will return the original English string without any change. Its only purpose is to mark this string as &amp;quot;must be translated&amp;quot;, and to make sure the translated version of the string will be available on client side.&lt;br /&gt;
&lt;br /&gt;
In general, you use clienttranslate:&lt;br /&gt;
* In your &#039;&#039;&#039;states.inc.php&#039;&#039;&#039;, for the fields &amp;quot;description&amp;quot; and &amp;quot;descriptionmyturn&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
      &amp;quot;description&amp;quot; =&amp;gt; clienttranslate(&#039;${card_name}: ${actplayer} must discard 4 identical energies&#039;),&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* In &#039;&#039;&#039;material.inc.php&#039;&#039;&#039;, when defining text for game materials that must be displayed on the client side.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$this-&amp;gt;card_types = array(&lt;br /&gt;
&lt;br /&gt;
     1 =&amp;gt; array(&lt;br /&gt;
        &#039;name&#039; =&amp;gt; clienttranslate(&#039;Amulet of Air&#039;), // Thus, we can use &amp;quot;_( card_name )&amp;quot; on Javascript side.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* When sending a notification with &#039;&#039;notifyAllPlayers&#039;&#039; or &#039;&#039;notifyPlayer&#039;&#039;, in the game log string and all game log arguments that need a translation.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
     // A game log string with no argument:&lt;br /&gt;
     self::notifyAllPlayers( &#039;pickLibraryCards&#039;, clienttranslate(&#039;Everyone draw cards from their library&#039;), [] );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As a consequence there is no point passing variables to this function. E.g.:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    notif=&amp;quot;foo&amp;quot;;&lt;br /&gt;
    self::notifyAllPlayers( &#039;log&#039;, clienttranslate(notif),[]); // BAD&lt;br /&gt;
    &lt;br /&gt;
    notif=clienttranslate(&amp;quot;foo&amp;quot;);&lt;br /&gt;
    self::notifyAllPlayers( &#039;log&#039;, notif,[]); // GOOD&lt;br /&gt;
&lt;br /&gt;
    self::notifyAllPlayers( &#039;log&#039;, clienttranslate(&amp;quot;player gains ${num} gems&amp;quot;),[num=&amp;gt;2]); // BAD it is dynamic string enterpreted by php &lt;br /&gt;
    self::notifyAllPlayers( &#039;log&#039;, clienttranslate(&#039;player gains ${num} gems&#039;),[num=&amp;gt;2]); // GOOD, difference is single quotes&lt;br /&gt;
&lt;br /&gt;
    self::notifyAllPlayers( &#039;log&#039;, clienttranslate(&amp;quot;player gains &amp;quot;.${num}.&amp;quot; gems&amp;quot;),[num=&amp;gt;2]); // BAD concatenation &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Translating arguments is a little bit more complex. This uses the &#039;&#039;&#039;i18n&#039;&#039;&#039; special argument as below:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 // In the following example, we translate the game log itself, but also the &amp;quot;card_name&amp;quot; argument:&lt;br /&gt;
&lt;br /&gt;
 self::notifyAllPlayers( &#039;winPoints&#039;, clienttranslate(&#039;${card_name}: ${player_name} gains ${points} point(s)&#039;), array(&lt;br /&gt;
                &#039;i18n&#039; =&amp;gt; array( &#039;card_name&#039; ),     // &amp;lt;===== We specify here that &amp;quot;card_name&amp;quot; argument must be translated&lt;br /&gt;
                &#039;player_id&#039; =&amp;gt; $player_id,&lt;br /&gt;
                &#039;player_name&#039; =&amp;gt; self::getActivePlayerName(),&lt;br /&gt;
                &#039;points&#039; =&amp;gt; $points,&lt;br /&gt;
                &#039;card_name&#039; =&amp;gt; $this-&amp;gt;card_types[8][&#039;name&#039;] // &amp;lt;==== Here, we provide original English string.&lt;br /&gt;
            ) ); &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To ensure the translation of the i18n argument will be made, clienttranslate must have been used somewhere, for instance:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$this-&amp;gt;card_types = array(&lt;br /&gt;
...&lt;br /&gt;
     8 =&amp;gt; array(&lt;br /&gt;
        &#039;name&#039; =&amp;gt; clienttranslate(&amp;quot;Amulet of Fire&amp;quot;),&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Pay attention when using the &#039;&#039;&#039;i18n&#039;&#039;&#039; argument when translating arguments for the client: do NOT use same argument for both translations AND key codes for client-side actions (like using &#039;card_name&#039; to move it on the player board as described in the example). It&#039;s pretty obvious in the example, but it can be very tricky when translation is made at the end of the development (which is often the case). Use explicit argument names like &#039;card_name_translated&#039; by example.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;WARNING:&#039;&#039;&#039; you should NEVER use concatenation with &#039;&#039;clienttranslate&#039;&#039;, as it would result in a different string to translate at runtime than the one retrieved statically in the translation system, and so translation would not be applied. If you need to compose a string, use substitution and the i18n parameter (but you also have to pay attention not to compose sentences in a way that is dependent upon the English language specific syntax, or it may be impossible to translate correctly in another language: sometimes, you need multiple full sentences rather than relying on substitution).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Method _ (underscore) ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;self::_( &amp;quot;my string to translate&amp;quot; ):&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This function returns a string translated in the language of CURRENT user (i.e. player who send the request to the server) (be careful, this is NOT the active player).&lt;br /&gt;
&lt;br /&gt;
This can be used like self::_(&#039;bla&#039;) or this-&amp;gt;(&#039;bla&#039;). You cannot use static underscore function _(&#039;bla&#039;) in php, it is not the same, it will not translate strings from your game.&lt;br /&gt;
&lt;br /&gt;
The returned string will be surrounded by HTML tags, so you cannot use it in places where pure text is required or your string already has another html markup.&lt;br /&gt;
&lt;br /&gt;
Most of the time, you don&#039;t need to translate strings on server side, except on the following situations:&lt;br /&gt;
* Throwing user exceptions&lt;br /&gt;
* Creating the labels for the game interface used in your template&lt;br /&gt;
* Rarely, in your material.inc.php, if for example you need to use some string elements in your exceptions&lt;br /&gt;
* Rarely, in your &amp;quot;getAllDatas&amp;quot; PHP method, as the data return by this method is used only by current user&lt;br /&gt;
&lt;br /&gt;
Imporant! This function does two things:&lt;br /&gt;
* Mark string for translation&lt;br /&gt;
* Translates in runtime&lt;br /&gt;
As a consequence you absolutely cannot have $var in there! Or string concatenations.&lt;br /&gt;
I.e.&lt;br /&gt;
  $food=self::_(&amp;quot;Banana&amp;quot;);// good&lt;br /&gt;
  self::_(&amp;quot;User gives $food to a cat&amp;quot;); // bad&lt;br /&gt;
For the translator we will have two strings &amp;quot;Banana&amp;quot; and &amp;quot;User gives $food to a cat&amp;quot;, but in runtime we will be&lt;br /&gt;
&amp;quot;Banana&amp;quot; and &amp;quot;User gives Banana to a cat&amp;quot; and second string would not match anything. And this is as bad&lt;br /&gt;
  self::_(&amp;quot;User gives &amp;quot;.$food.&amp;quot; to a cat&amp;quot;);// bad&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Throwing an exception because the player did a forbidden move ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// This will display a translatable red message to the player that just did some wrong action:&lt;br /&gt;
throw new BgaUserException( self::_(&#039;You must choose 3 cards&#039;) );&lt;br /&gt;
&lt;br /&gt;
// ... notice the use of BgaUserException that signals that this exception is &amp;quot;expected&amp;quot;. In theory, all exception that are expected should be translated.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Creating labels ====&lt;br /&gt;
&lt;br /&gt;
In &amp;quot;yourgame.view.php&amp;quot;, when creating the labels for the game interface used in your template (.tpl) file.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$this-&amp;gt;tpl[&#039;CARDS_FOR_YEAR_2&#039;] = self::_(&amp;quot;Your cards for year II&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Nota bene:&#039;&#039;&#039; it is recommended to set translated text in your interface client side rather than use template variables and server translation, so that translation works natively in replays (that don&#039;t have server side translations). For simple strings, the framework will handle moving the translation client side, but for more complex strings it may not work. In particular, you should not use server side translation for templates with substitution variables (or use the specific function &amp;quot;gameview_str_replace( $search, $replace, $string )&amp;quot; if not possible otherwise or for old code compatibility). Also, you should never use a &amp;quot;to_translate&amp;quot; class in your .tpl as it is used internally by the framework.&lt;br /&gt;
&lt;br /&gt;
Example with view.php:&lt;br /&gt;
in .tpl:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  &amp;lt;div id=&amp;quot;empire_title_{COLOR}&amp;quot; class=&amp;quot;side_title color_{COLOR}&amp;quot;&amp;gt;{EMPIRE_LABEL}&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
in view.php:&lt;br /&gt;
        $this-&amp;gt;page-&amp;gt;insert_block(&amp;quot;player_board&amp;quot;, array (&amp;quot;COLOR&amp;quot; =&amp;gt; $color,&amp;quot;PLAYER_NAME&amp;quot; =&amp;gt; $name,&amp;quot;PLAYER_NO&amp;quot; =&amp;gt; $no,&lt;br /&gt;
                &amp;quot;PLAYER_ID&amp;quot; =&amp;gt; $player_id, &amp;quot;CLASSES&amp;quot; =&amp;gt; $own?&amp;quot;own&amp;quot;:&amp;quot;&amp;quot;, &lt;br /&gt;
                &amp;quot;EMPIRE_LABEL&amp;quot; =&amp;gt; self::raw(gameview_str_replace(&#039;${player_name}&#039;, $name, self::_(&#039;${player_name}\&#039;s EMPIRE&#039;)))&lt;br /&gt;
              ));&lt;br /&gt;
Example with client side:&lt;br /&gt;
in .tpl:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  &amp;lt;div id=&amp;quot;empire_title_{COLOR}&amp;quot; class=&amp;quot;side_title color_{COLOR}&amp;quot;&amp;gt;Stub&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
in .js:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  for (var player_id in this.gamedatas.players) {&lt;br /&gt;
      var player_color = this.gamedatas.players[player_id].color;&lt;br /&gt;
      var player_name = this.gamedatas.players[player_id].name;&lt;br /&gt;
      $(&#039;empire_title_&#039;+player_color).innerHTML=this.format_string_recursive(_(&amp;quot;${player_name}&#039;s EMPIRE&amp;quot;), {player_name: player_name});&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Translating strings in material file ====&lt;br /&gt;
&lt;br /&gt;
Rarely, in your material.inc.php, if for example you need to use some string elements in your exceptions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// In material.inc.php, $this-&amp;gt;energies[n][&#039;nametr&#039;] has been created with the self::_() method. Now we can do this:&lt;br /&gt;
throw new BgaUserException( self::_(&amp;quot;To execute this action you need more: &amp;quot;).&#039; &#039;.$this-&amp;gt;energies[$resource_id][&#039;nametr&#039;] );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: you could also do this, so you don&#039;t need to pollute your material file&lt;br /&gt;
   throw new BgaUserException( self::_(&amp;quot;To execute this action you need more: &amp;quot;).&#039; &#039;.self::_($this-&amp;gt;energies[$resource_id][&#039;name&#039;]) );&lt;br /&gt;
&lt;br /&gt;
where $this-&amp;gt;energies[$resource_id][&#039;name&#039;] were marked in material file using regular clienttranslate function&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  $this-&amp;gt;energies = [&lt;br /&gt;
      22 =&amp;gt; [&lt;br /&gt;
          &#039;name&#039; =&amp;gt; clienttranslate(&#039;Sun&#039;)&lt;br /&gt;
          ...&lt;br /&gt;
      ]&lt;br /&gt;
  ];&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Strings in getAllDatas ====&lt;br /&gt;
&lt;br /&gt;
Rarely, in your &amp;quot;getAllDatas&amp;quot; PHP method, as the data return by this method is used only by current user.&lt;br /&gt;
&lt;br /&gt;
Note: not sure why would you send strings from the server in this case, as same can be achieved on the client usually.&lt;br /&gt;
&lt;br /&gt;
=== Function totranslate ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;totranslate( &amp;quot;my string to translate&amp;quot; ):&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This function works exactly like &#039;clienttranslate&#039;, except it tells BGA that the string is not needed on client side.&lt;br /&gt;
&lt;br /&gt;
You should not use this function, except on the following cases:&lt;br /&gt;
* Statistics name in stats.inc.php&lt;br /&gt;
* Option names and option values name in gameoptions.inc.php&lt;br /&gt;
&lt;br /&gt;
== Top Secret Undocumented Features ==&lt;br /&gt;
&lt;br /&gt;
If your string contains the clause &#039;$${value}&#039; (such as &#039;You gain $${value}.&#039;) then the translation system seems to move the position of the $ to a localized location (eg $5 in English but 5$ in French). This only seems to occur when using the argument &#039;value&#039;.&lt;br /&gt;
&lt;br /&gt;
In JavaScript, you can get the current user&#039;s language by retrieving the translation for the special string &amp;quot;$locale&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
    var lang = _(&#039;$locale&#039;); // en, fr, etc.&lt;br /&gt;
&lt;br /&gt;
== On server side - advanced (PHP) ==&lt;br /&gt;
&lt;br /&gt;
If you want to use translation system in your custom static modules, you will first need to expose the _() function :&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class mygame extends Table {&lt;br /&gt;
  // Exposing protected method translation&lt;br /&gt;
  public static function totranslate($text) {&lt;br /&gt;
    return self::_($text);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then you&#039;ll be able to use this directly in other modules by doing&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
throw new BgaUserException(mygame::totranslate(&amp;quot;Translated error from my awesome module file&amp;quot;));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Notice how the &amp;quot;totranslate&amp;quot; is also used by the static analysis to detect your string. So the following will not work :&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$msg = &amp;quot;Translated error from my awesome module file&amp;quot;;&lt;br /&gt;
throw new BgaUserException(mygame::totranslate($msg));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Analyze your project ==&lt;br /&gt;
&lt;br /&gt;
It looks super complex but there is help!&lt;br /&gt;
On studio control panel you can find a button &amp;quot;Check project&amp;quot; - it runs bunch of static analysis on your project including scanning for bad translations and missing translations.&lt;br /&gt;
It also will extact all you translation keys as translator will see them so you can double check - and run spell checker on them.&lt;br /&gt;
&lt;br /&gt;
== Other Useful Links ==&lt;br /&gt;
&lt;br /&gt;
* BLOG post about translations https://bga-devs.github.io/blog/posts/translations-summary/&lt;br /&gt;
&lt;br /&gt;
[[Category:Studio]]&lt;/div&gt;</summary>
		<author><name>Archduke</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Translations&amp;diff=13470</id>
		<title>Translations</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Translations&amp;diff=13470"/>
		<updated>2022-06-06T16:45:43Z</updated>

		<summary type="html">&lt;p&gt;Archduke: /* Formatting on client side */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Studio_Framework_Navigation}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Using BGA Studio, the game you create is ready to be translated to each language by the BGA community. To make this possible, you only need to specify which string must be translated and how to combine them.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
== Localization Overview ==&lt;br /&gt;
&lt;br /&gt;
Localization for BGA games happens largely on the CLIENT. Games must be developed in English and English strings are sent to the client.&lt;br /&gt;
&lt;br /&gt;
It&#039;s only at the client that your English strings will be displayed with the translation for the user&#039;s language, when such a translation exists.&lt;br /&gt;
&lt;br /&gt;
For anyone who has worked on a system where translation happens at the server and localized strings are sent to the client: you must unlearn what you have learned. Just stick with English and send the untranslated English strings. The magic happens at the client.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== How will my strings be translated? ==&lt;br /&gt;
&lt;br /&gt;
When developing your game, all strings must be in English. Strings must be coherent with the English version of the game.&lt;br /&gt;
&lt;br /&gt;
Once your game enters Beta, the BGA player community will descend upon your game like a plague of locusts and translate it into dozens of languages before you can say &amp;quot;Je ne parle pas anglais&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== What do I have to do from a programming standpoint? ==&lt;br /&gt;
&lt;br /&gt;
Not as much as you think. Read on for full details, but the golden rules are:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# Make sure that any string on the server side that needs to be translated on the client side is wrapped in a clienttranslate() function when defined. For example: $my_response = clienttranslate(&#039;Hey translators, please translate this string&#039;). clienttranslate doesn&#039;t actually do anything at all (it just passes the text through) but the translation engine searches your code for strings wrapped in that function and uses them to build the list of strings that need to be translated.&lt;br /&gt;
# On the client side, just display your text, but wrap it in _().&lt;br /&gt;
## If you pass a string constant to _() - such as _(&#039;This is my string&#039;) then the parser will automatically detect and add your string to the list of strings that need to be translated, AND it will display the local translation for it when displaying.&lt;br /&gt;
## If you pass a variable to _() - such as _(args.my_message) then MAKE SURE that the variable is set to an English string that is either defined somewhere in your PHP code in a clienttranslate() function or somewhere else in your javascript code in a _() function. As long as it is, the translators will provide translations for it, and the _() function will display the local translation of your English string.&lt;br /&gt;
# A string used as the message for notifyAllPlayers or notifyPlayer will automatically have its translation displayed on the client - you don&#039;t need to do anything EXCEPT make sure that it is wrapped in a clienttranslate() on the server, so that it gets translated.&lt;br /&gt;
# A string used as the &amp;quot;description&amp;quot; or &amp;quot;descriptionmyturn&amp;quot; for a state in your state machine will also be automatically translated on the client - you don&#039;t need to do anything EXCEPT make sure that it is wrapped in a clienttranslate() on the server, so that it gets translated.&lt;br /&gt;
# A string used in the pre-games option screen will also automatically have any translation displayed at the client - you don&#039;t need to do anything EXCEPT make sure that it is wrapped in a totranslate() on the server (nota bene: you should not use clienttranslate() here as this file is processed specifically and those strings will not be included in the game translation file but in the main site translation file - with a prefix to keep translations isolated by module - as they have to be translated on main site pages. If you need exactly the same string in your game for a client side translation, it should be declared somewhere else in your code wrapped inside a clienttranslate() to be included in the game translation file.&lt;br /&gt;
# A string used in the statistics screen will operate like a string in the pre-game options screen. It will automatically have any translation displayed at the client as long as you make sure that it is wrapped in a totranslate() on the server.&lt;br /&gt;
# If you are using parameters for a call to notifyAllPlayers or notifyPlayers, or for a state&#039;s &amp;quot;description&amp;quot; or &amp;quot;descriptionmyturn&amp;quot; and those parameters contain text that needs to be translated, you will need to tell the system to display the translated versions of them by using the &#039;i18n&#039; argument. See below for full details.&lt;br /&gt;
&lt;br /&gt;
== What strings should be translated? ==&lt;br /&gt;
&lt;br /&gt;
Every text that can be visible by the player when the game is running normally. This includes tooltips, texts on cards, error messages.&lt;br /&gt;
&lt;br /&gt;
This does NOT include error messages that are not supposed to happen (unexpected errors).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== What rules should I follow for the original English strings? ==&lt;br /&gt;
&lt;br /&gt;
For a coherent and homogeneous interface, here are some rules about ending a sentence with a final period &#039;.&#039;&lt;br /&gt;
&lt;br /&gt;
* As a general rule:&lt;br /&gt;
** If a sentence is displayed isolated in the interface =&amp;gt; no final period&lt;br /&gt;
** If a sentence is followed or could be followed by another sentence in the same interface space =&amp;gt; final period.&lt;br /&gt;
&lt;br /&gt;
* In detail:&lt;br /&gt;
** No final period:&lt;br /&gt;
*** button labels&lt;br /&gt;
*** section titles&lt;br /&gt;
*** menu elements&lt;br /&gt;
*** links triggering an isolated action&lt;br /&gt;
*** anything that is not a full sentence&lt;br /&gt;
*** current actions in the status bar&lt;br /&gt;
** Final period:&lt;br /&gt;
*** complete sentences (e.g., explanations and descriptions) that can be chained with other sentences&lt;br /&gt;
** Either a period or no period is acceptable (but this should be consistent throughout the game) for:&lt;br /&gt;
*** isolated tooltips / small sentences&lt;br /&gt;
*** game logs (no period is usually preferable)&lt;br /&gt;
*** error messages (unless there is more than one sentence in the error message; final period is mandatory in this case)&lt;br /&gt;
&lt;br /&gt;
Otherwise, you should try to follow as closely as possible the general style and format (including capitalization) used in the published English rulebook and game materials.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Focus on translating notifications ==&lt;br /&gt;
&lt;br /&gt;
Usually, translating a website is simple: you just call a function on every string you have to translate, and the string is translated in the player&#039;s language. On Board Game Arena, this is exactly the same with the &amp;quot;_( string )&amp;quot; function.&lt;br /&gt;
&lt;br /&gt;
However, there is one difference on BGA: notifications. The server is sending notifications to players, and most of the time the notifications are the same for every players, no matter what language each player is using. This is why notifications are translated on client side in the proper language, even if the strings are defined on server side.&lt;br /&gt;
&lt;br /&gt;
== How to not make translators crazy ;) ==&lt;br /&gt;
&lt;br /&gt;
* Try to reuse the exact same strings (with the same case, etc.) to minimize the number of strings to translate.&lt;br /&gt;
** &#039;&#039;&#039;Example&#039;&#039;&#039;: Consider replacing &amp;lt;pre&amp;gt;self::_(&amp;quot;Winner&amp;quot;)&amp;lt;/pre&amp;gt; and &amp;lt;pre&amp;gt;self::_(&amp;quot;Winners&amp;quot;)&amp;lt;/pre&amp;gt; (two strings to translate) with &amp;lt;pre&amp;gt;self::_(&amp;quot;Winner(s)&amp;quot;)&amp;lt;/pre&amp;gt;&lt;br /&gt;
** &#039;&#039;&#039;Example 2&#039;&#039;&#039;: &amp;lt;pre&amp;gt;clienttranslate(&amp;quot;play a card&amp;quot;)&amp;lt;/pre&amp;gt; and &amp;lt;pre&amp;gt;clienttranslate(&amp;quot;Play a card&amp;quot;)&amp;lt;/pre&amp;gt; means there will be two strings to translate.&lt;br /&gt;
* Do not mark as translatable a game element that does not have to be translated (e.g., if the name of a monster on a card is &amp;quot;Zzzzz&amp;quot;, maybe there&#039;s no need to translate it).&lt;br /&gt;
* Words does not come in the same order in each language. Thus, when you have to translate a string with an argument, do not write something like:&lt;br /&gt;
&amp;lt;pre&amp;gt;self::_(&amp;quot;First part of the string, &amp;quot;).$argument.&#039; &#039;.self::_(&amp;quot;second part of the string&amp;quot;)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Write instead:&lt;br /&gt;
&amp;lt;pre&amp;gt;sprintf( self::_(&amp;quot;First part of the string, %s second part of the string&amp;quot;), $argument )&amp;lt;/pre&amp;gt;&lt;br /&gt;
(or the equivalent &amp;quot;dojo.string.substitute&amp;quot; in Javascript)&lt;br /&gt;
* When translators are going to translate your game, the most difficult task for them is to get the context of the string to be translated. The shorter the string is, the more difficult the task is for them. As a rule of thumb, try to avoid short, insignificant strings that require knowledge of their surrounding context. You can also leave a comment on the context of the string in the translation program (English to English) if you are the developer of the game.&lt;br /&gt;
* The BGA translation policy is to be flexible on grammar. We prefer to write &amp;quot;player gets 1 coin(s)&amp;quot; rather than write two versions of the same string for plural and singular - it reduces the number of strings to translate.&lt;br /&gt;
* Instead of writing elaborate strings like &amp;quot;With the effect of ZZZ, player XXX gains a new YYY&amp;quot;, which is very difficult to translate, write strings like &amp;quot;ZZZ: XXX gets YYY&amp;quot;.&lt;br /&gt;
* Use present tense instead of past. E.g., &amp;quot;player gets wood&amp;quot; instead of &amp;quot;player got wood&amp;quot;.&lt;br /&gt;
* Avoid using gender-specific wording as much as possible. If needed be aware that [[https://forum.boardgamearena.com/viewtopic.php?f=11&amp;amp;t=19432&amp;amp;start=10#p88592 a pronoun replacement system]] is in place, and cannot work if your use &amp;quot;their&amp;quot; as a singular genderless pronoun, as it removes the information that it&#039;s singular. E.g., you should write &amp;quot;playerX returns card to *his* hand&amp;quot; or &amp;quot;playerX returns card to *his/her* hand&amp;quot; and not &amp;quot;playerX returns card to *their* hand&amp;quot; as in the 2 first case the system will substitute the proper pronoun his/her/their depending on playerX declared/undeclared gender, but in the second case it will always stay &amp;quot;their&amp;quot; whatever the player preference setting.&lt;br /&gt;
* Where two strings are identical apart from (say) a number, use the same string with a ${parameter}, and call format_string_recursive (on the client) or use args (for notifications and state descriptions) to provide the details. But *never* do that for composing multiple sentences with words: other languages have different grammar and it would most likely create untranslatable strings.&lt;br /&gt;
&lt;br /&gt;
== WARNING: Make sure your strings will be translated! ==&lt;br /&gt;
&lt;br /&gt;
For each game, our translation tool does a full scan of the code, looking for translation markers like &amp;quot;_()&amp;quot; or &amp;quot;clienttranslate()&amp;quot;. (See below for the full list of translation markers.)&lt;br /&gt;
&lt;br /&gt;
If your original string is not completely contained inside one of these markers, it won&#039;t be translated.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    // Examples: the following strings will be translated:&lt;br /&gt;
    var mystring_translated = _(&amp;quot;my string&amp;quot;);       // JS&lt;br /&gt;
    $mystring_translated = self::_(&amp;quot;my string&amp;quot;);    // PHP&lt;br /&gt;
    $mystring_translated = sprintf( self::_(&amp;quot;my string with an %s argument&amp;quot;), $argument );   // PHP&lt;br /&gt;
&lt;br /&gt;
    // Examples: the following strings WILL NOT be translated:&lt;br /&gt;
    $my_string = &amp;quot;my string&amp;quot;;&lt;br /&gt;
    $not_translated = self::_( $my_string );   // The original string is not contained within a translator marker =&amp;gt; no translation&lt;br /&gt;
    $not_translated = self::_( sprintf( &amp;quot;my string with a %s argument&amp;quot;, $argument ) ); // Ditto&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== On client side (Javascript) ==&lt;br /&gt;
&lt;br /&gt;
On client side, things are quite simple: you just have to use the &amp;quot;_()&amp;quot; function for all strings you want to translate.&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// Get a string in player&#039;s language:&lt;br /&gt;
var translated = _(&amp;quot;original english string&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
// Get a string in player&#039;s language with parameter:&lt;br /&gt;
var translated = dojo.string.substitute( _(&amp;quot;You can pick ${p} cards and discard ${d}&amp;quot;), {&lt;br /&gt;
    p: 2,&lt;br /&gt;
    d: 4&lt;br /&gt;
} );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;WARNING:&#039;&#039;&#039; in Javascript strings to translate, you should never use &#039;\n&#039;, &#039;\t&#039; or such, as it will break the translation bundle and result in all the Javascript translation to fail. In any case, the strings will result in HTML code, and such character codes won&#039;t have any impact on the HTML rendering. You should use HTML markup instead.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ANOTHER WARNING:&#039;&#039;&#039; you cannot use this function _() in the javascript object constructor, but you can achieve the same if you use it the setup method&lt;br /&gt;
&lt;br /&gt;
=== Formatting on client side ===&lt;br /&gt;
&lt;br /&gt;
Sometimes you will want to apply some formatting on the client side, but don&#039;t want to put HTML tags within the source string (which may be confusing for translators).&lt;br /&gt;
&lt;br /&gt;
This can be achieved with the &amp;lt;code&amp;gt;bga_format&amp;lt;/code&amp;gt; function and Markdown-style syntax.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * @function bga_format&lt;br /&gt;
 * Replaces delimiters with HTML tags in translated text&lt;br /&gt;
 * @param {string} translated string&lt;br /&gt;
 * @param {Object} map of replacements to make, should be of the form&lt;br /&gt;
 *     {&lt;br /&gt;
 *         &#039;*&#039;: (t) =&amp;gt; t,&lt;br /&gt;
 *         &#039;_&#039;: &#039;classname&#039;,&lt;br /&gt;
 *     }&lt;br /&gt;
 *     keys are delimiters within the translated string&lt;br /&gt;
 *     values are either strings (classname of surrounding span) or function (flexible replacements)&lt;br /&gt;
 * @returns {string} Returns the original string, with replacements made.&lt;br /&gt;
 */&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// Get a string in player&#039;s language:&lt;br /&gt;
bga_format(_(&#039;You receive a *special* _tile_&#039;), {&lt;br /&gt;
    &#039;*&#039;: (t) =&amp;gt; &#039;&amp;lt;b&amp;gt;&#039; + t + &#039;&amp;lt;/b&amp;gt;&#039;,&lt;br /&gt;
    &#039;_&#039;: &#039;tile-name&#039;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The above will return something along the lines of:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
You receive a &amp;lt;b&amp;gt;special&amp;lt;/b&amp;gt; &amp;lt;span class=&amp;quot;tile-name&amp;quot;&amp;gt;tile&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Or, if the user is playing in Spanish, for example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Recibes una &amp;lt;span class=&amp;quot;tile-name&amp;quot;&amp;gt;loseta&amp;lt;/span&amp;gt; &amp;lt;b&amp;gt;especial&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Notes:&lt;br /&gt;
* The text passed to &amp;lt;code&amp;gt;bga_format&amp;lt;/code&amp;gt; must still be translated using &amp;lt;code&amp;gt;_()&amp;lt;/code&amp;gt;, don&#039;t forget it!&lt;br /&gt;
* The characters available to demarcate formatting are: &amp;lt;code&amp;gt;[&#039;-&#039;, &#039;*&#039;, &#039;+&#039;, &#039;?&#039;, &#039;.&#039;, &#039;,&#039;, &#039;\\&#039;, &#039;^&#039;, &#039;$&#039;, &#039;|&#039;, &#039;#&#039;, &#039; &#039;]&amp;lt;/code&amp;gt;&lt;br /&gt;
* If the replacements object is a string, the inner text will be placed within a &amp;lt;code&amp;gt;&amp;amp;lt;span&amp;amp;gt;&amp;lt;/code&amp;gt; tag with the string as a class&lt;br /&gt;
* If the replacements object is a function, the inner text will be passed as an argument to the function, and the return value will replace the text and the delimiters&lt;br /&gt;
&lt;br /&gt;
== On server side (PHP) ==&lt;br /&gt;
&lt;br /&gt;
On PHP side, you can use 3 different functions to specify that a string must be translated.&lt;br /&gt;
&lt;br /&gt;
=== Function clienttranslate ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;clienttranslate( &#039;string to translate&#039; ):&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This function is &#039;&#039;transparent&#039;&#039;: it will return the original English string without any change. Its only purpose is to mark this string as &amp;quot;must be translated&amp;quot;, and to make sure the translated version of the string will be available on client side.&lt;br /&gt;
&lt;br /&gt;
In general, you use clienttranslate:&lt;br /&gt;
* In your &#039;&#039;&#039;states.inc.php&#039;&#039;&#039;, for the fields &amp;quot;description&amp;quot; and &amp;quot;descriptionmyturn&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
      &amp;quot;description&amp;quot; =&amp;gt; clienttranslate(&#039;${card_name}: ${actplayer} must discard 4 identical energies&#039;),&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* In &#039;&#039;&#039;material.inc.php&#039;&#039;&#039;, when defining text for game materials that must be displayed on the client side.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$this-&amp;gt;card_types = array(&lt;br /&gt;
&lt;br /&gt;
     1 =&amp;gt; array(&lt;br /&gt;
        &#039;name&#039; =&amp;gt; clienttranslate(&#039;Amulet of Air&#039;), // Thus, we can use &amp;quot;_( card_name )&amp;quot; on Javascript side.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* When sending a notification with &#039;&#039;notifyAllPlayers&#039;&#039; or &#039;&#039;notifyPlayer&#039;&#039;, in the game log string and all game log arguments that need a translation.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
     // A game log string with no argument:&lt;br /&gt;
     self::notifyAllPlayers( &#039;pickLibraryCards&#039;, clienttranslate(&#039;Everyone draw cards from their library&#039;), [] );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As a consequence there is no point passing variables to this function. E.g.:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    notif=&amp;quot;foo&amp;quot;;&lt;br /&gt;
    self::notifyAllPlayers( &#039;log&#039;, clienttranslate(notif),[]); // BAD&lt;br /&gt;
    &lt;br /&gt;
    notif=clienttranslate(&amp;quot;foo&amp;quot;);&lt;br /&gt;
    self::notifyAllPlayers( &#039;log&#039;, notif,[]); // GOOD&lt;br /&gt;
&lt;br /&gt;
    self::notifyAllPlayers( &#039;log&#039;, clienttranslate(&amp;quot;player gains ${num} gems&amp;quot;),[num=&amp;gt;2]); // BAD it is dynamic string enterpreted by php &lt;br /&gt;
    self::notifyAllPlayers( &#039;log&#039;, clienttranslate(&#039;player gains ${num} gems&#039;),[num=&amp;gt;2]); // GOOD, difference is single quotes&lt;br /&gt;
&lt;br /&gt;
    self::notifyAllPlayers( &#039;log&#039;, clienttranslate(&amp;quot;player gains &amp;quot;.${num}.&amp;quot; gems&amp;quot;),[num=&amp;gt;2]); // BAD concatenation &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Translating arguments is a little bit more complex. This uses the &#039;&#039;&#039;i18n&#039;&#039;&#039; special argument as below:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 // In the following example, we translate the game log itself, but also the &amp;quot;card_name&amp;quot; argument:&lt;br /&gt;
&lt;br /&gt;
 self::notifyAllPlayers( &#039;winPoints&#039;, clienttranslate(&#039;${card_name}: ${player_name} gains ${points} point(s)&#039;), array(&lt;br /&gt;
                &#039;i18n&#039; =&amp;gt; array( &#039;card_name&#039; ),     // &amp;lt;===== We specify here that &amp;quot;card_name&amp;quot; argument must be translated&lt;br /&gt;
                &#039;player_id&#039; =&amp;gt; $player_id,&lt;br /&gt;
                &#039;player_name&#039; =&amp;gt; self::getActivePlayerName(),&lt;br /&gt;
                &#039;points&#039; =&amp;gt; $points,&lt;br /&gt;
                &#039;card_name&#039; =&amp;gt; $this-&amp;gt;card_types[8][&#039;name&#039;] // &amp;lt;==== Here, we provide original English string.&lt;br /&gt;
            ) ); &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To ensure the translation of the i18n argument will be made, clienttranslate must have been used somewhere, for instance:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$this-&amp;gt;card_types = array(&lt;br /&gt;
...&lt;br /&gt;
     8 =&amp;gt; array(&lt;br /&gt;
        &#039;name&#039; =&amp;gt; clienttranslate(&amp;quot;Amulet of Fire&amp;quot;),&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Pay attention when using the &#039;&#039;&#039;i18n&#039;&#039;&#039; argument when translating arguments for the client: do NOT use same argument for both translations AND key codes for client-side actions (like using &#039;card_name&#039; to move it on the player board as described in the example). It&#039;s pretty obvious in the example, but it can be very tricky when translation is made at the end of the development (which is often the case). Use explicit argument names like &#039;card_name_translated&#039; by example.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;WARNING:&#039;&#039;&#039; you should NEVER use concatenation with &#039;&#039;clienttranslate&#039;&#039;, as it would result in a different string to translate at runtime than the one retrieved statically in the translation system, and so translation would not be applied. If you need to compose a string, use substitution and the i18n parameter (but you also have to pay attention not to compose sentences in a way that is dependent upon the English language specific syntax, or it may be impossible to translate correctly in another language: sometimes, you need multiple full sentences rather than relying on substitution).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Method _ (underscore) ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;self::_( &amp;quot;my string to translate&amp;quot; ):&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This function returns a string translated in the language of CURRENT user (i.e. player who send the request to the server) (be careful, this is NOT the active player).&lt;br /&gt;
&lt;br /&gt;
This can be used like self::_(&#039;bla&#039;) or this-&amp;gt;(&#039;bla&#039;). You cannot use static underscore function _(&#039;bla&#039;) in php, it is not the same, it will not translate strings from your game.&lt;br /&gt;
&lt;br /&gt;
The returned string will be surrounded by HTML tags, so you cannot use it in places where pure text is required or your string already has another html markup.&lt;br /&gt;
&lt;br /&gt;
Most of the time, you don&#039;t need to translate strings on server side, except on the following situations:&lt;br /&gt;
* Throwing user exceptions&lt;br /&gt;
* Creating the labels for the game interface used in your template&lt;br /&gt;
* Rarely, in your material.inc.php, if for example you need to use some string elements in your exceptions&lt;br /&gt;
* Rarely, in your &amp;quot;getAllDatas&amp;quot; PHP method, as the data return by this method is used only by current user&lt;br /&gt;
&lt;br /&gt;
Imporant! This function does two things:&lt;br /&gt;
* Mark string for translation&lt;br /&gt;
* Translates in runtime&lt;br /&gt;
As a consequence you absolutely cannot have $var in there! Or string concatenations.&lt;br /&gt;
I.e.&lt;br /&gt;
  $food=self::_(&amp;quot;Banana&amp;quot;);// good&lt;br /&gt;
  self::_(&amp;quot;User gives $food to a cat&amp;quot;); // bad&lt;br /&gt;
For the translator we will have two strings &amp;quot;Banana&amp;quot; and &amp;quot;User gives $food to a cat&amp;quot;, but in runtime we will be&lt;br /&gt;
&amp;quot;Banana&amp;quot; and &amp;quot;User gives Banana to a cat&amp;quot; and second string would not match anything. And this is as bad&lt;br /&gt;
  self::_(&amp;quot;User gives &amp;quot;.$food.&amp;quot; to a cat&amp;quot;);// bad&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Throwing an exception because the player did a forbidden move ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// This will display a translatable red message to the player that just did some wrong action:&lt;br /&gt;
throw new BgaUserException( self::_(&#039;You must choose 3 cards&#039;) );&lt;br /&gt;
&lt;br /&gt;
// ... notice the use of BgaUserException that signals that this exception is &amp;quot;expected&amp;quot;. In theory, all exception that are expected should be translated.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Creating labels ====&lt;br /&gt;
&lt;br /&gt;
In &amp;quot;yourgame.view.php&amp;quot;, when creating the labels for the game interface used in your template (.tpl) file.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$this-&amp;gt;tpl[&#039;CARDS_FOR_YEAR_2&#039;] = self::_(&amp;quot;Your cards for year II&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Nota bene:&#039;&#039;&#039; it is recommended to set translated text in your interface client side rather than use template variables and server translation, so that translation works natively in replays (that don&#039;t have server side translations). For simple strings, the framework will handle moving the translation client side, but for more complex strings it may not work. In particular, you should not use server side translation for templates with substitution variables (or use the specific function &amp;quot;gameview_str_replace( $search, $replace, $string )&amp;quot; if not possible otherwise or for old code compatibility). Also, you should never use a &amp;quot;to_translate&amp;quot; class in your .tpl as it is used internally by the framework.&lt;br /&gt;
&lt;br /&gt;
Example with view.php:&lt;br /&gt;
in .tpl:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  &amp;lt;div id=&amp;quot;empire_title_{COLOR}&amp;quot; class=&amp;quot;side_title color_{COLOR}&amp;quot;&amp;gt;{EMPIRE_LABEL}&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
in view.php:&lt;br /&gt;
        $this-&amp;gt;page-&amp;gt;insert_block(&amp;quot;player_board&amp;quot;, array (&amp;quot;COLOR&amp;quot; =&amp;gt; $color,&amp;quot;PLAYER_NAME&amp;quot; =&amp;gt; $name,&amp;quot;PLAYER_NO&amp;quot; =&amp;gt; $no,&lt;br /&gt;
                &amp;quot;PLAYER_ID&amp;quot; =&amp;gt; $player_id, &amp;quot;CLASSES&amp;quot; =&amp;gt; $own?&amp;quot;own&amp;quot;:&amp;quot;&amp;quot;, &lt;br /&gt;
                &amp;quot;EMPIRE_LABEL&amp;quot; =&amp;gt; self::raw(gameview_str_replace(&#039;${player_name}&#039;, $name, self::_(&#039;${player_name}\&#039;s EMPIRE&#039;)))&lt;br /&gt;
              ));&lt;br /&gt;
Example with client side:&lt;br /&gt;
in .tpl:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  &amp;lt;div id=&amp;quot;empire_title_{COLOR}&amp;quot; class=&amp;quot;side_title color_{COLOR}&amp;quot;&amp;gt;Stub&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
in .js:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  for (var player_id in this.gamedatas.players) {&lt;br /&gt;
      var player_color = this.gamedatas.players[player_id].color;&lt;br /&gt;
      var player_name = this.gamedatas.players[player_id].name;&lt;br /&gt;
      $(&#039;empire_title_&#039;+player_color).innerHTML=this.format_string_recursive(_(&amp;quot;${player_name}&#039;s EMPIRE&amp;quot;), {player_name: player_name});&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Translating strings in material file ====&lt;br /&gt;
&lt;br /&gt;
Rarely, in your material.inc.php, if for example you need to use some string elements in your exceptions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// In material.inc.php, $this-&amp;gt;energies[n][&#039;nametr&#039;] has been created with the self::_() method. Now we can do this:&lt;br /&gt;
throw new BgaUserException( self::_(&amp;quot;To execute this action you need more: &amp;quot;).&#039; &#039;.$this-&amp;gt;energies[$resource_id][&#039;nametr&#039;] );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: you could also do this, so you don&#039;t need to pollute your material file&lt;br /&gt;
   throw new BgaUserException( self::_(&amp;quot;To execute this action you need more: &amp;quot;).&#039; &#039;.self::_($this-&amp;gt;energies[$resource_id][&#039;name&#039;]) );&lt;br /&gt;
&lt;br /&gt;
where $this-&amp;gt;energies[$resource_id][&#039;name&#039;] were marked in material file using regular clienttranslate function&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  $this-&amp;gt;energies = [&lt;br /&gt;
      22 =&amp;gt; [&lt;br /&gt;
          &#039;name&#039; =&amp;gt; clienttranslate(&#039;Sun&#039;)&lt;br /&gt;
          ...&lt;br /&gt;
      ]&lt;br /&gt;
  ];&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Strings in getAllDatas ====&lt;br /&gt;
&lt;br /&gt;
Rarely, in your &amp;quot;getAllDatas&amp;quot; PHP method, as the data return by this method is used only by current user.&lt;br /&gt;
&lt;br /&gt;
Note: not sure why would you send strings from the server in this case, as same can be achieved on the client usually.&lt;br /&gt;
&lt;br /&gt;
=== Function totranslate ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;totranslate( &amp;quot;my string to translate&amp;quot; ):&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This function works exactly like &#039;clienttranslate&#039;, except it tells BGA that the string is not needed on client side.&lt;br /&gt;
&lt;br /&gt;
You should not use this function, except on the following cases:&lt;br /&gt;
* Statistics name in stats.inc.php&lt;br /&gt;
* Option names and option values name in gameoptions.inc.php&lt;br /&gt;
&lt;br /&gt;
== Top Secret Undocumented Features ==&lt;br /&gt;
&lt;br /&gt;
If your string contains the clause &#039;$${value}&#039; (such as &#039;You gain $${value}.&#039;) then the translation system seems to move the position of the $ to a localized location (eg $5 in English but 5$ in French). This only seems to occur when using the argument &#039;value&#039;.&lt;br /&gt;
&lt;br /&gt;
In JavaScript, you can get the current user&#039;s language by retrieving the translation for the special string &amp;quot;$locale&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
    var lang = _(&#039;$locale&#039;); // en, fr, etc.&lt;br /&gt;
&lt;br /&gt;
== On server side - advanced (PHP) ==&lt;br /&gt;
&lt;br /&gt;
If you want to use translation system in your custom static modules, you will first need to expose the _() function :&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class mygame extends Table {&lt;br /&gt;
  // Exposing protected method translation&lt;br /&gt;
  public static function totranslate($text) {&lt;br /&gt;
    return self::_($text);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then you&#039;ll be able to use this directly in other modules by doing&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
throw new BgaUserException(mygame::totranslate(&amp;quot;Translated error from my awesome module file&amp;quot;));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Notice how the &amp;quot;totranslate&amp;quot; is also used by the static analysis to detect your string. So the following will not work :&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$msg = &amp;quot;Translated error from my awesome module file&amp;quot;;&lt;br /&gt;
throw new BgaUserException(mygame::totranslate($msg));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Analyze your project ==&lt;br /&gt;
&lt;br /&gt;
It looks super complex but there is help!&lt;br /&gt;
On studio control panel you can find a button &amp;quot;Check project&amp;quot; - it runs bunch of static analysis on your project including scanning for bad translations and missing translations.&lt;br /&gt;
It also will extact all you translation keys as translator will see them so you can double check - and run spell checker on them.&lt;br /&gt;
&lt;br /&gt;
== Other Useful Links ==&lt;br /&gt;
&lt;br /&gt;
* BLOG post about translations https://bga-devs.github.io/blog/posts/translations-summary/&lt;br /&gt;
&lt;br /&gt;
[[Category:Studio]]&lt;/div&gt;</summary>
		<author><name>Archduke</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Translations&amp;diff=13469</id>
		<title>Translations</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Translations&amp;diff=13469"/>
		<updated>2022-06-06T16:44:38Z</updated>

		<summary type="html">&lt;p&gt;Archduke: /* Formatting on client side */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Studio_Framework_Navigation}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Using BGA Studio, the game you create is ready to be translated to each language by the BGA community. To make this possible, you only need to specify which string must be translated and how to combine them.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
== Localization Overview ==&lt;br /&gt;
&lt;br /&gt;
Localization for BGA games happens largely on the CLIENT. Games must be developed in English and English strings are sent to the client.&lt;br /&gt;
&lt;br /&gt;
It&#039;s only at the client that your English strings will be displayed with the translation for the user&#039;s language, when such a translation exists.&lt;br /&gt;
&lt;br /&gt;
For anyone who has worked on a system where translation happens at the server and localized strings are sent to the client: you must unlearn what you have learned. Just stick with English and send the untranslated English strings. The magic happens at the client.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== How will my strings be translated? ==&lt;br /&gt;
&lt;br /&gt;
When developing your game, all strings must be in English. Strings must be coherent with the English version of the game.&lt;br /&gt;
&lt;br /&gt;
Once your game enters Beta, the BGA player community will descend upon your game like a plague of locusts and translate it into dozens of languages before you can say &amp;quot;Je ne parle pas anglais&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== What do I have to do from a programming standpoint? ==&lt;br /&gt;
&lt;br /&gt;
Not as much as you think. Read on for full details, but the golden rules are:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# Make sure that any string on the server side that needs to be translated on the client side is wrapped in a clienttranslate() function when defined. For example: $my_response = clienttranslate(&#039;Hey translators, please translate this string&#039;). clienttranslate doesn&#039;t actually do anything at all (it just passes the text through) but the translation engine searches your code for strings wrapped in that function and uses them to build the list of strings that need to be translated.&lt;br /&gt;
# On the client side, just display your text, but wrap it in _().&lt;br /&gt;
## If you pass a string constant to _() - such as _(&#039;This is my string&#039;) then the parser will automatically detect and add your string to the list of strings that need to be translated, AND it will display the local translation for it when displaying.&lt;br /&gt;
## If you pass a variable to _() - such as _(args.my_message) then MAKE SURE that the variable is set to an English string that is either defined somewhere in your PHP code in a clienttranslate() function or somewhere else in your javascript code in a _() function. As long as it is, the translators will provide translations for it, and the _() function will display the local translation of your English string.&lt;br /&gt;
# A string used as the message for notifyAllPlayers or notifyPlayer will automatically have its translation displayed on the client - you don&#039;t need to do anything EXCEPT make sure that it is wrapped in a clienttranslate() on the server, so that it gets translated.&lt;br /&gt;
# A string used as the &amp;quot;description&amp;quot; or &amp;quot;descriptionmyturn&amp;quot; for a state in your state machine will also be automatically translated on the client - you don&#039;t need to do anything EXCEPT make sure that it is wrapped in a clienttranslate() on the server, so that it gets translated.&lt;br /&gt;
# A string used in the pre-games option screen will also automatically have any translation displayed at the client - you don&#039;t need to do anything EXCEPT make sure that it is wrapped in a totranslate() on the server (nota bene: you should not use clienttranslate() here as this file is processed specifically and those strings will not be included in the game translation file but in the main site translation file - with a prefix to keep translations isolated by module - as they have to be translated on main site pages. If you need exactly the same string in your game for a client side translation, it should be declared somewhere else in your code wrapped inside a clienttranslate() to be included in the game translation file.&lt;br /&gt;
# A string used in the statistics screen will operate like a string in the pre-game options screen. It will automatically have any translation displayed at the client as long as you make sure that it is wrapped in a totranslate() on the server.&lt;br /&gt;
# If you are using parameters for a call to notifyAllPlayers or notifyPlayers, or for a state&#039;s &amp;quot;description&amp;quot; or &amp;quot;descriptionmyturn&amp;quot; and those parameters contain text that needs to be translated, you will need to tell the system to display the translated versions of them by using the &#039;i18n&#039; argument. See below for full details.&lt;br /&gt;
&lt;br /&gt;
== What strings should be translated? ==&lt;br /&gt;
&lt;br /&gt;
Every text that can be visible by the player when the game is running normally. This includes tooltips, texts on cards, error messages.&lt;br /&gt;
&lt;br /&gt;
This does NOT include error messages that are not supposed to happen (unexpected errors).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== What rules should I follow for the original English strings? ==&lt;br /&gt;
&lt;br /&gt;
For a coherent and homogeneous interface, here are some rules about ending a sentence with a final period &#039;.&#039;&lt;br /&gt;
&lt;br /&gt;
* As a general rule:&lt;br /&gt;
** If a sentence is displayed isolated in the interface =&amp;gt; no final period&lt;br /&gt;
** If a sentence is followed or could be followed by another sentence in the same interface space =&amp;gt; final period.&lt;br /&gt;
&lt;br /&gt;
* In detail:&lt;br /&gt;
** No final period:&lt;br /&gt;
*** button labels&lt;br /&gt;
*** section titles&lt;br /&gt;
*** menu elements&lt;br /&gt;
*** links triggering an isolated action&lt;br /&gt;
*** anything that is not a full sentence&lt;br /&gt;
*** current actions in the status bar&lt;br /&gt;
** Final period:&lt;br /&gt;
*** complete sentences (e.g., explanations and descriptions) that can be chained with other sentences&lt;br /&gt;
** Either a period or no period is acceptable (but this should be consistent throughout the game) for:&lt;br /&gt;
*** isolated tooltips / small sentences&lt;br /&gt;
*** game logs (no period is usually preferable)&lt;br /&gt;
*** error messages (unless there is more than one sentence in the error message; final period is mandatory in this case)&lt;br /&gt;
&lt;br /&gt;
Otherwise, you should try to follow as closely as possible the general style and format (including capitalization) used in the published English rulebook and game materials.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Focus on translating notifications ==&lt;br /&gt;
&lt;br /&gt;
Usually, translating a website is simple: you just call a function on every string you have to translate, and the string is translated in the player&#039;s language. On Board Game Arena, this is exactly the same with the &amp;quot;_( string )&amp;quot; function.&lt;br /&gt;
&lt;br /&gt;
However, there is one difference on BGA: notifications. The server is sending notifications to players, and most of the time the notifications are the same for every players, no matter what language each player is using. This is why notifications are translated on client side in the proper language, even if the strings are defined on server side.&lt;br /&gt;
&lt;br /&gt;
== How to not make translators crazy ;) ==&lt;br /&gt;
&lt;br /&gt;
* Try to reuse the exact same strings (with the same case, etc.) to minimize the number of strings to translate.&lt;br /&gt;
** &#039;&#039;&#039;Example&#039;&#039;&#039;: Consider replacing &amp;lt;pre&amp;gt;self::_(&amp;quot;Winner&amp;quot;)&amp;lt;/pre&amp;gt; and &amp;lt;pre&amp;gt;self::_(&amp;quot;Winners&amp;quot;)&amp;lt;/pre&amp;gt; (two strings to translate) with &amp;lt;pre&amp;gt;self::_(&amp;quot;Winner(s)&amp;quot;)&amp;lt;/pre&amp;gt;&lt;br /&gt;
** &#039;&#039;&#039;Example 2&#039;&#039;&#039;: &amp;lt;pre&amp;gt;clienttranslate(&amp;quot;play a card&amp;quot;)&amp;lt;/pre&amp;gt; and &amp;lt;pre&amp;gt;clienttranslate(&amp;quot;Play a card&amp;quot;)&amp;lt;/pre&amp;gt; means there will be two strings to translate.&lt;br /&gt;
* Do not mark as translatable a game element that does not have to be translated (e.g., if the name of a monster on a card is &amp;quot;Zzzzz&amp;quot;, maybe there&#039;s no need to translate it).&lt;br /&gt;
* Words does not come in the same order in each language. Thus, when you have to translate a string with an argument, do not write something like:&lt;br /&gt;
&amp;lt;pre&amp;gt;self::_(&amp;quot;First part of the string, &amp;quot;).$argument.&#039; &#039;.self::_(&amp;quot;second part of the string&amp;quot;)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Write instead:&lt;br /&gt;
&amp;lt;pre&amp;gt;sprintf( self::_(&amp;quot;First part of the string, %s second part of the string&amp;quot;), $argument )&amp;lt;/pre&amp;gt;&lt;br /&gt;
(or the equivalent &amp;quot;dojo.string.substitute&amp;quot; in Javascript)&lt;br /&gt;
* When translators are going to translate your game, the most difficult task for them is to get the context of the string to be translated. The shorter the string is, the more difficult the task is for them. As a rule of thumb, try to avoid short, insignificant strings that require knowledge of their surrounding context. You can also leave a comment on the context of the string in the translation program (English to English) if you are the developer of the game.&lt;br /&gt;
* The BGA translation policy is to be flexible on grammar. We prefer to write &amp;quot;player gets 1 coin(s)&amp;quot; rather than write two versions of the same string for plural and singular - it reduces the number of strings to translate.&lt;br /&gt;
* Instead of writing elaborate strings like &amp;quot;With the effect of ZZZ, player XXX gains a new YYY&amp;quot;, which is very difficult to translate, write strings like &amp;quot;ZZZ: XXX gets YYY&amp;quot;.&lt;br /&gt;
* Use present tense instead of past. E.g., &amp;quot;player gets wood&amp;quot; instead of &amp;quot;player got wood&amp;quot;.&lt;br /&gt;
* Avoid using gender-specific wording as much as possible. If needed be aware that [[https://forum.boardgamearena.com/viewtopic.php?f=11&amp;amp;t=19432&amp;amp;start=10#p88592 a pronoun replacement system]] is in place, and cannot work if your use &amp;quot;their&amp;quot; as a singular genderless pronoun, as it removes the information that it&#039;s singular. E.g., you should write &amp;quot;playerX returns card to *his* hand&amp;quot; or &amp;quot;playerX returns card to *his/her* hand&amp;quot; and not &amp;quot;playerX returns card to *their* hand&amp;quot; as in the 2 first case the system will substitute the proper pronoun his/her/their depending on playerX declared/undeclared gender, but in the second case it will always stay &amp;quot;their&amp;quot; whatever the player preference setting.&lt;br /&gt;
* Where two strings are identical apart from (say) a number, use the same string with a ${parameter}, and call format_string_recursive (on the client) or use args (for notifications and state descriptions) to provide the details. But *never* do that for composing multiple sentences with words: other languages have different grammar and it would most likely create untranslatable strings.&lt;br /&gt;
&lt;br /&gt;
== WARNING: Make sure your strings will be translated! ==&lt;br /&gt;
&lt;br /&gt;
For each game, our translation tool does a full scan of the code, looking for translation markers like &amp;quot;_()&amp;quot; or &amp;quot;clienttranslate()&amp;quot;. (See below for the full list of translation markers.)&lt;br /&gt;
&lt;br /&gt;
If your original string is not completely contained inside one of these markers, it won&#039;t be translated.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    // Examples: the following strings will be translated:&lt;br /&gt;
    var mystring_translated = _(&amp;quot;my string&amp;quot;);       // JS&lt;br /&gt;
    $mystring_translated = self::_(&amp;quot;my string&amp;quot;);    // PHP&lt;br /&gt;
    $mystring_translated = sprintf( self::_(&amp;quot;my string with an %s argument&amp;quot;), $argument );   // PHP&lt;br /&gt;
&lt;br /&gt;
    // Examples: the following strings WILL NOT be translated:&lt;br /&gt;
    $my_string = &amp;quot;my string&amp;quot;;&lt;br /&gt;
    $not_translated = self::_( $my_string );   // The original string is not contained within a translator marker =&amp;gt; no translation&lt;br /&gt;
    $not_translated = self::_( sprintf( &amp;quot;my string with a %s argument&amp;quot;, $argument ) ); // Ditto&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== On client side (Javascript) ==&lt;br /&gt;
&lt;br /&gt;
On client side, things are quite simple: you just have to use the &amp;quot;_()&amp;quot; function for all strings you want to translate.&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// Get a string in player&#039;s language:&lt;br /&gt;
var translated = _(&amp;quot;original english string&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
// Get a string in player&#039;s language with parameter:&lt;br /&gt;
var translated = dojo.string.substitute( _(&amp;quot;You can pick ${p} cards and discard ${d}&amp;quot;), {&lt;br /&gt;
    p: 2,&lt;br /&gt;
    d: 4&lt;br /&gt;
} );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;WARNING:&#039;&#039;&#039; in Javascript strings to translate, you should never use &#039;\n&#039;, &#039;\t&#039; or such, as it will break the translation bundle and result in all the Javascript translation to fail. In any case, the strings will result in HTML code, and such character codes won&#039;t have any impact on the HTML rendering. You should use HTML markup instead.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ANOTHER WARNING:&#039;&#039;&#039; you cannot use this function _() in the javascript object constructor, but you can achieve the same if you use it the setup method&lt;br /&gt;
&lt;br /&gt;
=== Formatting on client side ===&lt;br /&gt;
&lt;br /&gt;
Sometimes you will want to apply some formatting on the client side, but don&#039;t want to put HTML tags within the source string (which may be confusing for translators).&lt;br /&gt;
&lt;br /&gt;
This can be achieved with the &amp;lt;code&amp;gt;bga_format&amp;lt;/code&amp;gt; function and Markdown-style syntax.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * @function bga_format&lt;br /&gt;
 * Replaces delimiters with HTML tags in translated text&lt;br /&gt;
 * @param {string} translated string&lt;br /&gt;
 * @param {Object} map of replacements to make, should be of the form&lt;br /&gt;
 *     {&lt;br /&gt;
 *         &#039;*&#039;: (t) =&amp;gt; t,&lt;br /&gt;
 *         &#039;_&#039;: &#039;classname&#039;,&lt;br /&gt;
 *     }&lt;br /&gt;
 *     keys are delimiters within the translated string&lt;br /&gt;
 *     values are either strings (classname of surrounding span) or function (flexible replacements)&lt;br /&gt;
 * @returns {string} Returns the original string, with replacements made.&lt;br /&gt;
 */&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// Get a string in player&#039;s language:&lt;br /&gt;
bga_format(_(&#039;You receive a *special* _tile_&#039;), {&lt;br /&gt;
    &#039;*&#039;: (t) =&amp;gt; &#039;&amp;lt;b&amp;gt;&#039; + t + &#039;&amp;lt;/b&amp;gt;&#039;,&lt;br /&gt;
    &#039;_&#039;: &#039;tile-name&#039;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The above will return something along the lines of:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
You receive a &amp;lt;b&amp;gt;special&amp;lt;/b&amp;gt; &amp;lt;span class=&amp;quot;tile-name&amp;quot;&amp;gt;tile&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Or, if the user is playing in Spanish, for example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Recibes una &amp;lt;span class=&amp;quot;tile-name&amp;quot;&amp;gt;loseta&amp;lt;/span&amp;gt; &amp;lt;b&amp;gt;especial&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Notes:&lt;br /&gt;
* The text passed to &amp;lt;code&amp;gt;bga_format&amp;lt;/code&amp;gt; must still be translated using &amp;lt;code&amp;gt;_()&amp;lt;/code&amp;gt;, don&#039;t forget it!&lt;br /&gt;
* The characters available to demarcate formatting are: &amp;lt;code&amp;gt;[&#039;-&#039;, &#039;*&#039;, &#039;+&#039;, &#039;?&#039;, &#039;.&#039;, &#039;,&#039;, &#039;\\&#039;, &#039;^&#039;, &#039;$&#039;, &#039;|&#039;, &#039;#&#039;, &#039; &#039;]&amp;lt;/code&amp;gt;&lt;br /&gt;
* If the replacements object is a string, the inner text will be placed within a `\&amp;lt;span\&amp;gt;` tag with the string as a class&lt;br /&gt;
* If the replacements object is a function, the inner text will be passed as an argument to the function, and the return value will replace the text and the delimiters&lt;br /&gt;
&lt;br /&gt;
== On server side (PHP) ==&lt;br /&gt;
&lt;br /&gt;
On PHP side, you can use 3 different functions to specify that a string must be translated.&lt;br /&gt;
&lt;br /&gt;
=== Function clienttranslate ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;clienttranslate( &#039;string to translate&#039; ):&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This function is &#039;&#039;transparent&#039;&#039;: it will return the original English string without any change. Its only purpose is to mark this string as &amp;quot;must be translated&amp;quot;, and to make sure the translated version of the string will be available on client side.&lt;br /&gt;
&lt;br /&gt;
In general, you use clienttranslate:&lt;br /&gt;
* In your &#039;&#039;&#039;states.inc.php&#039;&#039;&#039;, for the fields &amp;quot;description&amp;quot; and &amp;quot;descriptionmyturn&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
      &amp;quot;description&amp;quot; =&amp;gt; clienttranslate(&#039;${card_name}: ${actplayer} must discard 4 identical energies&#039;),&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* In &#039;&#039;&#039;material.inc.php&#039;&#039;&#039;, when defining text for game materials that must be displayed on the client side.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$this-&amp;gt;card_types = array(&lt;br /&gt;
&lt;br /&gt;
     1 =&amp;gt; array(&lt;br /&gt;
        &#039;name&#039; =&amp;gt; clienttranslate(&#039;Amulet of Air&#039;), // Thus, we can use &amp;quot;_( card_name )&amp;quot; on Javascript side.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* When sending a notification with &#039;&#039;notifyAllPlayers&#039;&#039; or &#039;&#039;notifyPlayer&#039;&#039;, in the game log string and all game log arguments that need a translation.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
     // A game log string with no argument:&lt;br /&gt;
     self::notifyAllPlayers( &#039;pickLibraryCards&#039;, clienttranslate(&#039;Everyone draw cards from their library&#039;), [] );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As a consequence there is no point passing variables to this function. E.g.:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    notif=&amp;quot;foo&amp;quot;;&lt;br /&gt;
    self::notifyAllPlayers( &#039;log&#039;, clienttranslate(notif),[]); // BAD&lt;br /&gt;
    &lt;br /&gt;
    notif=clienttranslate(&amp;quot;foo&amp;quot;);&lt;br /&gt;
    self::notifyAllPlayers( &#039;log&#039;, notif,[]); // GOOD&lt;br /&gt;
&lt;br /&gt;
    self::notifyAllPlayers( &#039;log&#039;, clienttranslate(&amp;quot;player gains ${num} gems&amp;quot;),[num=&amp;gt;2]); // BAD it is dynamic string enterpreted by php &lt;br /&gt;
    self::notifyAllPlayers( &#039;log&#039;, clienttranslate(&#039;player gains ${num} gems&#039;),[num=&amp;gt;2]); // GOOD, difference is single quotes&lt;br /&gt;
&lt;br /&gt;
    self::notifyAllPlayers( &#039;log&#039;, clienttranslate(&amp;quot;player gains &amp;quot;.${num}.&amp;quot; gems&amp;quot;),[num=&amp;gt;2]); // BAD concatenation &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Translating arguments is a little bit more complex. This uses the &#039;&#039;&#039;i18n&#039;&#039;&#039; special argument as below:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 // In the following example, we translate the game log itself, but also the &amp;quot;card_name&amp;quot; argument:&lt;br /&gt;
&lt;br /&gt;
 self::notifyAllPlayers( &#039;winPoints&#039;, clienttranslate(&#039;${card_name}: ${player_name} gains ${points} point(s)&#039;), array(&lt;br /&gt;
                &#039;i18n&#039; =&amp;gt; array( &#039;card_name&#039; ),     // &amp;lt;===== We specify here that &amp;quot;card_name&amp;quot; argument must be translated&lt;br /&gt;
                &#039;player_id&#039; =&amp;gt; $player_id,&lt;br /&gt;
                &#039;player_name&#039; =&amp;gt; self::getActivePlayerName(),&lt;br /&gt;
                &#039;points&#039; =&amp;gt; $points,&lt;br /&gt;
                &#039;card_name&#039; =&amp;gt; $this-&amp;gt;card_types[8][&#039;name&#039;] // &amp;lt;==== Here, we provide original English string.&lt;br /&gt;
            ) ); &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To ensure the translation of the i18n argument will be made, clienttranslate must have been used somewhere, for instance:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$this-&amp;gt;card_types = array(&lt;br /&gt;
...&lt;br /&gt;
     8 =&amp;gt; array(&lt;br /&gt;
        &#039;name&#039; =&amp;gt; clienttranslate(&amp;quot;Amulet of Fire&amp;quot;),&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Pay attention when using the &#039;&#039;&#039;i18n&#039;&#039;&#039; argument when translating arguments for the client: do NOT use same argument for both translations AND key codes for client-side actions (like using &#039;card_name&#039; to move it on the player board as described in the example). It&#039;s pretty obvious in the example, but it can be very tricky when translation is made at the end of the development (which is often the case). Use explicit argument names like &#039;card_name_translated&#039; by example.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;WARNING:&#039;&#039;&#039; you should NEVER use concatenation with &#039;&#039;clienttranslate&#039;&#039;, as it would result in a different string to translate at runtime than the one retrieved statically in the translation system, and so translation would not be applied. If you need to compose a string, use substitution and the i18n parameter (but you also have to pay attention not to compose sentences in a way that is dependent upon the English language specific syntax, or it may be impossible to translate correctly in another language: sometimes, you need multiple full sentences rather than relying on substitution).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Method _ (underscore) ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;self::_( &amp;quot;my string to translate&amp;quot; ):&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This function returns a string translated in the language of CURRENT user (i.e. player who send the request to the server) (be careful, this is NOT the active player).&lt;br /&gt;
&lt;br /&gt;
This can be used like self::_(&#039;bla&#039;) or this-&amp;gt;(&#039;bla&#039;). You cannot use static underscore function _(&#039;bla&#039;) in php, it is not the same, it will not translate strings from your game.&lt;br /&gt;
&lt;br /&gt;
The returned string will be surrounded by HTML tags, so you cannot use it in places where pure text is required or your string already has another html markup.&lt;br /&gt;
&lt;br /&gt;
Most of the time, you don&#039;t need to translate strings on server side, except on the following situations:&lt;br /&gt;
* Throwing user exceptions&lt;br /&gt;
* Creating the labels for the game interface used in your template&lt;br /&gt;
* Rarely, in your material.inc.php, if for example you need to use some string elements in your exceptions&lt;br /&gt;
* Rarely, in your &amp;quot;getAllDatas&amp;quot; PHP method, as the data return by this method is used only by current user&lt;br /&gt;
&lt;br /&gt;
Imporant! This function does two things:&lt;br /&gt;
* Mark string for translation&lt;br /&gt;
* Translates in runtime&lt;br /&gt;
As a consequence you absolutely cannot have $var in there! Or string concatenations.&lt;br /&gt;
I.e.&lt;br /&gt;
  $food=self::_(&amp;quot;Banana&amp;quot;);// good&lt;br /&gt;
  self::_(&amp;quot;User gives $food to a cat&amp;quot;); // bad&lt;br /&gt;
For the translator we will have two strings &amp;quot;Banana&amp;quot; and &amp;quot;User gives $food to a cat&amp;quot;, but in runtime we will be&lt;br /&gt;
&amp;quot;Banana&amp;quot; and &amp;quot;User gives Banana to a cat&amp;quot; and second string would not match anything. And this is as bad&lt;br /&gt;
  self::_(&amp;quot;User gives &amp;quot;.$food.&amp;quot; to a cat&amp;quot;);// bad&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Throwing an exception because the player did a forbidden move ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// This will display a translatable red message to the player that just did some wrong action:&lt;br /&gt;
throw new BgaUserException( self::_(&#039;You must choose 3 cards&#039;) );&lt;br /&gt;
&lt;br /&gt;
// ... notice the use of BgaUserException that signals that this exception is &amp;quot;expected&amp;quot;. In theory, all exception that are expected should be translated.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Creating labels ====&lt;br /&gt;
&lt;br /&gt;
In &amp;quot;yourgame.view.php&amp;quot;, when creating the labels for the game interface used in your template (.tpl) file.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$this-&amp;gt;tpl[&#039;CARDS_FOR_YEAR_2&#039;] = self::_(&amp;quot;Your cards for year II&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Nota bene:&#039;&#039;&#039; it is recommended to set translated text in your interface client side rather than use template variables and server translation, so that translation works natively in replays (that don&#039;t have server side translations). For simple strings, the framework will handle moving the translation client side, but for more complex strings it may not work. In particular, you should not use server side translation for templates with substitution variables (or use the specific function &amp;quot;gameview_str_replace( $search, $replace, $string )&amp;quot; if not possible otherwise or for old code compatibility). Also, you should never use a &amp;quot;to_translate&amp;quot; class in your .tpl as it is used internally by the framework.&lt;br /&gt;
&lt;br /&gt;
Example with view.php:&lt;br /&gt;
in .tpl:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  &amp;lt;div id=&amp;quot;empire_title_{COLOR}&amp;quot; class=&amp;quot;side_title color_{COLOR}&amp;quot;&amp;gt;{EMPIRE_LABEL}&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
in view.php:&lt;br /&gt;
        $this-&amp;gt;page-&amp;gt;insert_block(&amp;quot;player_board&amp;quot;, array (&amp;quot;COLOR&amp;quot; =&amp;gt; $color,&amp;quot;PLAYER_NAME&amp;quot; =&amp;gt; $name,&amp;quot;PLAYER_NO&amp;quot; =&amp;gt; $no,&lt;br /&gt;
                &amp;quot;PLAYER_ID&amp;quot; =&amp;gt; $player_id, &amp;quot;CLASSES&amp;quot; =&amp;gt; $own?&amp;quot;own&amp;quot;:&amp;quot;&amp;quot;, &lt;br /&gt;
                &amp;quot;EMPIRE_LABEL&amp;quot; =&amp;gt; self::raw(gameview_str_replace(&#039;${player_name}&#039;, $name, self::_(&#039;${player_name}\&#039;s EMPIRE&#039;)))&lt;br /&gt;
              ));&lt;br /&gt;
Example with client side:&lt;br /&gt;
in .tpl:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  &amp;lt;div id=&amp;quot;empire_title_{COLOR}&amp;quot; class=&amp;quot;side_title color_{COLOR}&amp;quot;&amp;gt;Stub&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
in .js:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  for (var player_id in this.gamedatas.players) {&lt;br /&gt;
      var player_color = this.gamedatas.players[player_id].color;&lt;br /&gt;
      var player_name = this.gamedatas.players[player_id].name;&lt;br /&gt;
      $(&#039;empire_title_&#039;+player_color).innerHTML=this.format_string_recursive(_(&amp;quot;${player_name}&#039;s EMPIRE&amp;quot;), {player_name: player_name});&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Translating strings in material file ====&lt;br /&gt;
&lt;br /&gt;
Rarely, in your material.inc.php, if for example you need to use some string elements in your exceptions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// In material.inc.php, $this-&amp;gt;energies[n][&#039;nametr&#039;] has been created with the self::_() method. Now we can do this:&lt;br /&gt;
throw new BgaUserException( self::_(&amp;quot;To execute this action you need more: &amp;quot;).&#039; &#039;.$this-&amp;gt;energies[$resource_id][&#039;nametr&#039;] );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: you could also do this, so you don&#039;t need to pollute your material file&lt;br /&gt;
   throw new BgaUserException( self::_(&amp;quot;To execute this action you need more: &amp;quot;).&#039; &#039;.self::_($this-&amp;gt;energies[$resource_id][&#039;name&#039;]) );&lt;br /&gt;
&lt;br /&gt;
where $this-&amp;gt;energies[$resource_id][&#039;name&#039;] were marked in material file using regular clienttranslate function&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  $this-&amp;gt;energies = [&lt;br /&gt;
      22 =&amp;gt; [&lt;br /&gt;
          &#039;name&#039; =&amp;gt; clienttranslate(&#039;Sun&#039;)&lt;br /&gt;
          ...&lt;br /&gt;
      ]&lt;br /&gt;
  ];&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Strings in getAllDatas ====&lt;br /&gt;
&lt;br /&gt;
Rarely, in your &amp;quot;getAllDatas&amp;quot; PHP method, as the data return by this method is used only by current user.&lt;br /&gt;
&lt;br /&gt;
Note: not sure why would you send strings from the server in this case, as same can be achieved on the client usually.&lt;br /&gt;
&lt;br /&gt;
=== Function totranslate ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;totranslate( &amp;quot;my string to translate&amp;quot; ):&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This function works exactly like &#039;clienttranslate&#039;, except it tells BGA that the string is not needed on client side.&lt;br /&gt;
&lt;br /&gt;
You should not use this function, except on the following cases:&lt;br /&gt;
* Statistics name in stats.inc.php&lt;br /&gt;
* Option names and option values name in gameoptions.inc.php&lt;br /&gt;
&lt;br /&gt;
== Top Secret Undocumented Features ==&lt;br /&gt;
&lt;br /&gt;
If your string contains the clause &#039;$${value}&#039; (such as &#039;You gain $${value}.&#039;) then the translation system seems to move the position of the $ to a localized location (eg $5 in English but 5$ in French). This only seems to occur when using the argument &#039;value&#039;.&lt;br /&gt;
&lt;br /&gt;
In JavaScript, you can get the current user&#039;s language by retrieving the translation for the special string &amp;quot;$locale&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
    var lang = _(&#039;$locale&#039;); // en, fr, etc.&lt;br /&gt;
&lt;br /&gt;
== On server side - advanced (PHP) ==&lt;br /&gt;
&lt;br /&gt;
If you want to use translation system in your custom static modules, you will first need to expose the _() function :&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class mygame extends Table {&lt;br /&gt;
  // Exposing protected method translation&lt;br /&gt;
  public static function totranslate($text) {&lt;br /&gt;
    return self::_($text);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then you&#039;ll be able to use this directly in other modules by doing&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
throw new BgaUserException(mygame::totranslate(&amp;quot;Translated error from my awesome module file&amp;quot;));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Notice how the &amp;quot;totranslate&amp;quot; is also used by the static analysis to detect your string. So the following will not work :&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$msg = &amp;quot;Translated error from my awesome module file&amp;quot;;&lt;br /&gt;
throw new BgaUserException(mygame::totranslate($msg));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Analyze your project ==&lt;br /&gt;
&lt;br /&gt;
It looks super complex but there is help!&lt;br /&gt;
On studio control panel you can find a button &amp;quot;Check project&amp;quot; - it runs bunch of static analysis on your project including scanning for bad translations and missing translations.&lt;br /&gt;
It also will extact all you translation keys as translator will see them so you can double check - and run spell checker on them.&lt;br /&gt;
&lt;br /&gt;
== Other Useful Links ==&lt;br /&gt;
&lt;br /&gt;
* BLOG post about translations https://bga-devs.github.io/blog/posts/translations-summary/&lt;br /&gt;
&lt;br /&gt;
[[Category:Studio]]&lt;/div&gt;</summary>
		<author><name>Archduke</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=File:Title_guidelines.png&amp;diff=13421</id>
		<title>File:Title guidelines.png</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=File:Title_guidelines.png&amp;diff=13421"/>
		<updated>2022-06-02T10:17:39Z</updated>

		<summary type="html">&lt;p&gt;Archduke: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Archduke</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Template:Studio_Framework_Navigation&amp;diff=12993</id>
		<title>Template:Studio Framework Navigation</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Template:Studio_Framework_Navigation&amp;diff=12993"/>
		<updated>2022-05-04T10:45:29Z</updated>

		<summary type="html">&lt;p&gt;Archduke: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;!-- Do not use heading tags, or else these sidebar headings appear in the page TOCs --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;studio-framework-navigation&amp;quot; style=&amp;quot;float: right; width: 300px; border: solid #000 1px; padding: 1em; margin-left: 1em; background: #fff;&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-weight:bold;font-size:1.2em;margin-top:0.3em;line-height:1.6;padding-top:0.5em;&amp;quot;&amp;gt;&amp;lt;center&amp;gt;&#039;&#039;&#039;Game File Reference&#039;&#039;&#039;&amp;lt;/center&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-weight:bold;font-size:1.2em;margin-top:0.3em;line-height:1.6;padding-top:0.5em;&amp;quot;&amp;gt;&amp;lt;center&amp;gt;&#039;&#039;&#039;[[Studio file reference|Overview]]&#039;&#039;&#039;&amp;lt;/center&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* [[Game database model: dbmodel.sql|&amp;lt;b&amp;gt;dbmodel.sql&amp;lt;/b&amp;gt;]] - database model&lt;br /&gt;
* [[Game meta-information: gameinfos.inc.php|&amp;lt;b&amp;gt;gameinfos.inc.php&amp;lt;/b&amp;gt;]] - meta-information&lt;br /&gt;
* [[Game options and preferences: gameoptions.inc.php|&amp;lt;b&amp;gt;gameoptions.inc.php&amp;lt;/b&amp;gt;]] - game options &amp;amp; user preferences&lt;br /&gt;
* [[Game art: img directory|&amp;lt;b&amp;gt;img/&amp;lt;/b&amp;gt;]] - game art&lt;br /&gt;
* [[Game_metadata_manager|&amp;lt;b&amp;gt;Game Metadata Manager&amp;lt;/b&amp;gt;]] - tags and metadata media&lt;br /&gt;
* [[Game material description: material.inc.php|&amp;lt;b&amp;gt;material.inc.php&amp;lt;/b&amp;gt;]] - static data&lt;br /&gt;
* &amp;lt;b&amp;gt;misc/&amp;lt;/b&amp;gt; - studio-only storage&lt;br /&gt;
* &amp;lt;b&amp;gt;modules/&amp;lt;/b&amp;gt; - additional game code&lt;br /&gt;
* [[Your game state machine: states.inc.php|&amp;lt;b&amp;gt;states.inc.php&amp;lt;/b&amp;gt;]] - state machine&lt;br /&gt;
* [[Game statistics: stats.inc.php|&amp;lt;b&amp;gt;stats.inc.php&amp;lt;/b&amp;gt;]] - statistics&lt;br /&gt;
* [[Players actions: yourgamename.action.php|X.&amp;lt;b&amp;gt;action.php&amp;lt;/b&amp;gt;]] - player actions&lt;br /&gt;
* [[Game interface stylesheet: yourgamename.css|X&amp;lt;b&amp;gt;.css&amp;lt;/b&amp;gt;]] - interface stylesheet&lt;br /&gt;
* [[Main game logic: yourgamename.game.php|X.&amp;lt;b&amp;gt;game.php&amp;lt;/b&amp;gt;]] - main logic&lt;br /&gt;
* [[Game interface logic: yourgamename.js|X.&amp;lt;b&amp;gt;js&amp;lt;/b&amp;gt;]] - interface logic&lt;br /&gt;
* [[Game layout: view and template: yourgamename.view.php and yourgamename_yourgamename.tpl|X.&amp;lt;b&amp;gt;view.php&amp;lt;/b&amp;gt;]] - dynamic game layout&lt;br /&gt;
* [[Game layout: view and template: yourgamename.view.php and yourgamename_yourgamename.tpl|X_X.&amp;lt;b&amp;gt;tpl&amp;lt;/b&amp;gt;]] - static game layout&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
-----&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-weight:bold;font-size:1.2em;margin-top:0.3em;line-height:1.6;padding-top:0.5em;&amp;quot;&amp;gt;&amp;lt;center&amp;gt;&#039;&#039;&#039;Useful Components&#039;&#039;&#039;&amp;lt;/center&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Official&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* [[Deck]]: a PHP component to manage cards (deck, hands, picking cards, moving cards, shuffle deck, ...).&lt;br /&gt;
* [[Draggable]]: a JS component to manage drag&#039;n&#039;drop actions.&lt;br /&gt;
* [[Counter]]: a JS component to manage a counter that can increase/decrease (ex: player&#039;s score).&lt;br /&gt;
* [[ExpandableSection]]: a JS component to manage a rectangular block of HTML than can be displayed/hidden.&lt;br /&gt;
* [[Scrollmap]]: a JS component to manage a scrollable game area (useful when the game area can be infinite. Examples:  Saboteur or Takenoko games).&lt;br /&gt;
* [[Stock]]: a JS component to manage and display a set of game elements displayed at a position.&lt;br /&gt;
* [[Zone]]: a JS component to manage a zone of the board where several game elements can come and leave, but should be well displayed together (See for example: token&#039;s places at Can&#039;t Stop).&lt;br /&gt;
&lt;br /&gt;
Undocumented component (if somebody knows please help with docs)&lt;br /&gt;
* [[Wrapper]]: a JS component to wrap a  &amp;amp;lt;div&amp;amp;gt; element around its child, even if these elements are absolute positioned.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Unofficial&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* [[BGA Code Sharing]] - Shared resources, projects on git hub, common code, other links&lt;br /&gt;
* [[BGA Studio Cookbook]] - Tips and instructions on using API&#039;s, libraries and frameworks&lt;br /&gt;
* [[Some usual board game elements image ressources]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
-----&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-weight:bold;font-size:1.2em;margin-top:0.3em;line-height:1.6;padding-top:0.5em;&amp;quot;&amp;gt;&amp;lt;center&amp;gt;&#039;&#039;&#039;Game Development Process&#039;&#039;&#039;&amp;lt;/center&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* [[First steps with BGA Studio]]&lt;br /&gt;
* [[Create a game in BGA Studio: Complete Walkthrough]]&lt;br /&gt;
* [[Tutorial reversi]] &lt;br /&gt;
* [[Tutorial gomoku]] &lt;br /&gt;
* [[Tutorial hearts]]&lt;br /&gt;
* [[BGA Studio Guidelines]]&lt;br /&gt;
* [[BGA game Lifecycle]]&lt;br /&gt;
* [[Pre-release checklist]]&lt;br /&gt;
* [[Post-release phase]]&lt;br /&gt;
* [[Help|Player Resources]] - add player help/rules to your game page&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
-----&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-weight:bold;font-size:1.2em;margin-top:0.3em;line-height:1.6;padding-top:0.5em;&amp;quot;&amp;gt;&amp;lt;center&amp;gt;&#039;&#039;&#039;Guides for Common Topics&#039;&#039;&#039;&amp;lt;/center&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* [[Translations]] - make your game translatable&lt;br /&gt;
* [[Game replay|Game Replay]]&lt;br /&gt;
* [[Your game mobile version|Mobile Users]]&lt;br /&gt;
* [[3D]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
-----&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-weight:bold;font-size:1.2em;margin-top:0.3em;line-height:1.6;padding-top:0.5em;&amp;quot;&amp;gt;&amp;lt;center&amp;gt;&#039;&#039;&#039;Miscellaneous Resources&#039;&#039;&#039;&amp;lt;/center&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* [[Studio FAQ]]&lt;br /&gt;
* [[Tools and tips of BGA Studio]] - Tips and instructions on setting up development environment&lt;br /&gt;
* [[Studio logs]] - Instructions for log access&lt;br /&gt;
* [[Practical debugging]] - Tips focused on debugging&lt;br /&gt;
* [[Troubleshooting]] - Most common &amp;quot;I am really stuck&amp;quot; situations&lt;br /&gt;
* [https://studio.boardgamearena.com/bugs Studio Bugs] - Reports against Studio itself (not BGA!)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Archduke</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Template:Studio_Framework_Navigation&amp;diff=12992</id>
		<title>Template:Studio Framework Navigation</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Template:Studio_Framework_Navigation&amp;diff=12992"/>
		<updated>2022-05-04T10:45:12Z</updated>

		<summary type="html">&lt;p&gt;Archduke: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;!-- Do not use heading tags, or else these sidebar headings appear in the page TOCs --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;studio-framework-navigation&amp;quot; style=&amp;quot;float: right; width: 300px; border: solid #000 1px; padding: 1em; margin-left: 1em; background: #fff;&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-weight:bold;font-size:1.2em;margin-top:0.3em;line-height:1.6;padding-top:0.5em;&amp;quot;&amp;gt;&amp;lt;center&amp;gt;&#039;&#039;&#039;Game File Reference&#039;&#039;&#039;&amp;lt;/center&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-weight:bold;font-size:1.2em;margin-top:0.3em;line-height:1.6;padding-top:0.5em;&amp;quot;&amp;gt;&amp;lt;center&amp;gt;&#039;&#039;&#039;[[Studio file reference|Overview]]&#039;&#039;&#039;&amp;lt;/center&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* [[Game database model: dbmodel.sql|&amp;lt;b&amp;gt;dbmodel.sql&amp;lt;/b&amp;gt;]] - database model&lt;br /&gt;
* [[Game meta-information: gameinfos.inc.php|&amp;lt;b&amp;gt;gameinfos.inc.php&amp;lt;/b&amp;gt;]] - meta-information&lt;br /&gt;
* [[Game options and preferences: gameoptions.inc.php|&amp;lt;b&amp;gt;gameoptions.inc.php&amp;lt;/b&amp;gt;]] - game options &amp;amp; user preferences&lt;br /&gt;
* [[Game art: img directory|&amp;lt;b&amp;gt;img/&amp;lt;/b&amp;gt;]] - game art&lt;br /&gt;
* [[Game_metadata_manager|Game Metadata Manager]] - tags and metadata media&lt;br /&gt;
* [[Game material description: material.inc.php|&amp;lt;b&amp;gt;material.inc.php&amp;lt;/b&amp;gt;]] - static data&lt;br /&gt;
* &amp;lt;b&amp;gt;misc/&amp;lt;/b&amp;gt; - studio-only storage&lt;br /&gt;
* &amp;lt;b&amp;gt;modules/&amp;lt;/b&amp;gt; - additional game code&lt;br /&gt;
* [[Your game state machine: states.inc.php|&amp;lt;b&amp;gt;states.inc.php&amp;lt;/b&amp;gt;]] - state machine&lt;br /&gt;
* [[Game statistics: stats.inc.php|&amp;lt;b&amp;gt;stats.inc.php&amp;lt;/b&amp;gt;]] - statistics&lt;br /&gt;
* [[Players actions: yourgamename.action.php|X.&amp;lt;b&amp;gt;action.php&amp;lt;/b&amp;gt;]] - player actions&lt;br /&gt;
* [[Game interface stylesheet: yourgamename.css|X&amp;lt;b&amp;gt;.css&amp;lt;/b&amp;gt;]] - interface stylesheet&lt;br /&gt;
* [[Main game logic: yourgamename.game.php|X.&amp;lt;b&amp;gt;game.php&amp;lt;/b&amp;gt;]] - main logic&lt;br /&gt;
* [[Game interface logic: yourgamename.js|X.&amp;lt;b&amp;gt;js&amp;lt;/b&amp;gt;]] - interface logic&lt;br /&gt;
* [[Game layout: view and template: yourgamename.view.php and yourgamename_yourgamename.tpl|X.&amp;lt;b&amp;gt;view.php&amp;lt;/b&amp;gt;]] - dynamic game layout&lt;br /&gt;
* [[Game layout: view and template: yourgamename.view.php and yourgamename_yourgamename.tpl|X_X.&amp;lt;b&amp;gt;tpl&amp;lt;/b&amp;gt;]] - static game layout&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
-----&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-weight:bold;font-size:1.2em;margin-top:0.3em;line-height:1.6;padding-top:0.5em;&amp;quot;&amp;gt;&amp;lt;center&amp;gt;&#039;&#039;&#039;Useful Components&#039;&#039;&#039;&amp;lt;/center&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Official&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* [[Deck]]: a PHP component to manage cards (deck, hands, picking cards, moving cards, shuffle deck, ...).&lt;br /&gt;
* [[Draggable]]: a JS component to manage drag&#039;n&#039;drop actions.&lt;br /&gt;
* [[Counter]]: a JS component to manage a counter that can increase/decrease (ex: player&#039;s score).&lt;br /&gt;
* [[ExpandableSection]]: a JS component to manage a rectangular block of HTML than can be displayed/hidden.&lt;br /&gt;
* [[Scrollmap]]: a JS component to manage a scrollable game area (useful when the game area can be infinite. Examples:  Saboteur or Takenoko games).&lt;br /&gt;
* [[Stock]]: a JS component to manage and display a set of game elements displayed at a position.&lt;br /&gt;
* [[Zone]]: a JS component to manage a zone of the board where several game elements can come and leave, but should be well displayed together (See for example: token&#039;s places at Can&#039;t Stop).&lt;br /&gt;
&lt;br /&gt;
Undocumented component (if somebody knows please help with docs)&lt;br /&gt;
* [[Wrapper]]: a JS component to wrap a  &amp;amp;lt;div&amp;amp;gt; element around its child, even if these elements are absolute positioned.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Unofficial&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* [[BGA Code Sharing]] - Shared resources, projects on git hub, common code, other links&lt;br /&gt;
* [[BGA Studio Cookbook]] - Tips and instructions on using API&#039;s, libraries and frameworks&lt;br /&gt;
* [[Some usual board game elements image ressources]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
-----&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-weight:bold;font-size:1.2em;margin-top:0.3em;line-height:1.6;padding-top:0.5em;&amp;quot;&amp;gt;&amp;lt;center&amp;gt;&#039;&#039;&#039;Game Development Process&#039;&#039;&#039;&amp;lt;/center&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* [[First steps with BGA Studio]]&lt;br /&gt;
* [[Create a game in BGA Studio: Complete Walkthrough]]&lt;br /&gt;
* [[Tutorial reversi]] &lt;br /&gt;
* [[Tutorial gomoku]] &lt;br /&gt;
* [[Tutorial hearts]]&lt;br /&gt;
* [[BGA Studio Guidelines]]&lt;br /&gt;
* [[BGA game Lifecycle]]&lt;br /&gt;
* [[Pre-release checklist]]&lt;br /&gt;
* [[Post-release phase]]&lt;br /&gt;
* [[Help|Player Resources]] - add player help/rules to your game page&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
-----&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-weight:bold;font-size:1.2em;margin-top:0.3em;line-height:1.6;padding-top:0.5em;&amp;quot;&amp;gt;&amp;lt;center&amp;gt;&#039;&#039;&#039;Guides for Common Topics&#039;&#039;&#039;&amp;lt;/center&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* [[Translations]] - make your game translatable&lt;br /&gt;
* [[Game replay|Game Replay]]&lt;br /&gt;
* [[Your game mobile version|Mobile Users]]&lt;br /&gt;
* [[3D]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
-----&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-weight:bold;font-size:1.2em;margin-top:0.3em;line-height:1.6;padding-top:0.5em;&amp;quot;&amp;gt;&amp;lt;center&amp;gt;&#039;&#039;&#039;Miscellaneous Resources&#039;&#039;&#039;&amp;lt;/center&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* [[Studio FAQ]]&lt;br /&gt;
* [[Tools and tips of BGA Studio]] - Tips and instructions on setting up development environment&lt;br /&gt;
* [[Studio logs]] - Instructions for log access&lt;br /&gt;
* [[Practical debugging]] - Tips focused on debugging&lt;br /&gt;
* [[Troubleshooting]] - Most common &amp;quot;I am really stuck&amp;quot; situations&lt;br /&gt;
* [https://studio.boardgamearena.com/bugs Studio Bugs] - Reports against Studio itself (not BGA!)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Archduke</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=File:Game_Metadata_Manager_Icon.png&amp;diff=12987</id>
		<title>File:Game Metadata Manager Icon.png</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=File:Game_Metadata_Manager_Icon.png&amp;diff=12987"/>
		<updated>2022-05-03T15:24:34Z</updated>

		<summary type="html">&lt;p&gt;Archduke: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Archduke</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=File:Carcassonne_Banner.jpg&amp;diff=12982</id>
		<title>File:Carcassonne Banner.jpg</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=File:Carcassonne_Banner.jpg&amp;diff=12982"/>
		<updated>2022-05-03T13:53:34Z</updated>

		<summary type="html">&lt;p&gt;Archduke: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Archduke</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=File:Carcassonne_Icon.png&amp;diff=12981</id>
		<title>File:Carcassonne Icon.png</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=File:Carcassonne_Icon.png&amp;diff=12981"/>
		<updated>2022-05-03T13:52:56Z</updated>

		<summary type="html">&lt;p&gt;Archduke: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Archduke</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=File:Carcassonne_Box.png&amp;diff=12980</id>
		<title>File:Carcassonne Box.png</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=File:Carcassonne_Box.png&amp;diff=12980"/>
		<updated>2022-05-03T13:51:53Z</updated>

		<summary type="html">&lt;p&gt;Archduke: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Archduke</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=File:Carcassonne_Title.png&amp;diff=12978</id>
		<title>File:Carcassonne Title.png</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=File:Carcassonne_Title.png&amp;diff=12978"/>
		<updated>2022-05-03T13:49:04Z</updated>

		<summary type="html">&lt;p&gt;Archduke: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Archduke</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Template:Studio_Framework_Navigation&amp;diff=12966</id>
		<title>Template:Studio Framework Navigation</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Template:Studio_Framework_Navigation&amp;diff=12966"/>
		<updated>2022-05-03T10:17:02Z</updated>

		<summary type="html">&lt;p&gt;Archduke: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;!-- Do not use heading tags, or else these sidebar headings appear in the page TOCs --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;studio-framework-navigation&amp;quot; style=&amp;quot;float: right; width: 300px; border: solid #000 1px; padding: 1em; margin-left: 1em; background: #fff;&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-weight:bold;font-size:1.2em;margin-top:0.3em;line-height:1.6;padding-top:0.5em;&amp;quot;&amp;gt;&amp;lt;center&amp;gt;&#039;&#039;&#039;Game File Reference&#039;&#039;&#039;&amp;lt;/center&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-weight:bold;font-size:1.2em;margin-top:0.3em;line-height:1.6;padding-top:0.5em;&amp;quot;&amp;gt;&amp;lt;center&amp;gt;&#039;&#039;&#039;[[Studio file reference|Overview]]&#039;&#039;&#039;&amp;lt;/center&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* [[Game database model: dbmodel.sql|&amp;lt;b&amp;gt;dbmodel.sql&amp;lt;/b&amp;gt;]] - database model&lt;br /&gt;
* [[Game meta-information: gameinfos.inc.php|&amp;lt;b&amp;gt;gameinfos.inc.php&amp;lt;/b&amp;gt;]] - meta-information&lt;br /&gt;
* [[Game options and preferences: gameoptions.inc.php|&amp;lt;b&amp;gt;gameoptions.inc.php&amp;lt;/b&amp;gt;]] - game options &amp;amp; user preferences&lt;br /&gt;
* [[Game art: img directory|&amp;lt;b&amp;gt;img/&amp;lt;/b&amp;gt;]] - game art&lt;br /&gt;
* [[Game material description: material.inc.php|&amp;lt;b&amp;gt;material.inc.php&amp;lt;/b&amp;gt;]] - static data&lt;br /&gt;
* &amp;lt;b&amp;gt;misc/&amp;lt;/b&amp;gt; - studio-only storage&lt;br /&gt;
* &amp;lt;b&amp;gt;modules/&amp;lt;/b&amp;gt; - additional game code&lt;br /&gt;
* [[Your game state machine: states.inc.php|&amp;lt;b&amp;gt;states.inc.php&amp;lt;/b&amp;gt;]] - state machine&lt;br /&gt;
* [[Game statistics: stats.inc.php|&amp;lt;b&amp;gt;stats.inc.php&amp;lt;/b&amp;gt;]] - statistics&lt;br /&gt;
* [[Players actions: yourgamename.action.php|X.&amp;lt;b&amp;gt;action.php&amp;lt;/b&amp;gt;]] - player actions&lt;br /&gt;
* [[Game interface stylesheet: yourgamename.css|X&amp;lt;b&amp;gt;.css&amp;lt;/b&amp;gt;]] - interface stylesheet&lt;br /&gt;
* [[Main game logic: yourgamename.game.php|X.&amp;lt;b&amp;gt;game.php&amp;lt;/b&amp;gt;]] - main logic&lt;br /&gt;
* [[Game interface logic: yourgamename.js|X.&amp;lt;b&amp;gt;js&amp;lt;/b&amp;gt;]] - interface logic&lt;br /&gt;
* [[Game layout: view and template: yourgamename.view.php and yourgamename_yourgamename.tpl|X.&amp;lt;b&amp;gt;view.php&amp;lt;/b&amp;gt;]] - dynamic game layout&lt;br /&gt;
* [[Game layout: view and template: yourgamename.view.php and yourgamename_yourgamename.tpl|X_X.&amp;lt;b&amp;gt;tpl&amp;lt;/b&amp;gt;]] - static game layout&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
-----&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-weight:bold;font-size:1.2em;margin-top:0.3em;line-height:1.6;padding-top:0.5em;&amp;quot;&amp;gt;&amp;lt;center&amp;gt;&#039;&#039;&#039;Useful Components&#039;&#039;&#039;&amp;lt;/center&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Official&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* [[Deck]]: a PHP component to manage cards (deck, hands, picking cards, moving cards, shuffle deck, ...).&lt;br /&gt;
* [[Draggable]]: a JS component to manage drag&#039;n&#039;drop actions.&lt;br /&gt;
* [[Counter]]: a JS component to manage a counter that can increase/decrease (ex: player&#039;s score).&lt;br /&gt;
* [[ExpandableSection]]: a JS component to manage a rectangular block of HTML than can be displayed/hidden.&lt;br /&gt;
* [[Scrollmap]]: a JS component to manage a scrollable game area (useful when the game area can be infinite. Examples:  Saboteur or Takenoko games).&lt;br /&gt;
* [[Stock]]: a JS component to manage and display a set of game elements displayed at a position.&lt;br /&gt;
* [[Zone]]: a JS component to manage a zone of the board where several game elements can come and leave, but should be well displayed together (See for example: token&#039;s places at Can&#039;t Stop).&lt;br /&gt;
&lt;br /&gt;
Undocumented component (if somebody knows please help with docs)&lt;br /&gt;
* [[Wrapper]]: a JS component to wrap a  &amp;amp;lt;div&amp;amp;gt; element around its child, even if these elements are absolute positioned.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Unofficial&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* [[BGA Code Sharing]] - Shared resources, projects on git hub, common code, other links&lt;br /&gt;
* [[BGA Studio Cookbook]] - Tips and instructions on using API&#039;s, libraries and frameworks&lt;br /&gt;
* [[Some usual board game elements image ressources]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
-----&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-weight:bold;font-size:1.2em;margin-top:0.3em;line-height:1.6;padding-top:0.5em;&amp;quot;&amp;gt;&amp;lt;center&amp;gt;&#039;&#039;&#039;Game Development Process&#039;&#039;&#039;&amp;lt;/center&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* [[First steps with BGA Studio]]&lt;br /&gt;
* [[Create a game in BGA Studio: Complete Walkthrough]]&lt;br /&gt;
* [[Tutorial reversi]] &lt;br /&gt;
* [[Tutorial gomoku]] &lt;br /&gt;
* [[Tutorial hearts]]&lt;br /&gt;
* [[BGA Studio Guidelines]]&lt;br /&gt;
* [[BGA game Lifecycle]]&lt;br /&gt;
* [[Pre-release checklist]]&lt;br /&gt;
* [[Post-release phase]]&lt;br /&gt;
* [[Help|Player Resources]] - add player help/rules to your game page&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
-----&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-weight:bold;font-size:1.2em;margin-top:0.3em;line-height:1.6;padding-top:0.5em;&amp;quot;&amp;gt;&amp;lt;center&amp;gt;&#039;&#039;&#039;Guides for Common Topics&#039;&#039;&#039;&amp;lt;/center&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* [[Translations]] - make your game translatable&lt;br /&gt;
* [[Game replay|Game Replay]]&lt;br /&gt;
* [[Your game mobile version|Mobile Users]]&lt;br /&gt;
* [[3D]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
-----&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-weight:bold;font-size:1.2em;margin-top:0.3em;line-height:1.6;padding-top:0.5em;&amp;quot;&amp;gt;&amp;lt;center&amp;gt;&#039;&#039;&#039;Miscellaneous Resources&#039;&#039;&#039;&amp;lt;/center&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* [[Studio FAQ]]&lt;br /&gt;
* [[Tools and tips of BGA Studio]] - Tips and instructions on setting up development environment&lt;br /&gt;
* [[Studio logs]] - Instructions for log access&lt;br /&gt;
* [[Practical debugging]] - Tips focused on debugging&lt;br /&gt;
* [[Troubleshooting]] - Most common &amp;quot;I am really stuck&amp;quot; situations&lt;br /&gt;
* [https://studio.boardgamearena.com/bugs Studio Bugs] - Reports against Studio itself (not BGA!)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Archduke</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Template:Studio_Framework_Navigation&amp;diff=12965</id>
		<title>Template:Studio Framework Navigation</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Template:Studio_Framework_Navigation&amp;diff=12965"/>
		<updated>2022-05-03T10:16:40Z</updated>

		<summary type="html">&lt;p&gt;Archduke: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;!-- Do not use heading tags, or else these sidebar headings appear in the page TOCs --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;studio-framework-navigation&amp;quot; style=&amp;quot;float: right; width: 300px; border: solid #000 1px; padding: 1em; margin-left: 1em; background: #fff;&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-weight:bold;font-size:1.2em;margin-top:0.3em;line-height:1.6;padding-top:0.5em;&amp;quot;&amp;gt;&amp;lt;center&amp;gt;&#039;&#039;&#039;Game File Reference&#039;&#039;&#039;&amp;lt;/center&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-weight:bold;font-size:1.2em;margin-top:0.3em;line-height:1.6;padding-top:0.5em;&amp;quot;&amp;gt;&amp;lt;center&amp;gt;&#039;&#039;&#039;[[Studio file reference|Overview]]&#039;&#039;&#039;&amp;lt;/center&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* [[Game database model: dbmodel.sql|&amp;lt;b&amp;gt;dbmodel.sql&amp;lt;/b&amp;gt;]] - database model&lt;br /&gt;
* [[Game meta-information: gameinfos.inc.php|&amp;lt;b&amp;gt;gameinfos.inc.php&amp;lt;/b&amp;gt;]] - meta-information&lt;br /&gt;
* [[Game options and preferences: gameoptions.inc.php|&amp;lt;b&amp;gt;gameoptions.inc.php&amp;lt;/b&amp;gt;]] - game options &amp;amp; user preferences&lt;br /&gt;
* [[Game art: img directory|&amp;lt;b&amp;gt;img/&amp;lt;/b&amp;gt;]] - game art&lt;br /&gt;
* [[Game material description: material.inc.php|&amp;lt;b&amp;gt;material.inc.php&amp;lt;/b&amp;gt;]] - static data&lt;br /&gt;
* &amp;lt;b&amp;gt;misc/&amp;lt;/b&amp;gt; - studio-only storage&lt;br /&gt;
* &amp;lt;b&amp;gt;modules/&amp;lt;/b&amp;gt; - additional game code&lt;br /&gt;
* [[Your game state machine: states.inc.php|&amp;lt;b&amp;gt;states.inc.php&amp;lt;/b&amp;gt;]] - state machine&lt;br /&gt;
* [[Game statistics: stats.inc.php|&amp;lt;b&amp;gt;stats.inc.php&amp;lt;/b&amp;gt;]] - statistics&lt;br /&gt;
* [[Players actions: yourgamename.action.php|X.&amp;lt;b&amp;gt;action.php&amp;lt;/b&amp;gt;]] - player actions&lt;br /&gt;
* [[Game interface stylesheet: yourgamename.css|X&amp;lt;b&amp;gt;.css&amp;lt;/b&amp;gt;]] - interface stylesheet&lt;br /&gt;
* [[Main game logic: yourgamename.game.php|X.&amp;lt;b&amp;gt;game.php&amp;lt;/b&amp;gt;]] - main logic&lt;br /&gt;
* [[Game interface logic: yourgamename.js|X.&amp;lt;b&amp;gt;js&amp;lt;/b&amp;gt;]] - interface logic&lt;br /&gt;
* [[Game layout: view and template: yourgamename.view.php and yourgamename_yourgamename.tpl|X.&amp;lt;b&amp;gt;view.php&amp;lt;/b&amp;gt;]] - dynamic game layout&lt;br /&gt;
* [[Game layout: view and template: yourgamename.view.php and yourgamename_yourgamename.tpl|X_X.&amp;lt;b&amp;gt;tpl&amp;lt;/b&amp;gt;]] - static game layout&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
-----&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-weight:bold;font-size:1.2em;margin-top:0.3em;line-height:1.6;padding-top:0.5em;&amp;quot;&amp;gt;&amp;lt;center&amp;gt;&#039;&#039;&#039;Useful Components&#039;&#039;&#039;&amp;lt;/center&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Official&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* [[Deck]]: a PHP component to manage cards (deck, hands, picking cards, moving cards, shuffle deck, ...).&lt;br /&gt;
* [[Draggable]]: a JS component to manage drag&#039;n&#039;drop actions.&lt;br /&gt;
* [[Counter]]: a JS component to manage a counter that can increase/decrease (ex: player&#039;s score).&lt;br /&gt;
* [[ExpandableSection]]: a JS component to manage a rectangular block of HTML than can be displayed/hidden.&lt;br /&gt;
* [[Scrollmap]]: a JS component to manage a scrollable game area (useful when the game area can be infinite. Examples:  Saboteur or Takenoko games).&lt;br /&gt;
* [[Stock]]: a JS component to manage and display a set of game elements displayed at a position.&lt;br /&gt;
* [[Zone]]: a JS component to manage a zone of the board where several game elements can come and leave, but should be well displayed together (See for example: token&#039;s places at Can&#039;t Stop).&lt;br /&gt;
&lt;br /&gt;
Undocumented component (if somebody knows please help with docs)&lt;br /&gt;
* [[Wrapper]]: a JS component to wrap a  &amp;amp;lt;div&amp;amp;gt; element around its child, even if these elements are absolute positioned.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Unofficial&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* [[BGA Code Sharing]] - Shared resources, projects on git hub, common code, other links&lt;br /&gt;
* [[BGA Studio Cookbook]] - Tips and instructions on using API&#039;s, libraries and frameworks&lt;br /&gt;
* [[Some usual board game elements image ressources]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
-----&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-weight:bold;font-size:1.2em;margin-top:0.3em;line-height:1.6;padding-top:0.5em;&amp;quot;&amp;gt;&amp;lt;center&amp;gt;&#039;&#039;&#039;Game Development Process&#039;&#039;&#039;&amp;lt;/center&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* [[First steps with BGA Studio]]&lt;br /&gt;
* [[Create a game in BGA Studio: Complete Walkthrough]]&lt;br /&gt;
* [[Tutorial reversi]] &lt;br /&gt;
* [[Tutorial gomoku]] &lt;br /&gt;
* [[Tutorial hearts]]&lt;br /&gt;
* [[BGA Studio Guidelines]]&lt;br /&gt;
* [[BGA game Lifecycle]]&lt;br /&gt;
* [[Pre-release checklist]]&lt;br /&gt;
* [[Post-release phase]]&lt;br /&gt;
* [[Help|Player Resources]] - add player help/rules to your game page&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
-----&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-weight:bold;font-size:1.2em;margin-top:0.3em;line-height:1.6;padding-top:0.5em;&amp;quot;&amp;gt;&amp;lt;center&amp;gt;&#039;&#039;&#039;Guides for Common Topics&#039;&#039;&#039;&amp;lt;/center&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* [[Translations]] - make your game translatable&lt;br /&gt;
* [[Game replay|Game Replay]]&lt;br /&gt;
* [[Your game mobile version|Mobile Users]]&lt;br /&gt;
* [[3D]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
-----&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-weight:bold;font-size:1.2em;margin-top:0.3em;line-height:1.6;padding-top:0.5em;&amp;quot;&amp;gt;&amp;lt;center&amp;gt;&#039;&#039;&#039;Miscellaneous Resources&#039;&#039;&#039;&amp;lt;/center&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* [[Studio FAQ]]&lt;br /&gt;
* [[Tools and tips of BGA Studio]] - Tips and instructions on setting up development environment&lt;br /&gt;
* [[Studio logs]] - Instructions for log access&lt;br /&gt;
* [[Practical debugging]] - Tips focused on debugging&lt;br /&gt;
* [[Troubleshooting]] - Most common &amp;quot;I am really stuck&amp;quot; situations&lt;br /&gt;
* [https://studio.boardgamearena.com/bugs Studio Bugs] - Reports against Studio itself (not BGA!)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;/div&gt;</summary>
		<author><name>Archduke</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Template:Studio_Framework_Navigation&amp;diff=12964</id>
		<title>Template:Studio Framework Navigation</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Template:Studio_Framework_Navigation&amp;diff=12964"/>
		<updated>2022-05-03T10:16:20Z</updated>

		<summary type="html">&lt;p&gt;Archduke: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;!-- Do not use heading tags, or else these sidebar headings appear in the page TOCs --&amp;gt;&lt;br /&gt;
__TOC__&lt;br /&gt;
&amp;lt;div class=&amp;quot;studio-framework-navigation&amp;quot; style=&amp;quot;float: right; width: 300px; border: solid #000 1px; padding: 1em; margin-left: 1em; background: #fff;&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-weight:bold;font-size:1.2em;margin-top:0.3em;line-height:1.6;padding-top:0.5em;&amp;quot;&amp;gt;&amp;lt;center&amp;gt;&#039;&#039;&#039;Game File Reference&#039;&#039;&#039;&amp;lt;/center&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-weight:bold;font-size:1.2em;margin-top:0.3em;line-height:1.6;padding-top:0.5em;&amp;quot;&amp;gt;&amp;lt;center&amp;gt;&#039;&#039;&#039;[[Studio file reference|Overview]]&#039;&#039;&#039;&amp;lt;/center&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* [[Game database model: dbmodel.sql|&amp;lt;b&amp;gt;dbmodel.sql&amp;lt;/b&amp;gt;]] - database model&lt;br /&gt;
* [[Game meta-information: gameinfos.inc.php|&amp;lt;b&amp;gt;gameinfos.inc.php&amp;lt;/b&amp;gt;]] - meta-information&lt;br /&gt;
* [[Game options and preferences: gameoptions.inc.php|&amp;lt;b&amp;gt;gameoptions.inc.php&amp;lt;/b&amp;gt;]] - game options &amp;amp; user preferences&lt;br /&gt;
* [[Game art: img directory|&amp;lt;b&amp;gt;img/&amp;lt;/b&amp;gt;]] - game art&lt;br /&gt;
* [[Game material description: material.inc.php|&amp;lt;b&amp;gt;material.inc.php&amp;lt;/b&amp;gt;]] - static data&lt;br /&gt;
* &amp;lt;b&amp;gt;misc/&amp;lt;/b&amp;gt; - studio-only storage&lt;br /&gt;
* &amp;lt;b&amp;gt;modules/&amp;lt;/b&amp;gt; - additional game code&lt;br /&gt;
* [[Your game state machine: states.inc.php|&amp;lt;b&amp;gt;states.inc.php&amp;lt;/b&amp;gt;]] - state machine&lt;br /&gt;
* [[Game statistics: stats.inc.php|&amp;lt;b&amp;gt;stats.inc.php&amp;lt;/b&amp;gt;]] - statistics&lt;br /&gt;
* [[Players actions: yourgamename.action.php|X.&amp;lt;b&amp;gt;action.php&amp;lt;/b&amp;gt;]] - player actions&lt;br /&gt;
* [[Game interface stylesheet: yourgamename.css|X&amp;lt;b&amp;gt;.css&amp;lt;/b&amp;gt;]] - interface stylesheet&lt;br /&gt;
* [[Main game logic: yourgamename.game.php|X.&amp;lt;b&amp;gt;game.php&amp;lt;/b&amp;gt;]] - main logic&lt;br /&gt;
* [[Game interface logic: yourgamename.js|X.&amp;lt;b&amp;gt;js&amp;lt;/b&amp;gt;]] - interface logic&lt;br /&gt;
* [[Game layout: view and template: yourgamename.view.php and yourgamename_yourgamename.tpl|X.&amp;lt;b&amp;gt;view.php&amp;lt;/b&amp;gt;]] - dynamic game layout&lt;br /&gt;
* [[Game layout: view and template: yourgamename.view.php and yourgamename_yourgamename.tpl|X_X.&amp;lt;b&amp;gt;tpl&amp;lt;/b&amp;gt;]] - static game layout&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
-----&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-weight:bold;font-size:1.2em;margin-top:0.3em;line-height:1.6;padding-top:0.5em;&amp;quot;&amp;gt;&amp;lt;center&amp;gt;&#039;&#039;&#039;Useful Components&#039;&#039;&#039;&amp;lt;/center&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Official&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* [[Deck]]: a PHP component to manage cards (deck, hands, picking cards, moving cards, shuffle deck, ...).&lt;br /&gt;
* [[Draggable]]: a JS component to manage drag&#039;n&#039;drop actions.&lt;br /&gt;
* [[Counter]]: a JS component to manage a counter that can increase/decrease (ex: player&#039;s score).&lt;br /&gt;
* [[ExpandableSection]]: a JS component to manage a rectangular block of HTML than can be displayed/hidden.&lt;br /&gt;
* [[Scrollmap]]: a JS component to manage a scrollable game area (useful when the game area can be infinite. Examples:  Saboteur or Takenoko games).&lt;br /&gt;
* [[Stock]]: a JS component to manage and display a set of game elements displayed at a position.&lt;br /&gt;
* [[Zone]]: a JS component to manage a zone of the board where several game elements can come and leave, but should be well displayed together (See for example: token&#039;s places at Can&#039;t Stop).&lt;br /&gt;
&lt;br /&gt;
Undocumented component (if somebody knows please help with docs)&lt;br /&gt;
* [[Wrapper]]: a JS component to wrap a  &amp;amp;lt;div&amp;amp;gt; element around its child, even if these elements are absolute positioned.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Unofficial&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* [[BGA Code Sharing]] - Shared resources, projects on git hub, common code, other links&lt;br /&gt;
* [[BGA Studio Cookbook]] - Tips and instructions on using API&#039;s, libraries and frameworks&lt;br /&gt;
* [[Some usual board game elements image ressources]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
-----&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-weight:bold;font-size:1.2em;margin-top:0.3em;line-height:1.6;padding-top:0.5em;&amp;quot;&amp;gt;&amp;lt;center&amp;gt;&#039;&#039;&#039;Game Development Process&#039;&#039;&#039;&amp;lt;/center&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* [[First steps with BGA Studio]]&lt;br /&gt;
* [[Create a game in BGA Studio: Complete Walkthrough]]&lt;br /&gt;
* [[Tutorial reversi]] &lt;br /&gt;
* [[Tutorial gomoku]] &lt;br /&gt;
* [[Tutorial hearts]]&lt;br /&gt;
* [[BGA Studio Guidelines]]&lt;br /&gt;
* [[BGA game Lifecycle]]&lt;br /&gt;
* [[Pre-release checklist]]&lt;br /&gt;
* [[Post-release phase]]&lt;br /&gt;
* [[Help|Player Resources]] - add player help/rules to your game page&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
-----&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-weight:bold;font-size:1.2em;margin-top:0.3em;line-height:1.6;padding-top:0.5em;&amp;quot;&amp;gt;&amp;lt;center&amp;gt;&#039;&#039;&#039;Guides for Common Topics&#039;&#039;&#039;&amp;lt;/center&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* [[Translations]] - make your game translatable&lt;br /&gt;
* [[Game replay|Game Replay]]&lt;br /&gt;
* [[Your game mobile version|Mobile Users]]&lt;br /&gt;
* [[3D]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
-----&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-weight:bold;font-size:1.2em;margin-top:0.3em;line-height:1.6;padding-top:0.5em;&amp;quot;&amp;gt;&amp;lt;center&amp;gt;&#039;&#039;&#039;Miscellaneous Resources&#039;&#039;&#039;&amp;lt;/center&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* [[Studio FAQ]]&lt;br /&gt;
* [[Tools and tips of BGA Studio]] - Tips and instructions on setting up development environment&lt;br /&gt;
* [[Studio logs]] - Instructions for log access&lt;br /&gt;
* [[Practical debugging]] - Tips focused on debugging&lt;br /&gt;
* [[Troubleshooting]] - Most common &amp;quot;I am really stuck&amp;quot; situations&lt;br /&gt;
* [https://studio.boardgamearena.com/bugs Studio Bugs] - Reports against Studio itself (not BGA!)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Archduke</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Studio&amp;diff=12959</id>
		<title>Studio</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Studio&amp;diff=12959"/>
		<updated>2022-05-03T10:15:21Z</updated>

		<summary type="html">&lt;p&gt;Archduke: Add TOC&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Studio_Framework_Navigation}}&lt;br /&gt;
&lt;br /&gt;
[[File:Bga_studio_small.jpg]]&lt;br /&gt;
&lt;br /&gt;
Note: Please DO NOT translate Studio Documentation, so that there can be one place where you can find the latest information available.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
== What is Board Game Arena Studio? ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Board Game Arena Studio&#039;&#039;&#039; is a platform to build online board game adaptations using the Board Game Arena platform.&lt;br /&gt;
&lt;br /&gt;
It is open to any gamer with software development skills :)&lt;br /&gt;
&lt;br /&gt;
BGA Studio website: https://studio.boardgamearena.com&lt;br /&gt;
&lt;br /&gt;
Original announcement on BGA forum: https://forum.boardgamearena.com/viewtopic.php?f=10&amp;amp;t=1973&lt;br /&gt;
&lt;br /&gt;
== Discover BGA Studio in 5 presentations ==&lt;br /&gt;
&lt;br /&gt;
Why, how, what... to start discovering BGA Studio, we prepared 5 &amp;quot;powerpoint&amp;quot; presentations for you:&lt;br /&gt;
&lt;br /&gt;
* [http://www.slideshare.net/boardgamearena/5-reasons-why-you-should-use-bga-studio-for-your-online-board-game 5 reasons why you should use BGA Studio for your online board game] (or [http://en.doc.boardgamearena.com/images/5/58/1-why-developing.pdf ‎Download as PDF])&lt;br /&gt;
* [http://www.slideshare.net/boardgamearena/the-8-steps-to-create-a-board-game-on-board-game-arena The 8 steps to create a board game on Board Game Arena] (or [http://en.doc.boardgamearena.com/images/1/1e/2-8-steps-to-realize.pdf Download as PDF])&lt;br /&gt;
* [http://www.slideshare.net/boardgamearena/the-bga-framework-at-a-glance The BGA Framework at a glance] (or [http://en.doc.boardgamearena.com/images/7/79/3-thebgaframework.pdf Download as PDF])&lt;br /&gt;
* [http://www.slideshare.net/boardgamearena/bga-studio-focus-on-bga-game-state-machine Focus on BGA game state machine] (or [http://en.doc.boardgamearena.com/images/9/98/4-gamestates.pdf Download as PDF])&lt;br /&gt;
* [http://www.slideshare.net/boardgamearena/bga-studio-guidelines BGA developers guidelines] (or [http://en.doc.boardgamearena.com/images/7/76/5-guidelines.pdf ‎Download as PDF])&lt;br /&gt;
&lt;br /&gt;
== How to join the BGA developer team? ==&lt;br /&gt;
&lt;br /&gt;
Please see this page: [[How to join BGA developer team?]]&lt;br /&gt;
&lt;br /&gt;
== Great, I&#039;m in! ... How should I start? ==&lt;br /&gt;
&lt;br /&gt;
If you didn&#039;t already, check the presentations at the top of this page to get the basics.&lt;br /&gt;
&lt;br /&gt;
Then, you should checkout the [[First steps with BGA Studio]] to make sure that runs fine.&lt;br /&gt;
&lt;br /&gt;
After that, we strongly advise you to take one of these game creation tutorials:&lt;br /&gt;
* [[Tutorial reversi]] - an abstract strategy game played on an 8×8 uncheckered board for 2 players&lt;br /&gt;
* [[Tutorial gomoku]] - an abstract strategy game tic-tac-toe style for 2 players&lt;br /&gt;
* [[Tutorial hearts]] - a card game for 4 players&lt;br /&gt;
&lt;br /&gt;
Then start editing files and see what happens! ;)&lt;br /&gt;
&lt;br /&gt;
Once you&#039;re done with tutorials, you can start a real game (or join existing project)&lt;br /&gt;
* [[Create a game in BGA Studio: Complete Walkthrough]] &lt;br /&gt;
&lt;br /&gt;
If you have any questions, please check out the &#039;&#039;&#039;[[Studio FAQ]]&#039;&#039;&#039; first, then if you didn&#039;t find the answer you were looking for, please post your question on the [http://forum.boardgamearena.com/viewforum.php?f=12 &#039;&#039;&#039;development forum&#039;&#039;&#039;].&lt;br /&gt;
&lt;br /&gt;
== BGA Studio documentation ==&lt;br /&gt;
&lt;br /&gt;
=== BGA Studio Framework reference ===&lt;br /&gt;
&lt;br /&gt;
This part of the documentation focuses on the development framework itself: functions and methods available to build your game.&lt;br /&gt;
&lt;br /&gt;
[[Studio file reference|File structure of a BGA game]]&lt;br /&gt;
&lt;br /&gt;
==== Game logic (Server side) ====&lt;br /&gt;
&lt;br /&gt;
* [[Main game logic: yourgamename.game.php]]&lt;br /&gt;
* [[Your game state machine: states.inc.php]]&lt;br /&gt;
* [[Game database model: dbmodel.sql]]&lt;br /&gt;
* [[Players actions: yourgamename.action.php]]&lt;br /&gt;
* [[Game material description: material.inc.php]]&lt;br /&gt;
* [[Game statistics: stats.inc.php]]&lt;br /&gt;
&lt;br /&gt;
==== Game interface (Client side) ====&lt;br /&gt;
&lt;br /&gt;
* [[Game interface logic: yourgamename.js]]&lt;br /&gt;
* [[Game art: img directory]]&lt;br /&gt;
* [[Game interface stylesheet: yourgamename.css]]&lt;br /&gt;
* [[Game layout: view and template: yourgamename.view.php and yourgamename_yourgamename.tpl]]&lt;br /&gt;
* [[Your game mobile version]]&lt;br /&gt;
&lt;br /&gt;
==== Other components ====&lt;br /&gt;
&lt;br /&gt;
* [[Translations]] (how to make your game translatable)&lt;br /&gt;
* [[Game options and preferences: gameoptions.inc.php]]&lt;br /&gt;
* [[Game meta-information: gameinfos.inc.php]]&lt;br /&gt;
* [[Game replay]]&lt;br /&gt;
* [[3D]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== BGA Studio game components reference ===&lt;br /&gt;
&lt;br /&gt;
Game components are useful tools you can use in your game adaptations.&lt;br /&gt;
&lt;br /&gt;
JS:&lt;br /&gt;
&lt;br /&gt;
* [[Counter]]: a JS component to manage a counter that can increase/decrease (ex: player&#039;s score).&lt;br /&gt;
* [[Scrollmap]]: a JS component to manage a scrollable game area (useful when the game area can be infinite. Examples:  Saboteur or Takenoko games).&lt;br /&gt;
* [[Stock]]: a JS component to manage and display a set of game elements displayed at a position.&lt;br /&gt;
* [[Zone]]: a JS component to manage a zone of the board where several game elements can come and leave, but should be well displayed together (See for example: token&#039;s places at Can&#039;t Stop).&lt;br /&gt;
* [[Draggable]]: a JS component to manage drag&#039;n&#039;drop actions.&lt;br /&gt;
* [[ExpandableSection]]: a JS component to manage a rectangular block of HTML than can be displayed/hidden.&lt;br /&gt;
* [[Anti-Stock]]:Code snippets in ValinaJS/HTML5 to do what stock does (that is if you cannot beat Stock into submission)&lt;br /&gt;
&lt;br /&gt;
PHP:&lt;br /&gt;
* [[Deck]]: a PHP component to manage cards (deck, hands, picking cards, moving cards, shuffle deck, ...).&lt;br /&gt;
&lt;br /&gt;
Reference for classes in game class hierarchy&lt;br /&gt;
&lt;br /&gt;
* [[Table]]: a PHP class that you inherit from for the game php&lt;br /&gt;
&lt;br /&gt;
=== BGA Studio user guide ===&lt;br /&gt;
&lt;br /&gt;
This part of the documentation is a user guide for the BGA Studio online development environment.&lt;br /&gt;
&lt;br /&gt;
Lifecycle&lt;br /&gt;
&lt;br /&gt;
* [[BGA game Lifecycle]]&lt;br /&gt;
* [[Create a game in BGA Studio: Complete Walkthrough]]&lt;br /&gt;
* [[Pre-release checklist]] - Go throught this list if you think you done development&lt;br /&gt;
* [[Post-release phase]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Tools and Advice&lt;br /&gt;
* [[BGA Studio Guidelines]]&lt;br /&gt;
* [[I wish I knew this when I started]] - one liners on most common missed features, mistakes, etc with further doc references&lt;br /&gt;
* [[Tools and tips of BGA Studio]] - Tips and instructions on setting up development environment&lt;br /&gt;
** [[Practical debugging]] - Tips focused on debugging&lt;br /&gt;
** [[Studio logs]] - Instructions for log access&lt;br /&gt;
** [[Troubleshooting]] - Most common &amp;quot;I am really stuck&amp;quot; situations&lt;br /&gt;
* [[BGA Studio Cookbook]] - Tips and instructions on using API&#039;s, libraries and frameworks&lt;br /&gt;
** [[Using Vue]] - work-in-progress guide on using the modern framework Vue.js to create a game&lt;br /&gt;
** [[Using Typescript and Scss]] - How to auto-build Typescript and SCSS files to make your code cleaner&lt;br /&gt;
** [[Bots and Artificial Intelligence]] - How to add AI/Bots to the game&lt;br /&gt;
* [[Studio FAQ]]&lt;br /&gt;
&lt;br /&gt;
Sharing&lt;br /&gt;
* [[Common board game elements image resources]] - Dice, meeples, cubes, etc&lt;br /&gt;
* [[BGA Code Sharing]] - Shared resources, projects on git hub, common code, other links&lt;br /&gt;
&lt;br /&gt;
== Other resources ==&lt;br /&gt;
&lt;br /&gt;
[http://forum.boardgamearena.com/viewforum.php?f=12 Development forum]&lt;br /&gt;
&lt;br /&gt;
[https://studio.boardgamearena.com/bugs Bug tracking system FOR STUDIO issues and APIs]&lt;br /&gt;
&lt;br /&gt;
DISCORD chat server/room invite link https://discord.gg/YxEUacY if it does not work check this topic https://forum.boardgamearena.com/viewtopic.php?f=12&amp;amp;t=17403&amp;amp;hilit=discord&lt;br /&gt;
&lt;br /&gt;
Developer BLOGS https://bga-devs.github.io/blog/&lt;br /&gt;
&lt;br /&gt;
[[Contact BGA Studio]]&lt;br /&gt;
&lt;br /&gt;
== Software Versions ==&lt;br /&gt;
&lt;br /&gt;
Versions currently used by BGA framework:&lt;br /&gt;
&lt;br /&gt;
* Dojo Toolkit 1.15&lt;br /&gt;
* PHP: 7.4&lt;br /&gt;
* SQL: MySQL 5.7&lt;br /&gt;
* JS/CSS/HTML: limited by what minimization tools support [[Game_interface_logic:_yourgamename.js#Javascript_minimization_.28after_July_2020.29]]&lt;br /&gt;
* Font Awesome: 4.7 https://fontawesome.com/v4.7/icons/&lt;/div&gt;</summary>
		<author><name>Archduke</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Template:Studio_Framework_Navigation&amp;diff=12958</id>
		<title>Template:Studio Framework Navigation</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Template:Studio_Framework_Navigation&amp;diff=12958"/>
		<updated>2022-05-03T10:14:54Z</updated>

		<summary type="html">&lt;p&gt;Archduke: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;!-- Do not use heading tags, or else these sidebar headings appear in the page TOCs --&amp;gt;&lt;br /&gt;
__NOTOC__&lt;br /&gt;
&amp;lt;div class=&amp;quot;studio-framework-navigation&amp;quot; style=&amp;quot;float: right; width: 300px; border: solid #000 1px; padding: 1em; margin-left: 1em; background: #fff;&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-weight:bold;font-size:1.2em;margin-top:0.3em;line-height:1.6;padding-top:0.5em;&amp;quot;&amp;gt;&amp;lt;center&amp;gt;&#039;&#039;&#039;Game File Reference&#039;&#039;&#039;&amp;lt;/center&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-weight:bold;font-size:1.2em;margin-top:0.3em;line-height:1.6;padding-top:0.5em;&amp;quot;&amp;gt;&amp;lt;center&amp;gt;&#039;&#039;&#039;[[Studio file reference|Overview]]&#039;&#039;&#039;&amp;lt;/center&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* [[Game database model: dbmodel.sql|&amp;lt;b&amp;gt;dbmodel.sql&amp;lt;/b&amp;gt;]] - database model&lt;br /&gt;
* [[Game meta-information: gameinfos.inc.php|&amp;lt;b&amp;gt;gameinfos.inc.php&amp;lt;/b&amp;gt;]] - meta-information&lt;br /&gt;
* [[Game options and preferences: gameoptions.inc.php|&amp;lt;b&amp;gt;gameoptions.inc.php&amp;lt;/b&amp;gt;]] - game options &amp;amp; user preferences&lt;br /&gt;
* [[Game art: img directory|&amp;lt;b&amp;gt;img/&amp;lt;/b&amp;gt;]] - game art&lt;br /&gt;
* [[Game material description: material.inc.php|&amp;lt;b&amp;gt;material.inc.php&amp;lt;/b&amp;gt;]] - static data&lt;br /&gt;
* &amp;lt;b&amp;gt;misc/&amp;lt;/b&amp;gt; - studio-only storage&lt;br /&gt;
* &amp;lt;b&amp;gt;modules/&amp;lt;/b&amp;gt; - additional game code&lt;br /&gt;
* [[Your game state machine: states.inc.php|&amp;lt;b&amp;gt;states.inc.php&amp;lt;/b&amp;gt;]] - state machine&lt;br /&gt;
* [[Game statistics: stats.inc.php|&amp;lt;b&amp;gt;stats.inc.php&amp;lt;/b&amp;gt;]] - statistics&lt;br /&gt;
* [[Players actions: yourgamename.action.php|X.&amp;lt;b&amp;gt;action.php&amp;lt;/b&amp;gt;]] - player actions&lt;br /&gt;
* [[Game interface stylesheet: yourgamename.css|X&amp;lt;b&amp;gt;.css&amp;lt;/b&amp;gt;]] - interface stylesheet&lt;br /&gt;
* [[Main game logic: yourgamename.game.php|X.&amp;lt;b&amp;gt;game.php&amp;lt;/b&amp;gt;]] - main logic&lt;br /&gt;
* [[Game interface logic: yourgamename.js|X.&amp;lt;b&amp;gt;js&amp;lt;/b&amp;gt;]] - interface logic&lt;br /&gt;
* [[Game layout: view and template: yourgamename.view.php and yourgamename_yourgamename.tpl|X.&amp;lt;b&amp;gt;view.php&amp;lt;/b&amp;gt;]] - dynamic game layout&lt;br /&gt;
* [[Game layout: view and template: yourgamename.view.php and yourgamename_yourgamename.tpl|X_X.&amp;lt;b&amp;gt;tpl&amp;lt;/b&amp;gt;]] - static game layout&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
-----&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-weight:bold;font-size:1.2em;margin-top:0.3em;line-height:1.6;padding-top:0.5em;&amp;quot;&amp;gt;&amp;lt;center&amp;gt;&#039;&#039;&#039;Useful Components&#039;&#039;&#039;&amp;lt;/center&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Official&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* [[Deck]]: a PHP component to manage cards (deck, hands, picking cards, moving cards, shuffle deck, ...).&lt;br /&gt;
* [[Draggable]]: a JS component to manage drag&#039;n&#039;drop actions.&lt;br /&gt;
* [[Counter]]: a JS component to manage a counter that can increase/decrease (ex: player&#039;s score).&lt;br /&gt;
* [[ExpandableSection]]: a JS component to manage a rectangular block of HTML than can be displayed/hidden.&lt;br /&gt;
* [[Scrollmap]]: a JS component to manage a scrollable game area (useful when the game area can be infinite. Examples:  Saboteur or Takenoko games).&lt;br /&gt;
* [[Stock]]: a JS component to manage and display a set of game elements displayed at a position.&lt;br /&gt;
* [[Zone]]: a JS component to manage a zone of the board where several game elements can come and leave, but should be well displayed together (See for example: token&#039;s places at Can&#039;t Stop).&lt;br /&gt;
&lt;br /&gt;
Undocumented component (if somebody knows please help with docs)&lt;br /&gt;
* [[Wrapper]]: a JS component to wrap a  &amp;amp;lt;div&amp;amp;gt; element around its child, even if these elements are absolute positioned.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Unofficial&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* [[BGA Code Sharing]] - Shared resources, projects on git hub, common code, other links&lt;br /&gt;
* [[BGA Studio Cookbook]] - Tips and instructions on using API&#039;s, libraries and frameworks&lt;br /&gt;
* [[Some usual board game elements image ressources]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
-----&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-weight:bold;font-size:1.2em;margin-top:0.3em;line-height:1.6;padding-top:0.5em;&amp;quot;&amp;gt;&amp;lt;center&amp;gt;&#039;&#039;&#039;Game Development Process&#039;&#039;&#039;&amp;lt;/center&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* [[First steps with BGA Studio]]&lt;br /&gt;
* [[Create a game in BGA Studio: Complete Walkthrough]]&lt;br /&gt;
* [[Tutorial reversi]] &lt;br /&gt;
* [[Tutorial gomoku]] &lt;br /&gt;
* [[Tutorial hearts]]&lt;br /&gt;
* [[BGA Studio Guidelines]]&lt;br /&gt;
* [[BGA game Lifecycle]]&lt;br /&gt;
* [[Pre-release checklist]]&lt;br /&gt;
* [[Post-release phase]]&lt;br /&gt;
* [[Help|Player Resources]] - add player help/rules to your game page&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
-----&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-weight:bold;font-size:1.2em;margin-top:0.3em;line-height:1.6;padding-top:0.5em;&amp;quot;&amp;gt;&amp;lt;center&amp;gt;&#039;&#039;&#039;Guides for Common Topics&#039;&#039;&#039;&amp;lt;/center&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* [[Translations]] - make your game translatable&lt;br /&gt;
* [[Game replay|Game Replay]]&lt;br /&gt;
* [[Your game mobile version|Mobile Users]]&lt;br /&gt;
* [[3D]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
-----&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-weight:bold;font-size:1.2em;margin-top:0.3em;line-height:1.6;padding-top:0.5em;&amp;quot;&amp;gt;&amp;lt;center&amp;gt;&#039;&#039;&#039;Miscellaneous Resources&#039;&#039;&#039;&amp;lt;/center&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* [[Studio FAQ]]&lt;br /&gt;
* [[Tools and tips of BGA Studio]] - Tips and instructions on setting up development environment&lt;br /&gt;
* [[Studio logs]] - Instructions for log access&lt;br /&gt;
* [[Practical debugging]] - Tips focused on debugging&lt;br /&gt;
* [[Troubleshooting]] - Most common &amp;quot;I am really stuck&amp;quot; situations&lt;br /&gt;
* [https://studio.boardgamearena.com/bugs Studio Bugs] - Reports against Studio itself (not BGA!)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Archduke</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Translations&amp;diff=12957</id>
		<title>Translations</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Translations&amp;diff=12957"/>
		<updated>2022-05-03T10:04:30Z</updated>

		<summary type="html">&lt;p&gt;Archduke: /* Formatting on client side */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Studio_Framework_Navigation}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Using BGA Studio, the game you create is ready to be translated to each language by the BGA community. To make this possible, you only need to specify which string must be translated and how to combine them.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
== Localization Overview ==&lt;br /&gt;
&lt;br /&gt;
Localization for BGA games happens largely on the CLIENT. Games must be developed in English and English strings are sent to the client.&lt;br /&gt;
&lt;br /&gt;
It&#039;s only at the client that your English strings will be displayed with the translation for the user&#039;s language, when such a translation exists.&lt;br /&gt;
&lt;br /&gt;
For anyone who has worked on a system where translation happens at the server and localized strings are sent to the client: you must unlearn what you have learned. Just stick with English and send the untranslated English strings. The magic happens at the client.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== How will my strings be translated? ==&lt;br /&gt;
&lt;br /&gt;
When developing your game, all strings must be in English. Strings must be coherent with the English version of the game.&lt;br /&gt;
&lt;br /&gt;
Once your game enters Beta, the BGA player community will descend upon your game like a plague of locusts and translate it into dozens of languages before you can say &amp;quot;Je ne parle pas anglais&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== What do I have to do from a programming standpoint? ==&lt;br /&gt;
&lt;br /&gt;
Not as much as you think. Read on for full details, but the golden rules are:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# Make sure that any string on the server side that needs to be translated on the client side is wrapped in a clienttranslate() function when defined. For example: $my_response = clienttranslate(&#039;Hey translators, please translate this string&#039;). clienttranslate doesn&#039;t actually do anything at all (it just passes the text through) but the translation engine searches your code for strings wrapped in that function and uses them to build the list of strings that need to be translated.&lt;br /&gt;
# On the client side, just display your text, but wrap it in _().&lt;br /&gt;
## If you pass a string constant to _() - such as _(&#039;This is my string&#039;) then the parser will automatically detect and add your string to the list of strings that need to be translated, AND it will display the local translation for it when displaying.&lt;br /&gt;
## If you pass a variable to _() - such as _(args.my_message) then MAKE SURE that the variable is set to an English string that is either defined somewhere in your PHP code in a clienttranslate() function or somewhere else in your javascript code in a _() function. As long as it is, the translators will provide translations for it, and the _() function will display the local translation of your English string.&lt;br /&gt;
# A string used as the message for notifyAllPlayers or notifyPlayer will automatically have its translation displayed on the client - you don&#039;t need to do anything EXCEPT make sure that it is wrapped in a clienttranslate() on the server, so that it gets translated.&lt;br /&gt;
# A string used as the &amp;quot;description&amp;quot; or &amp;quot;descriptionmyturn&amp;quot; for a state in your state machine will also be automatically translated on the client - you don&#039;t need to do anything EXCEPT make sure that it is wrapped in a clienttranslate() on the server, so that it gets translated.&lt;br /&gt;
# A string used in the pre-games option screen will also automatically have any translation displayed at the client - you don&#039;t need to do anything EXCEPT make sure that it is wrapped in a totranslate() on the server (nota bene: you should not use clienttranslate() here as this file is processed specifically and those strings will not be included in the game translation file but in the main site translation file - with a prefix to keep translations isolated by module - as they have to be translated on main site pages. If you need exactly the same string in your game for a client side translation, it should be declared somewhere else in your code wrapped inside a clienttranslate() to be included in the game translation file.&lt;br /&gt;
# A string used in the statistics screen will operate like a string in the pre-game options screen. It will automatically have any translation displayed at the client as long as you make sure that it is wrapped in a totranslate() on the server.&lt;br /&gt;
# If you are using parameters for a call to notifyAllPlayers or notifyPlayers, or for a state&#039;s &amp;quot;description&amp;quot; or &amp;quot;descriptionmyturn&amp;quot; and those parameters contain text that needs to be translated, you will need to tell the system to display the translated versions of them by using the &#039;i18n&#039; argument. See below for full details.&lt;br /&gt;
&lt;br /&gt;
== What strings should be translated? ==&lt;br /&gt;
&lt;br /&gt;
Every text that can be visible by the player when the game is running normally. This includes tooltips, texts on cards, error messages.&lt;br /&gt;
&lt;br /&gt;
This does NOT include error messages that are not supposed to happen (unexpected errors).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== What rules should I follow for the original English strings? ==&lt;br /&gt;
&lt;br /&gt;
For a coherent and homogeneous interface, here are some rules about ending a sentence with a final period &#039;.&#039;&lt;br /&gt;
&lt;br /&gt;
* As a general rule:&lt;br /&gt;
** If a sentence is displayed isolated in the interface =&amp;gt; no final period&lt;br /&gt;
** If a sentence is followed or could be followed by another sentence in the same interface space =&amp;gt; final period.&lt;br /&gt;
&lt;br /&gt;
* In detail:&lt;br /&gt;
** No final period:&lt;br /&gt;
*** button labels&lt;br /&gt;
*** section titles&lt;br /&gt;
*** menu elements&lt;br /&gt;
*** links triggering an isolated action&lt;br /&gt;
*** anything that is not a full sentence&lt;br /&gt;
*** current actions in the status bar&lt;br /&gt;
** Final period:&lt;br /&gt;
*** complete sentences (e.g., explanations and descriptions) that can be chained with other sentences&lt;br /&gt;
** Either a period or no period is acceptable (but this should be consistent throughout the game) for:&lt;br /&gt;
*** isolated tooltips / small sentences&lt;br /&gt;
*** game logs (no period is usually preferable)&lt;br /&gt;
*** error messages (unless there is more than one sentence in the error message; final period is mandatory in this case)&lt;br /&gt;
&lt;br /&gt;
Otherwise, you should try to follow as closely as possible the general style and format (including capitalization) used in the published English rulebook and game materials.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Focus on translating notifications ==&lt;br /&gt;
&lt;br /&gt;
Usually, translating a website is simple: you just call a function on every string you have to translate, and the string is translated in the player&#039;s language. On Board Game Arena, this is exactly the same with the &amp;quot;_( string )&amp;quot; function.&lt;br /&gt;
&lt;br /&gt;
However, there is one difference on BGA: notifications. The server is sending notifications to players, and most of the time the notifications are the same for every players, no matter what language each player is using. This is why notifications are translated on client side in the proper language, even if the strings are defined on server side.&lt;br /&gt;
&lt;br /&gt;
== How to not make translators crazy ;) ==&lt;br /&gt;
&lt;br /&gt;
* Try to reuse the exact same strings (with the same case, etc.) to minimize the number of strings to translate.&lt;br /&gt;
** &#039;&#039;&#039;Example&#039;&#039;&#039;: Consider replacing &amp;lt;pre&amp;gt;self::_(&amp;quot;Winner&amp;quot;)&amp;lt;/pre&amp;gt; and &amp;lt;pre&amp;gt;self::_(&amp;quot;Winners&amp;quot;)&amp;lt;/pre&amp;gt; (two strings to translate) with &amp;lt;pre&amp;gt;self::_(&amp;quot;Winner(s)&amp;quot;)&amp;lt;/pre&amp;gt;&lt;br /&gt;
** &#039;&#039;&#039;Example 2&#039;&#039;&#039;: &amp;lt;pre&amp;gt;clienttranslate(&amp;quot;play a card&amp;quot;)&amp;lt;/pre&amp;gt; and &amp;lt;pre&amp;gt;clienttranslate(&amp;quot;Play a card&amp;quot;)&amp;lt;/pre&amp;gt; means there will be two strings to translate.&lt;br /&gt;
* Do not mark as translatable a game element that does not have to be translated (e.g., if the name of a monster on a card is &amp;quot;Zzzzz&amp;quot;, maybe there&#039;s no need to translate it).&lt;br /&gt;
* Words does not come in the same order in each language. Thus, when you have to translate a string with an argument, do not write something like:&lt;br /&gt;
&amp;lt;pre&amp;gt;self::_(&amp;quot;First part of the string, &amp;quot;).$argument.&#039; &#039;.self::_(&amp;quot;second part of the string&amp;quot;)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Write instead:&lt;br /&gt;
&amp;lt;pre&amp;gt;sprintf( self::_(&amp;quot;First part of the string, %s second part of the string&amp;quot;), $argument )&amp;lt;/pre&amp;gt;&lt;br /&gt;
(or the equivalent &amp;quot;dojo.string.substitute&amp;quot; in Javascript)&lt;br /&gt;
* When translators are going to translate your game, the most difficult task for them is to get the context of the string to be translated. The shorter the string is, the more difficult the task is for them. As a rule of thumb, try to avoid short, insignificant strings that require knowledge of their surrounding context. You can also leave a comment on the context of the string in the translation program (English to English) if you are the developer of the game.&lt;br /&gt;
* The BGA translation policy is to be flexible on grammar. We prefer to write &amp;quot;player gets 1 coin(s)&amp;quot; rather than write two versions of the same string for plural and singular - it reduces the number of strings to translate.&lt;br /&gt;
* Instead of writing elaborate strings like &amp;quot;With the effect of ZZZ, player XXX gains a new YYY&amp;quot;, which is very difficult to translate, write strings like &amp;quot;ZZZ: XXX gets YYY&amp;quot;.&lt;br /&gt;
* Use present tense instead of past. E.g., &amp;quot;player gets wood&amp;quot; instead of &amp;quot;player got wood&amp;quot;.&lt;br /&gt;
* Avoid using gender-specific wording as much as possible. If needed be aware that [[https://forum.boardgamearena.com/viewtopic.php?f=11&amp;amp;t=19432&amp;amp;start=10#p88592 a pronoun replacement system]] is in place, and cannot work if your use &amp;quot;their&amp;quot; as a singular genderless pronoun, as it removes the information that it&#039;s singular. E.g., you should write &amp;quot;playerX returns card to *his* hand&amp;quot; or &amp;quot;playerX returns card to *his/her* hand&amp;quot; and not &amp;quot;playerX returns card to *their* hand&amp;quot; as in the 2 first case the system will substitute the proper pronoun his/her/their depending on playerX declared/undeclared gender, but in the second case it will always stay &amp;quot;their&amp;quot; whatever the player preference setting.&lt;br /&gt;
* Where two strings are identical apart from (say) a number, use the same string with a ${parameter}, and call format_string_recursive (on the client) or use args (for notifications and state descriptions) to provide the details. But *never* do that for composing multiple sentences with words: other languages have different grammar and it would most likely create untranslatable strings.&lt;br /&gt;
&lt;br /&gt;
== WARNING: Make sure your strings will be translated! ==&lt;br /&gt;
&lt;br /&gt;
For each game, our translation tool does a full scan of the code, looking for translation markers like &amp;quot;_()&amp;quot; or &amp;quot;clienttranslate()&amp;quot;. (See below for the full list of translation markers.)&lt;br /&gt;
&lt;br /&gt;
If your original string is not completely contained inside one of these markers, it won&#039;t be translated.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    // Examples: the following strings will be translated:&lt;br /&gt;
    var mystring_translated = _(&amp;quot;my string&amp;quot;);       // JS&lt;br /&gt;
    $mystring_translated = self::_(&amp;quot;my string&amp;quot;);    // PHP&lt;br /&gt;
    $mystring_translated = sprintf( self::_(&amp;quot;my string with an %s argument&amp;quot;), $argument );   // PHP&lt;br /&gt;
&lt;br /&gt;
    // Examples: the following strings WILL NOT be translated:&lt;br /&gt;
    $my_string = &amp;quot;my string&amp;quot;;&lt;br /&gt;
    $not_translated = self::_( $my_string );   // The original string is not contained within a translator marker =&amp;gt; no translation&lt;br /&gt;
    $not_translated = self::_( sprintf( &amp;quot;my string with a %s argument&amp;quot;, $argument ) ); // Ditto&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== On client side (Javascript) ==&lt;br /&gt;
&lt;br /&gt;
On client side, things are quite simple: you just have to use the &amp;quot;_()&amp;quot; function for all strings you want to translate.&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// Get a string in player&#039;s language:&lt;br /&gt;
var translated = _(&amp;quot;original english string&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
// Get a string in player&#039;s language with parameter:&lt;br /&gt;
var translated = dojo.string.substitute( _(&amp;quot;You can pick ${p} cards and discard ${d}&amp;quot;), {&lt;br /&gt;
    p: 2,&lt;br /&gt;
    d: 4&lt;br /&gt;
} );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;WARNING:&#039;&#039;&#039; in Javascript strings to translate, you should never use &#039;\n&#039;, &#039;\t&#039; or such, as it will break the translation bundle and result in all the Javascript translation to fail. In any case, the strings will result in HTML code, and such character codes won&#039;t have any impact on the HTML rendering. You should use HTML markup instead.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ANOTHER WARNING:&#039;&#039;&#039; you cannot use this function _() in the javascript object constructor, but you can achieve the same if you use it the setup method&lt;br /&gt;
&lt;br /&gt;
=== Formatting on client side ===&lt;br /&gt;
&lt;br /&gt;
Sometimes you will want to apply some formatting on the client side, but don&#039;t want to put HTML tags within the source string (which may be confusing for translators).&lt;br /&gt;
&lt;br /&gt;
This can be achieved with the &amp;lt;code&amp;gt;bga_format&amp;lt;/code&amp;gt; function and Markdown-style syntax.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * @function bga_format&lt;br /&gt;
 * Replaces delimiters with HTML tags in translated text&lt;br /&gt;
 * @param {string} translated string&lt;br /&gt;
 * @param {Object} map of replacements to make, should be of the form&lt;br /&gt;
 *     {&lt;br /&gt;
 *         &#039;*&#039;: (t) =&amp;gt; t,&lt;br /&gt;
 *         &#039;_&#039;: &#039;classname&#039;,&lt;br /&gt;
 *     }&lt;br /&gt;
 *     keys are delimiters within the translated string&lt;br /&gt;
 *     values are either strings (classname of surrounding span) or function (flexible replacements)&lt;br /&gt;
 * @returns {string} Returns the original string, with replacements made.&lt;br /&gt;
 */&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// Get a string in player&#039;s language:&lt;br /&gt;
bga_format(_(&#039;You receive a *special* _tile_&#039;), {&lt;br /&gt;
    &#039;*&#039;: (t) =&amp;gt; &#039;&amp;lt;b&amp;gt;&#039; + t + &#039;&amp;lt;/b&amp;gt;&#039;,&lt;br /&gt;
    &#039;_&#039;: &#039;tile-name&#039;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The above will return something along the lines of:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
You receive a &amp;lt;b&amp;gt;special&amp;lt;/b&amp;gt; &amp;lt;span class=&amp;quot;tile-name&amp;quot;&amp;gt;tile&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Or, if the user is playing in Spanish, for example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Recibes una &amp;lt;span class=&amp;quot;tile-name&amp;quot;&amp;gt;loseta&amp;lt;/span&amp;gt; &amp;lt;b&amp;gt;especial&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Notes:&lt;br /&gt;
* The text passed to &amp;lt;code&amp;gt;bga_format&amp;lt;/code&amp;gt; must still be translated using &amp;lt;code&amp;gt;_()&amp;lt;/code&amp;gt;, don&#039;t forget it!&lt;br /&gt;
* The characters available to demarcate formatting are: &amp;lt;code&amp;gt;[&#039;-&#039;, &#039;[&#039;, &#039;]&#039;, &#039;{&#039;, &#039;}&#039;, &#039;(&#039;, &#039;)&#039;, &#039;*&#039;, &#039;+&#039;, &#039;?&#039;, &#039;.&#039;, &#039;,&#039;, &#039;\\&#039;, &#039;^&#039;, &#039;$&#039;, &#039;|&#039;, &#039;#&#039;, &#039; &#039;]&amp;lt;/code&amp;gt;&lt;br /&gt;
* If the replacements object is a string, the inner text will be placed within a `&amp;lt;span&amp;gt;` tag with the string as a class&lt;br /&gt;
* If the replacements object is a function, the inner text will be passed as an argument to the function, and the return value will replace the text and the delimiters&lt;br /&gt;
&lt;br /&gt;
== On server side (PHP) ==&lt;br /&gt;
&lt;br /&gt;
On PHP side, you can use 3 different functions to specify that a string must be translated.&lt;br /&gt;
&lt;br /&gt;
=== Function clienttranslate ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;clienttranslate( &#039;string to translate&#039; ):&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This function is &#039;&#039;transparent&#039;&#039;: it will return the original English string without any change. Its only purpose is to mark this string as &amp;quot;must be translated&amp;quot;, and to make sure the translated version of the string will be available on client side.&lt;br /&gt;
&lt;br /&gt;
In general, you use clienttranslate:&lt;br /&gt;
* In your &#039;&#039;&#039;states.inc.php&#039;&#039;&#039;, for the fields &amp;quot;description&amp;quot; and &amp;quot;descriptionmyturn&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
      &amp;quot;description&amp;quot; =&amp;gt; clienttranslate(&#039;${card_name}: ${actplayer} must discard 4 identical energies&#039;),&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* In &#039;&#039;&#039;material.inc.php&#039;&#039;&#039;, when defining text for game materials that must be displayed on the client side.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$this-&amp;gt;card_types = array(&lt;br /&gt;
&lt;br /&gt;
     1 =&amp;gt; array(&lt;br /&gt;
        &#039;name&#039; =&amp;gt; clienttranslate(&#039;Amulet of Air&#039;), // Thus, we can use &amp;quot;_( card_name )&amp;quot; on Javascript side.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* When sending a notification with &#039;&#039;notifyAllPlayers&#039;&#039; or &#039;&#039;notifyPlayer&#039;&#039;, in the game log string and all game log arguments that need a translation.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
     // A game log string with no argument:&lt;br /&gt;
     self::notifyAllPlayers( &#039;pickLibraryCards&#039;, clienttranslate(&#039;Everyone draw cards from their library&#039;), [] );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As a consequence there is no point passing variables to this function. E.g.:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    notif=&amp;quot;foo&amp;quot;;&lt;br /&gt;
    self::notifyAllPlayers( &#039;log&#039;, clienttranslate(notif),[]); // BAD&lt;br /&gt;
    &lt;br /&gt;
    notif=clienttranslate(&amp;quot;foo&amp;quot;);&lt;br /&gt;
    self::notifyAllPlayers( &#039;log&#039;, notif,[]); // GOOD&lt;br /&gt;
&lt;br /&gt;
    self::notifyAllPlayers( &#039;log&#039;, clienttranslate(&amp;quot;player gains ${num} gems&amp;quot;),[num=&amp;gt;2]); // BAD it is dynamic string enterpreted by php &lt;br /&gt;
    self::notifyAllPlayers( &#039;log&#039;, clienttranslate(&#039;player gains ${num} gems&#039;),[num=&amp;gt;2]); // GOOD, difference is single quotes&lt;br /&gt;
&lt;br /&gt;
    self::notifyAllPlayers( &#039;log&#039;, clienttranslate(&amp;quot;player gains &amp;quot;.${num}.&amp;quot; gems&amp;quot;),[num=&amp;gt;2]); // BAD concatenation &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Translating arguments is a little bit more complex. This uses the &#039;&#039;&#039;i18n&#039;&#039;&#039; special argument as below:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 // In the following example, we translate the game log itself, but also the &amp;quot;card_name&amp;quot; argument:&lt;br /&gt;
&lt;br /&gt;
 self::notifyAllPlayers( &#039;winPoints&#039;, clienttranslate(&#039;${card_name}: ${player_name} gains ${points} point(s)&#039;), array(&lt;br /&gt;
                &#039;i18n&#039; =&amp;gt; array( &#039;card_name&#039; ),     // &amp;lt;===== We specify here that &amp;quot;card_name&amp;quot; argument must be translated&lt;br /&gt;
                &#039;player_id&#039; =&amp;gt; $player_id,&lt;br /&gt;
                &#039;player_name&#039; =&amp;gt; self::getActivePlayerName(),&lt;br /&gt;
                &#039;points&#039; =&amp;gt; $points,&lt;br /&gt;
                &#039;card_name&#039; =&amp;gt; $this-&amp;gt;card_types[8][&#039;name&#039;] // &amp;lt;==== Here, we provide original English string.&lt;br /&gt;
            ) ); &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To ensure the translation of the i18n argument will be made, clienttranslate must have been used somewhere, for instance:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$this-&amp;gt;card_types = array(&lt;br /&gt;
...&lt;br /&gt;
     8 =&amp;gt; array(&lt;br /&gt;
        &#039;name&#039; =&amp;gt; clienttranslate(&amp;quot;Amulet of Fire&amp;quot;),&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Pay attention when using the &#039;&#039;&#039;i18n&#039;&#039;&#039; argument when translating arguments for the client: do NOT use same argument for both translations AND key codes for client-side actions (like using &#039;card_name&#039; to move it on the player board as described in the example). It&#039;s pretty obvious in the example, but it can be very tricky when translation is made at the end of the development (which is often the case). Use explicit argument names like &#039;card_name_translated&#039; by example.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;WARNING:&#039;&#039;&#039; you should NEVER use concatenation with &#039;&#039;clienttranslate&#039;&#039;, as it would result in a different string to translate at runtime than the one retrieved statically in the translation system, and so translation would not be applied. If you need to compose a string, use substitution and the i18n parameter (but you also have to pay attention not to compose sentences in a way that is dependent upon the English language specific syntax, or it may be impossible to translate correctly in another language: sometimes, you need multiple full sentences rather than relying on substitution).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Method _ (underscore) ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;self::_( &amp;quot;my string to translate&amp;quot; ):&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This function returns a string translated in the language of CURRENT user (i.e. player who send the request to the server) (be careful, this is NOT the active player).&lt;br /&gt;
&lt;br /&gt;
This can be used like self::_(&#039;bla&#039;) or this-&amp;gt;(&#039;bla&#039;). You cannot use static underscore function _(&#039;bla&#039;) in php, it is not the same, it will not translate strings from your game.&lt;br /&gt;
&lt;br /&gt;
The returned string will be surrounded by HTML tags, so you cannot use it in places where pure text is required or your string already has another html markup.&lt;br /&gt;
&lt;br /&gt;
Most of the time, you don&#039;t need to translate strings on server side, except on the following situations:&lt;br /&gt;
* Throwing user exceptions&lt;br /&gt;
* Creating the labels for the game interface used in your template&lt;br /&gt;
* Rarely, in your material.inc.php, if for example you need to use some string elements in your exceptions&lt;br /&gt;
* Rarely, in your &amp;quot;getAllDatas&amp;quot; PHP method, as the data return by this method is used only by current user&lt;br /&gt;
&lt;br /&gt;
Imporant! This function does two things:&lt;br /&gt;
* Mark string for translation&lt;br /&gt;
* Translates in runtime&lt;br /&gt;
As a consequence you absolutely cannot have $var in there! Or string concatenations.&lt;br /&gt;
I.e.&lt;br /&gt;
  $food=self::_(&amp;quot;Banana&amp;quot;);// good&lt;br /&gt;
  self::_(&amp;quot;User gives $food to a cat&amp;quot;); // bad&lt;br /&gt;
For the translator we will have two strings &amp;quot;Banana&amp;quot; and &amp;quot;User gives $food to a cat&amp;quot;, but in runtime we will be&lt;br /&gt;
&amp;quot;Banana&amp;quot; and &amp;quot;User gives Banana to a cat&amp;quot; and second string would not match anything. And this is as bad&lt;br /&gt;
  self::_(&amp;quot;User gives &amp;quot;.$food.&amp;quot; to a cat&amp;quot;);// bad&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Throwing an exception because the player did a forbidden move ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// This will display a translatable red message to the player that just did some wrong action:&lt;br /&gt;
throw new BgaUserException( self::_(&#039;You must choose 3 cards&#039;) );&lt;br /&gt;
&lt;br /&gt;
// ... notice the use of BgaUserException that signals that this exception is &amp;quot;expected&amp;quot;. In theory, all exception that are expected should be translated.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Creating labels ====&lt;br /&gt;
&lt;br /&gt;
In &amp;quot;yourgame.view.php&amp;quot;, when creating the labels for the game interface used in your template (.tpl) file.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$this-&amp;gt;tpl[&#039;CARDS_FOR_YEAR_2&#039;] = self::_(&amp;quot;Your cards for year II&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Nota bene:&#039;&#039;&#039; it is recommended to set translated text in your interface client side rather than use template variables and server translation, so that translation works natively in replays (that don&#039;t have server side translations). For simple strings, the framework will handle moving the translation client side, but for more complex strings it may not work. In particular, you should not use server side translation for templates with substitution variables (or use the specific function &amp;quot;gameview_str_replace( $search, $replace, $string )&amp;quot; if not possible otherwise or for old code compatibility). Also, you should never use a &amp;quot;to_translate&amp;quot; class in your .tpl as it is used internally by the framework.&lt;br /&gt;
&lt;br /&gt;
Example with view.php:&lt;br /&gt;
in .tpl:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  &amp;lt;div id=&amp;quot;empire_title_{COLOR}&amp;quot; class=&amp;quot;side_title color_{COLOR}&amp;quot;&amp;gt;{EMPIRE_LABEL}&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
in view.php:&lt;br /&gt;
        $this-&amp;gt;page-&amp;gt;insert_block(&amp;quot;player_board&amp;quot;, array (&amp;quot;COLOR&amp;quot; =&amp;gt; $color,&amp;quot;PLAYER_NAME&amp;quot; =&amp;gt; $name,&amp;quot;PLAYER_NO&amp;quot; =&amp;gt; $no,&lt;br /&gt;
                &amp;quot;PLAYER_ID&amp;quot; =&amp;gt; $player_id, &amp;quot;CLASSES&amp;quot; =&amp;gt; $own?&amp;quot;own&amp;quot;:&amp;quot;&amp;quot;, &lt;br /&gt;
                &amp;quot;EMPIRE_LABEL&amp;quot; =&amp;gt; self::raw(gameview_str_replace(&#039;${player_name}&#039;, $name, self::_(&#039;${player_name}\&#039;s EMPIRE&#039;)))&lt;br /&gt;
              ));&lt;br /&gt;
Example with client side:&lt;br /&gt;
in .tpl:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  &amp;lt;div id=&amp;quot;empire_title_{COLOR}&amp;quot; class=&amp;quot;side_title color_{COLOR}&amp;quot;&amp;gt;Stub&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
in .js:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  for (var player_id in this.gamedatas.players) {&lt;br /&gt;
      var player_color = this.gamedatas.players[player_id].color;&lt;br /&gt;
      var player_name = this.gamedatas.players[player_id].name;&lt;br /&gt;
      $(&#039;empire_title_&#039;+player_color).innerHTML=this.format_string_recursive(_(&amp;quot;${player_name}&#039;s EMPIRE&amp;quot;), {player_name: player_name});&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Translating strings in material file ====&lt;br /&gt;
&lt;br /&gt;
Rarely, in your material.inc.php, if for example you need to use some string elements in your exceptions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// In material.inc.php, $this-&amp;gt;energies[n][&#039;nametr&#039;] has been created with the self::_() method. Now we can do this:&lt;br /&gt;
throw new BgaUserException( self::_(&amp;quot;To execute this action you need more: &amp;quot;).&#039; &#039;.$this-&amp;gt;energies[$resource_id][&#039;nametr&#039;] );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: you could also do this, so you don&#039;t need to pollute your material file&lt;br /&gt;
   throw new BgaUserException( self::_(&amp;quot;To execute this action you need more: &amp;quot;).&#039; &#039;.self::_($this-&amp;gt;energies[$resource_id][&#039;name&#039;]) );&lt;br /&gt;
&lt;br /&gt;
where $this-&amp;gt;energies[$resource_id][&#039;name&#039;] were marked in material file using regular clienttranslate function&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  $this-&amp;gt;energies = [&lt;br /&gt;
      22 =&amp;gt; [&lt;br /&gt;
          &#039;name&#039; =&amp;gt; clienttranslate(&#039;Sun&#039;)&lt;br /&gt;
          ...&lt;br /&gt;
      ]&lt;br /&gt;
  ];&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Strings in getAllDatas ====&lt;br /&gt;
&lt;br /&gt;
Rarely, in your &amp;quot;getAllDatas&amp;quot; PHP method, as the data return by this method is used only by current user.&lt;br /&gt;
&lt;br /&gt;
Note: not sure why would you send strings from the server in this case, as same can be achieved on the client usually.&lt;br /&gt;
&lt;br /&gt;
=== Function totranslate ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;totranslate( &amp;quot;my string to translate&amp;quot; ):&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This function works exactly like &#039;clienttranslate&#039;, except it tells BGA that the string is not needed on client side.&lt;br /&gt;
&lt;br /&gt;
You should not use this function, except on the following cases:&lt;br /&gt;
* Statistics name in stats.inc.php&lt;br /&gt;
* Option names and option values name in gameoptions.inc.php&lt;br /&gt;
&lt;br /&gt;
== Top Secret Undocumented Features ==&lt;br /&gt;
&lt;br /&gt;
If your string contains the clause &#039;$${value}&#039; (such as &#039;You gain $${value}.&#039;) then the translation system seems to move the position of the $ to a localized location (eg $5 in English but 5$ in French). This only seems to occur when using the argument &#039;value&#039;.&lt;br /&gt;
&lt;br /&gt;
In JavaScript, you can get the current user&#039;s language by retrieving the translation for the special string &amp;quot;$locale&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
    var lang = _(&#039;$locale&#039;); // en, fr, etc.&lt;br /&gt;
&lt;br /&gt;
== On server side - advanced (PHP) ==&lt;br /&gt;
&lt;br /&gt;
If you want to use translation system in your custom static modules, you will first need to expose the _() function :&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class mygame extends Table {&lt;br /&gt;
  // Exposing protected method translation&lt;br /&gt;
  public static function totranslate($text) {&lt;br /&gt;
    return self::_($text);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then you&#039;ll be able to use this directly in other modules by doing&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
throw new BgaUserException(mygame::totranslate(&amp;quot;Translated error from my awesome module file&amp;quot;));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Notice how the &amp;quot;totranslate&amp;quot; is also used by the static analysis to detect your string. So the following will not work :&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$msg = &amp;quot;Translated error from my awesome module file&amp;quot;;&lt;br /&gt;
throw new BgaUserException(mygame::totranslate($msg));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Analyze your project ==&lt;br /&gt;
&lt;br /&gt;
It looks super complex but there is help!&lt;br /&gt;
On studio control panel you can find a button &amp;quot;Check project&amp;quot; - it runs bunch of static analysis on your project including scanning for bad translations and missing translations.&lt;br /&gt;
It also will extact all you translation keys as translator will see them so you can double check - and run spell checker on them.&lt;br /&gt;
&lt;br /&gt;
== Other Useful Links ==&lt;br /&gt;
&lt;br /&gt;
* BLOG post about translations https://bga-devs.github.io/blog/posts/translations-summary/&lt;/div&gt;</summary>
		<author><name>Archduke</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Translations&amp;diff=12956</id>
		<title>Translations</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Translations&amp;diff=12956"/>
		<updated>2022-05-03T10:03:06Z</updated>

		<summary type="html">&lt;p&gt;Archduke: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Studio_Framework_Navigation}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Using BGA Studio, the game you create is ready to be translated to each language by the BGA community. To make this possible, you only need to specify which string must be translated and how to combine them.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
== Localization Overview ==&lt;br /&gt;
&lt;br /&gt;
Localization for BGA games happens largely on the CLIENT. Games must be developed in English and English strings are sent to the client.&lt;br /&gt;
&lt;br /&gt;
It&#039;s only at the client that your English strings will be displayed with the translation for the user&#039;s language, when such a translation exists.&lt;br /&gt;
&lt;br /&gt;
For anyone who has worked on a system where translation happens at the server and localized strings are sent to the client: you must unlearn what you have learned. Just stick with English and send the untranslated English strings. The magic happens at the client.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== How will my strings be translated? ==&lt;br /&gt;
&lt;br /&gt;
When developing your game, all strings must be in English. Strings must be coherent with the English version of the game.&lt;br /&gt;
&lt;br /&gt;
Once your game enters Beta, the BGA player community will descend upon your game like a plague of locusts and translate it into dozens of languages before you can say &amp;quot;Je ne parle pas anglais&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== What do I have to do from a programming standpoint? ==&lt;br /&gt;
&lt;br /&gt;
Not as much as you think. Read on for full details, but the golden rules are:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# Make sure that any string on the server side that needs to be translated on the client side is wrapped in a clienttranslate() function when defined. For example: $my_response = clienttranslate(&#039;Hey translators, please translate this string&#039;). clienttranslate doesn&#039;t actually do anything at all (it just passes the text through) but the translation engine searches your code for strings wrapped in that function and uses them to build the list of strings that need to be translated.&lt;br /&gt;
# On the client side, just display your text, but wrap it in _().&lt;br /&gt;
## If you pass a string constant to _() - such as _(&#039;This is my string&#039;) then the parser will automatically detect and add your string to the list of strings that need to be translated, AND it will display the local translation for it when displaying.&lt;br /&gt;
## If you pass a variable to _() - such as _(args.my_message) then MAKE SURE that the variable is set to an English string that is either defined somewhere in your PHP code in a clienttranslate() function or somewhere else in your javascript code in a _() function. As long as it is, the translators will provide translations for it, and the _() function will display the local translation of your English string.&lt;br /&gt;
# A string used as the message for notifyAllPlayers or notifyPlayer will automatically have its translation displayed on the client - you don&#039;t need to do anything EXCEPT make sure that it is wrapped in a clienttranslate() on the server, so that it gets translated.&lt;br /&gt;
# A string used as the &amp;quot;description&amp;quot; or &amp;quot;descriptionmyturn&amp;quot; for a state in your state machine will also be automatically translated on the client - you don&#039;t need to do anything EXCEPT make sure that it is wrapped in a clienttranslate() on the server, so that it gets translated.&lt;br /&gt;
# A string used in the pre-games option screen will also automatically have any translation displayed at the client - you don&#039;t need to do anything EXCEPT make sure that it is wrapped in a totranslate() on the server (nota bene: you should not use clienttranslate() here as this file is processed specifically and those strings will not be included in the game translation file but in the main site translation file - with a prefix to keep translations isolated by module - as they have to be translated on main site pages. If you need exactly the same string in your game for a client side translation, it should be declared somewhere else in your code wrapped inside a clienttranslate() to be included in the game translation file.&lt;br /&gt;
# A string used in the statistics screen will operate like a string in the pre-game options screen. It will automatically have any translation displayed at the client as long as you make sure that it is wrapped in a totranslate() on the server.&lt;br /&gt;
# If you are using parameters for a call to notifyAllPlayers or notifyPlayers, or for a state&#039;s &amp;quot;description&amp;quot; or &amp;quot;descriptionmyturn&amp;quot; and those parameters contain text that needs to be translated, you will need to tell the system to display the translated versions of them by using the &#039;i18n&#039; argument. See below for full details.&lt;br /&gt;
&lt;br /&gt;
== What strings should be translated? ==&lt;br /&gt;
&lt;br /&gt;
Every text that can be visible by the player when the game is running normally. This includes tooltips, texts on cards, error messages.&lt;br /&gt;
&lt;br /&gt;
This does NOT include error messages that are not supposed to happen (unexpected errors).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== What rules should I follow for the original English strings? ==&lt;br /&gt;
&lt;br /&gt;
For a coherent and homogeneous interface, here are some rules about ending a sentence with a final period &#039;.&#039;&lt;br /&gt;
&lt;br /&gt;
* As a general rule:&lt;br /&gt;
** If a sentence is displayed isolated in the interface =&amp;gt; no final period&lt;br /&gt;
** If a sentence is followed or could be followed by another sentence in the same interface space =&amp;gt; final period.&lt;br /&gt;
&lt;br /&gt;
* In detail:&lt;br /&gt;
** No final period:&lt;br /&gt;
*** button labels&lt;br /&gt;
*** section titles&lt;br /&gt;
*** menu elements&lt;br /&gt;
*** links triggering an isolated action&lt;br /&gt;
*** anything that is not a full sentence&lt;br /&gt;
*** current actions in the status bar&lt;br /&gt;
** Final period:&lt;br /&gt;
*** complete sentences (e.g., explanations and descriptions) that can be chained with other sentences&lt;br /&gt;
** Either a period or no period is acceptable (but this should be consistent throughout the game) for:&lt;br /&gt;
*** isolated tooltips / small sentences&lt;br /&gt;
*** game logs (no period is usually preferable)&lt;br /&gt;
*** error messages (unless there is more than one sentence in the error message; final period is mandatory in this case)&lt;br /&gt;
&lt;br /&gt;
Otherwise, you should try to follow as closely as possible the general style and format (including capitalization) used in the published English rulebook and game materials.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Focus on translating notifications ==&lt;br /&gt;
&lt;br /&gt;
Usually, translating a website is simple: you just call a function on every string you have to translate, and the string is translated in the player&#039;s language. On Board Game Arena, this is exactly the same with the &amp;quot;_( string )&amp;quot; function.&lt;br /&gt;
&lt;br /&gt;
However, there is one difference on BGA: notifications. The server is sending notifications to players, and most of the time the notifications are the same for every players, no matter what language each player is using. This is why notifications are translated on client side in the proper language, even if the strings are defined on server side.&lt;br /&gt;
&lt;br /&gt;
== How to not make translators crazy ;) ==&lt;br /&gt;
&lt;br /&gt;
* Try to reuse the exact same strings (with the same case, etc.) to minimize the number of strings to translate.&lt;br /&gt;
** &#039;&#039;&#039;Example&#039;&#039;&#039;: Consider replacing &amp;lt;pre&amp;gt;self::_(&amp;quot;Winner&amp;quot;)&amp;lt;/pre&amp;gt; and &amp;lt;pre&amp;gt;self::_(&amp;quot;Winners&amp;quot;)&amp;lt;/pre&amp;gt; (two strings to translate) with &amp;lt;pre&amp;gt;self::_(&amp;quot;Winner(s)&amp;quot;)&amp;lt;/pre&amp;gt;&lt;br /&gt;
** &#039;&#039;&#039;Example 2&#039;&#039;&#039;: &amp;lt;pre&amp;gt;clienttranslate(&amp;quot;play a card&amp;quot;)&amp;lt;/pre&amp;gt; and &amp;lt;pre&amp;gt;clienttranslate(&amp;quot;Play a card&amp;quot;)&amp;lt;/pre&amp;gt; means there will be two strings to translate.&lt;br /&gt;
* Do not mark as translatable a game element that does not have to be translated (e.g., if the name of a monster on a card is &amp;quot;Zzzzz&amp;quot;, maybe there&#039;s no need to translate it).&lt;br /&gt;
* Words does not come in the same order in each language. Thus, when you have to translate a string with an argument, do not write something like:&lt;br /&gt;
&amp;lt;pre&amp;gt;self::_(&amp;quot;First part of the string, &amp;quot;).$argument.&#039; &#039;.self::_(&amp;quot;second part of the string&amp;quot;)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Write instead:&lt;br /&gt;
&amp;lt;pre&amp;gt;sprintf( self::_(&amp;quot;First part of the string, %s second part of the string&amp;quot;), $argument )&amp;lt;/pre&amp;gt;&lt;br /&gt;
(or the equivalent &amp;quot;dojo.string.substitute&amp;quot; in Javascript)&lt;br /&gt;
* When translators are going to translate your game, the most difficult task for them is to get the context of the string to be translated. The shorter the string is, the more difficult the task is for them. As a rule of thumb, try to avoid short, insignificant strings that require knowledge of their surrounding context. You can also leave a comment on the context of the string in the translation program (English to English) if you are the developer of the game.&lt;br /&gt;
* The BGA translation policy is to be flexible on grammar. We prefer to write &amp;quot;player gets 1 coin(s)&amp;quot; rather than write two versions of the same string for plural and singular - it reduces the number of strings to translate.&lt;br /&gt;
* Instead of writing elaborate strings like &amp;quot;With the effect of ZZZ, player XXX gains a new YYY&amp;quot;, which is very difficult to translate, write strings like &amp;quot;ZZZ: XXX gets YYY&amp;quot;.&lt;br /&gt;
* Use present tense instead of past. E.g., &amp;quot;player gets wood&amp;quot; instead of &amp;quot;player got wood&amp;quot;.&lt;br /&gt;
* Avoid using gender-specific wording as much as possible. If needed be aware that [[https://forum.boardgamearena.com/viewtopic.php?f=11&amp;amp;t=19432&amp;amp;start=10#p88592 a pronoun replacement system]] is in place, and cannot work if your use &amp;quot;their&amp;quot; as a singular genderless pronoun, as it removes the information that it&#039;s singular. E.g., you should write &amp;quot;playerX returns card to *his* hand&amp;quot; or &amp;quot;playerX returns card to *his/her* hand&amp;quot; and not &amp;quot;playerX returns card to *their* hand&amp;quot; as in the 2 first case the system will substitute the proper pronoun his/her/their depending on playerX declared/undeclared gender, but in the second case it will always stay &amp;quot;their&amp;quot; whatever the player preference setting.&lt;br /&gt;
* Where two strings are identical apart from (say) a number, use the same string with a ${parameter}, and call format_string_recursive (on the client) or use args (for notifications and state descriptions) to provide the details. But *never* do that for composing multiple sentences with words: other languages have different grammar and it would most likely create untranslatable strings.&lt;br /&gt;
&lt;br /&gt;
== WARNING: Make sure your strings will be translated! ==&lt;br /&gt;
&lt;br /&gt;
For each game, our translation tool does a full scan of the code, looking for translation markers like &amp;quot;_()&amp;quot; or &amp;quot;clienttranslate()&amp;quot;. (See below for the full list of translation markers.)&lt;br /&gt;
&lt;br /&gt;
If your original string is not completely contained inside one of these markers, it won&#039;t be translated.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    // Examples: the following strings will be translated:&lt;br /&gt;
    var mystring_translated = _(&amp;quot;my string&amp;quot;);       // JS&lt;br /&gt;
    $mystring_translated = self::_(&amp;quot;my string&amp;quot;);    // PHP&lt;br /&gt;
    $mystring_translated = sprintf( self::_(&amp;quot;my string with an %s argument&amp;quot;), $argument );   // PHP&lt;br /&gt;
&lt;br /&gt;
    // Examples: the following strings WILL NOT be translated:&lt;br /&gt;
    $my_string = &amp;quot;my string&amp;quot;;&lt;br /&gt;
    $not_translated = self::_( $my_string );   // The original string is not contained within a translator marker =&amp;gt; no translation&lt;br /&gt;
    $not_translated = self::_( sprintf( &amp;quot;my string with a %s argument&amp;quot;, $argument ) ); // Ditto&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== On client side (Javascript) ==&lt;br /&gt;
&lt;br /&gt;
On client side, things are quite simple: you just have to use the &amp;quot;_()&amp;quot; function for all strings you want to translate.&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// Get a string in player&#039;s language:&lt;br /&gt;
var translated = _(&amp;quot;original english string&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
// Get a string in player&#039;s language with parameter:&lt;br /&gt;
var translated = dojo.string.substitute( _(&amp;quot;You can pick ${p} cards and discard ${d}&amp;quot;), {&lt;br /&gt;
    p: 2,&lt;br /&gt;
    d: 4&lt;br /&gt;
} );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;WARNING:&#039;&#039;&#039; in Javascript strings to translate, you should never use &#039;\n&#039;, &#039;\t&#039; or such, as it will break the translation bundle and result in all the Javascript translation to fail. In any case, the strings will result in HTML code, and such character codes won&#039;t have any impact on the HTML rendering. You should use HTML markup instead.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ANOTHER WARNING:&#039;&#039;&#039; you cannot use this function _() in the javascript object constructor, but you can achieve the same if you use it the setup method&lt;br /&gt;
&lt;br /&gt;
=== Formatting on client side ===&lt;br /&gt;
&lt;br /&gt;
Sometimes you will want to apply some formatting on the client side, but don&#039;t want to put HTML tags within the source string (which may be confusing for translators).&lt;br /&gt;
&lt;br /&gt;
This can be achieved with the `bga_format` function and Markdown-style syntax.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * @function bga_format&lt;br /&gt;
 * Replaces delimiters with HTML tags in translated text&lt;br /&gt;
 * @param {string} translated string&lt;br /&gt;
 * @param {Object} map of replacements to make, should be of the form&lt;br /&gt;
 *     {&lt;br /&gt;
 *         &#039;*&#039;: (t) =&amp;gt; t,&lt;br /&gt;
 *         &#039;_&#039;: &#039;classname&#039;,&lt;br /&gt;
 *     }&lt;br /&gt;
 *     keys are delimiters within the translated string&lt;br /&gt;
 *     values are either strings (classname of surrounding span) or function (flexible replacements)&lt;br /&gt;
 * @returns {string} Returns the original string, with replacements made.&lt;br /&gt;
 */&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// Get a string in player&#039;s language:&lt;br /&gt;
bga_format(_(&#039;You receive a *special* _tile_&#039;), {&lt;br /&gt;
    &#039;*&#039;: (t) =&amp;gt; &#039;&amp;lt;b&amp;gt;&#039; + t + &#039;&amp;lt;/b&amp;gt;&#039;,&lt;br /&gt;
    &#039;_&#039;: &#039;tile-name&#039;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The above will return something along the lines of:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
You receive a &amp;lt;b&amp;gt;special&amp;lt;/b&amp;gt; &amp;lt;span class=&amp;quot;tile-name&amp;quot;&amp;gt;tile&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Or, if the user is playing in Spanish, for example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Recibes una &amp;lt;span class=&amp;quot;tile-name&amp;quot;&amp;gt;loseta&amp;lt;/span&amp;gt; &amp;lt;b&amp;gt;especial&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Notes:&lt;br /&gt;
- The text passed to `bga_format` must still be translated using `_()`, don&#039;t forget it!&lt;br /&gt;
- The characters available to demarcate formatting are: &amp;lt;code&amp;gt;[&#039;-&#039;, &#039;[&#039;, &#039;]&#039;, &#039;{&#039;, &#039;}&#039;, &#039;(&#039;, &#039;)&#039;, &#039;*&#039;, &#039;+&#039;, &#039;?&#039;, &#039;.&#039;, &#039;,&#039;, &#039;\\&#039;, &#039;^&#039;, &#039;$&#039;, &#039;|&#039;, &#039;#&#039;, &#039; &#039;]&amp;lt;/code&amp;gt;&lt;br /&gt;
- If the replacements object is a string, the inner text will be placed within a `&amp;lt;span&amp;gt;` tag with the string as a class&lt;br /&gt;
- If the replacements object is a function, the inner text will be passed as an argument to the function, and the return value will replace the text and the delimiters&lt;br /&gt;
&lt;br /&gt;
== On server side (PHP) ==&lt;br /&gt;
&lt;br /&gt;
On PHP side, you can use 3 different functions to specify that a string must be translated.&lt;br /&gt;
&lt;br /&gt;
=== Function clienttranslate ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;clienttranslate( &#039;string to translate&#039; ):&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This function is &#039;&#039;transparent&#039;&#039;: it will return the original English string without any change. Its only purpose is to mark this string as &amp;quot;must be translated&amp;quot;, and to make sure the translated version of the string will be available on client side.&lt;br /&gt;
&lt;br /&gt;
In general, you use clienttranslate:&lt;br /&gt;
* In your &#039;&#039;&#039;states.inc.php&#039;&#039;&#039;, for the fields &amp;quot;description&amp;quot; and &amp;quot;descriptionmyturn&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
      &amp;quot;description&amp;quot; =&amp;gt; clienttranslate(&#039;${card_name}: ${actplayer} must discard 4 identical energies&#039;),&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* In &#039;&#039;&#039;material.inc.php&#039;&#039;&#039;, when defining text for game materials that must be displayed on the client side.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$this-&amp;gt;card_types = array(&lt;br /&gt;
&lt;br /&gt;
     1 =&amp;gt; array(&lt;br /&gt;
        &#039;name&#039; =&amp;gt; clienttranslate(&#039;Amulet of Air&#039;), // Thus, we can use &amp;quot;_( card_name )&amp;quot; on Javascript side.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* When sending a notification with &#039;&#039;notifyAllPlayers&#039;&#039; or &#039;&#039;notifyPlayer&#039;&#039;, in the game log string and all game log arguments that need a translation.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
     // A game log string with no argument:&lt;br /&gt;
     self::notifyAllPlayers( &#039;pickLibraryCards&#039;, clienttranslate(&#039;Everyone draw cards from their library&#039;), [] );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As a consequence there is no point passing variables to this function. E.g.:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    notif=&amp;quot;foo&amp;quot;;&lt;br /&gt;
    self::notifyAllPlayers( &#039;log&#039;, clienttranslate(notif),[]); // BAD&lt;br /&gt;
    &lt;br /&gt;
    notif=clienttranslate(&amp;quot;foo&amp;quot;);&lt;br /&gt;
    self::notifyAllPlayers( &#039;log&#039;, notif,[]); // GOOD&lt;br /&gt;
&lt;br /&gt;
    self::notifyAllPlayers( &#039;log&#039;, clienttranslate(&amp;quot;player gains ${num} gems&amp;quot;),[num=&amp;gt;2]); // BAD it is dynamic string enterpreted by php &lt;br /&gt;
    self::notifyAllPlayers( &#039;log&#039;, clienttranslate(&#039;player gains ${num} gems&#039;),[num=&amp;gt;2]); // GOOD, difference is single quotes&lt;br /&gt;
&lt;br /&gt;
    self::notifyAllPlayers( &#039;log&#039;, clienttranslate(&amp;quot;player gains &amp;quot;.${num}.&amp;quot; gems&amp;quot;),[num=&amp;gt;2]); // BAD concatenation &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Translating arguments is a little bit more complex. This uses the &#039;&#039;&#039;i18n&#039;&#039;&#039; special argument as below:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 // In the following example, we translate the game log itself, but also the &amp;quot;card_name&amp;quot; argument:&lt;br /&gt;
&lt;br /&gt;
 self::notifyAllPlayers( &#039;winPoints&#039;, clienttranslate(&#039;${card_name}: ${player_name} gains ${points} point(s)&#039;), array(&lt;br /&gt;
                &#039;i18n&#039; =&amp;gt; array( &#039;card_name&#039; ),     // &amp;lt;===== We specify here that &amp;quot;card_name&amp;quot; argument must be translated&lt;br /&gt;
                &#039;player_id&#039; =&amp;gt; $player_id,&lt;br /&gt;
                &#039;player_name&#039; =&amp;gt; self::getActivePlayerName(),&lt;br /&gt;
                &#039;points&#039; =&amp;gt; $points,&lt;br /&gt;
                &#039;card_name&#039; =&amp;gt; $this-&amp;gt;card_types[8][&#039;name&#039;] // &amp;lt;==== Here, we provide original English string.&lt;br /&gt;
            ) ); &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To ensure the translation of the i18n argument will be made, clienttranslate must have been used somewhere, for instance:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$this-&amp;gt;card_types = array(&lt;br /&gt;
...&lt;br /&gt;
     8 =&amp;gt; array(&lt;br /&gt;
        &#039;name&#039; =&amp;gt; clienttranslate(&amp;quot;Amulet of Fire&amp;quot;),&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Pay attention when using the &#039;&#039;&#039;i18n&#039;&#039;&#039; argument when translating arguments for the client: do NOT use same argument for both translations AND key codes for client-side actions (like using &#039;card_name&#039; to move it on the player board as described in the example). It&#039;s pretty obvious in the example, but it can be very tricky when translation is made at the end of the development (which is often the case). Use explicit argument names like &#039;card_name_translated&#039; by example.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;WARNING:&#039;&#039;&#039; you should NEVER use concatenation with &#039;&#039;clienttranslate&#039;&#039;, as it would result in a different string to translate at runtime than the one retrieved statically in the translation system, and so translation would not be applied. If you need to compose a string, use substitution and the i18n parameter (but you also have to pay attention not to compose sentences in a way that is dependent upon the English language specific syntax, or it may be impossible to translate correctly in another language: sometimes, you need multiple full sentences rather than relying on substitution).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Method _ (underscore) ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;self::_( &amp;quot;my string to translate&amp;quot; ):&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This function returns a string translated in the language of CURRENT user (i.e. player who send the request to the server) (be careful, this is NOT the active player).&lt;br /&gt;
&lt;br /&gt;
This can be used like self::_(&#039;bla&#039;) or this-&amp;gt;(&#039;bla&#039;). You cannot use static underscore function _(&#039;bla&#039;) in php, it is not the same, it will not translate strings from your game.&lt;br /&gt;
&lt;br /&gt;
The returned string will be surrounded by HTML tags, so you cannot use it in places where pure text is required or your string already has another html markup.&lt;br /&gt;
&lt;br /&gt;
Most of the time, you don&#039;t need to translate strings on server side, except on the following situations:&lt;br /&gt;
* Throwing user exceptions&lt;br /&gt;
* Creating the labels for the game interface used in your template&lt;br /&gt;
* Rarely, in your material.inc.php, if for example you need to use some string elements in your exceptions&lt;br /&gt;
* Rarely, in your &amp;quot;getAllDatas&amp;quot; PHP method, as the data return by this method is used only by current user&lt;br /&gt;
&lt;br /&gt;
Imporant! This function does two things:&lt;br /&gt;
* Mark string for translation&lt;br /&gt;
* Translates in runtime&lt;br /&gt;
As a consequence you absolutely cannot have $var in there! Or string concatenations.&lt;br /&gt;
I.e.&lt;br /&gt;
  $food=self::_(&amp;quot;Banana&amp;quot;);// good&lt;br /&gt;
  self::_(&amp;quot;User gives $food to a cat&amp;quot;); // bad&lt;br /&gt;
For the translator we will have two strings &amp;quot;Banana&amp;quot; and &amp;quot;User gives $food to a cat&amp;quot;, but in runtime we will be&lt;br /&gt;
&amp;quot;Banana&amp;quot; and &amp;quot;User gives Banana to a cat&amp;quot; and second string would not match anything. And this is as bad&lt;br /&gt;
  self::_(&amp;quot;User gives &amp;quot;.$food.&amp;quot; to a cat&amp;quot;);// bad&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Throwing an exception because the player did a forbidden move ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// This will display a translatable red message to the player that just did some wrong action:&lt;br /&gt;
throw new BgaUserException( self::_(&#039;You must choose 3 cards&#039;) );&lt;br /&gt;
&lt;br /&gt;
// ... notice the use of BgaUserException that signals that this exception is &amp;quot;expected&amp;quot;. In theory, all exception that are expected should be translated.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Creating labels ====&lt;br /&gt;
&lt;br /&gt;
In &amp;quot;yourgame.view.php&amp;quot;, when creating the labels for the game interface used in your template (.tpl) file.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$this-&amp;gt;tpl[&#039;CARDS_FOR_YEAR_2&#039;] = self::_(&amp;quot;Your cards for year II&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Nota bene:&#039;&#039;&#039; it is recommended to set translated text in your interface client side rather than use template variables and server translation, so that translation works natively in replays (that don&#039;t have server side translations). For simple strings, the framework will handle moving the translation client side, but for more complex strings it may not work. In particular, you should not use server side translation for templates with substitution variables (or use the specific function &amp;quot;gameview_str_replace( $search, $replace, $string )&amp;quot; if not possible otherwise or for old code compatibility). Also, you should never use a &amp;quot;to_translate&amp;quot; class in your .tpl as it is used internally by the framework.&lt;br /&gt;
&lt;br /&gt;
Example with view.php:&lt;br /&gt;
in .tpl:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  &amp;lt;div id=&amp;quot;empire_title_{COLOR}&amp;quot; class=&amp;quot;side_title color_{COLOR}&amp;quot;&amp;gt;{EMPIRE_LABEL}&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
in view.php:&lt;br /&gt;
        $this-&amp;gt;page-&amp;gt;insert_block(&amp;quot;player_board&amp;quot;, array (&amp;quot;COLOR&amp;quot; =&amp;gt; $color,&amp;quot;PLAYER_NAME&amp;quot; =&amp;gt; $name,&amp;quot;PLAYER_NO&amp;quot; =&amp;gt; $no,&lt;br /&gt;
                &amp;quot;PLAYER_ID&amp;quot; =&amp;gt; $player_id, &amp;quot;CLASSES&amp;quot; =&amp;gt; $own?&amp;quot;own&amp;quot;:&amp;quot;&amp;quot;, &lt;br /&gt;
                &amp;quot;EMPIRE_LABEL&amp;quot; =&amp;gt; self::raw(gameview_str_replace(&#039;${player_name}&#039;, $name, self::_(&#039;${player_name}\&#039;s EMPIRE&#039;)))&lt;br /&gt;
              ));&lt;br /&gt;
Example with client side:&lt;br /&gt;
in .tpl:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  &amp;lt;div id=&amp;quot;empire_title_{COLOR}&amp;quot; class=&amp;quot;side_title color_{COLOR}&amp;quot;&amp;gt;Stub&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
in .js:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  for (var player_id in this.gamedatas.players) {&lt;br /&gt;
      var player_color = this.gamedatas.players[player_id].color;&lt;br /&gt;
      var player_name = this.gamedatas.players[player_id].name;&lt;br /&gt;
      $(&#039;empire_title_&#039;+player_color).innerHTML=this.format_string_recursive(_(&amp;quot;${player_name}&#039;s EMPIRE&amp;quot;), {player_name: player_name});&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Translating strings in material file ====&lt;br /&gt;
&lt;br /&gt;
Rarely, in your material.inc.php, if for example you need to use some string elements in your exceptions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// In material.inc.php, $this-&amp;gt;energies[n][&#039;nametr&#039;] has been created with the self::_() method. Now we can do this:&lt;br /&gt;
throw new BgaUserException( self::_(&amp;quot;To execute this action you need more: &amp;quot;).&#039; &#039;.$this-&amp;gt;energies[$resource_id][&#039;nametr&#039;] );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: you could also do this, so you don&#039;t need to pollute your material file&lt;br /&gt;
   throw new BgaUserException( self::_(&amp;quot;To execute this action you need more: &amp;quot;).&#039; &#039;.self::_($this-&amp;gt;energies[$resource_id][&#039;name&#039;]) );&lt;br /&gt;
&lt;br /&gt;
where $this-&amp;gt;energies[$resource_id][&#039;name&#039;] were marked in material file using regular clienttranslate function&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  $this-&amp;gt;energies = [&lt;br /&gt;
      22 =&amp;gt; [&lt;br /&gt;
          &#039;name&#039; =&amp;gt; clienttranslate(&#039;Sun&#039;)&lt;br /&gt;
          ...&lt;br /&gt;
      ]&lt;br /&gt;
  ];&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Strings in getAllDatas ====&lt;br /&gt;
&lt;br /&gt;
Rarely, in your &amp;quot;getAllDatas&amp;quot; PHP method, as the data return by this method is used only by current user.&lt;br /&gt;
&lt;br /&gt;
Note: not sure why would you send strings from the server in this case, as same can be achieved on the client usually.&lt;br /&gt;
&lt;br /&gt;
=== Function totranslate ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;totranslate( &amp;quot;my string to translate&amp;quot; ):&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This function works exactly like &#039;clienttranslate&#039;, except it tells BGA that the string is not needed on client side.&lt;br /&gt;
&lt;br /&gt;
You should not use this function, except on the following cases:&lt;br /&gt;
* Statistics name in stats.inc.php&lt;br /&gt;
* Option names and option values name in gameoptions.inc.php&lt;br /&gt;
&lt;br /&gt;
== Top Secret Undocumented Features ==&lt;br /&gt;
&lt;br /&gt;
If your string contains the clause &#039;$${value}&#039; (such as &#039;You gain $${value}.&#039;) then the translation system seems to move the position of the $ to a localized location (eg $5 in English but 5$ in French). This only seems to occur when using the argument &#039;value&#039;.&lt;br /&gt;
&lt;br /&gt;
In JavaScript, you can get the current user&#039;s language by retrieving the translation for the special string &amp;quot;$locale&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
    var lang = _(&#039;$locale&#039;); // en, fr, etc.&lt;br /&gt;
&lt;br /&gt;
== On server side - advanced (PHP) ==&lt;br /&gt;
&lt;br /&gt;
If you want to use translation system in your custom static modules, you will first need to expose the _() function :&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class mygame extends Table {&lt;br /&gt;
  // Exposing protected method translation&lt;br /&gt;
  public static function totranslate($text) {&lt;br /&gt;
    return self::_($text);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then you&#039;ll be able to use this directly in other modules by doing&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
throw new BgaUserException(mygame::totranslate(&amp;quot;Translated error from my awesome module file&amp;quot;));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Notice how the &amp;quot;totranslate&amp;quot; is also used by the static analysis to detect your string. So the following will not work :&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$msg = &amp;quot;Translated error from my awesome module file&amp;quot;;&lt;br /&gt;
throw new BgaUserException(mygame::totranslate($msg));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Analyze your project ==&lt;br /&gt;
&lt;br /&gt;
It looks super complex but there is help!&lt;br /&gt;
On studio control panel you can find a button &amp;quot;Check project&amp;quot; - it runs bunch of static analysis on your project including scanning for bad translations and missing translations.&lt;br /&gt;
It also will extact all you translation keys as translator will see them so you can double check - and run spell checker on them.&lt;br /&gt;
&lt;br /&gt;
== Other Useful Links ==&lt;br /&gt;
&lt;br /&gt;
* BLOG post about translations https://bga-devs.github.io/blog/posts/translations-summary/&lt;/div&gt;</summary>
		<author><name>Archduke</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Translations&amp;diff=12955</id>
		<title>Translations</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Translations&amp;diff=12955"/>
		<updated>2022-05-03T09:46:14Z</updated>

		<summary type="html">&lt;p&gt;Archduke: Add TOC&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Studio_Framework_Navigation}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Using BGA Studio, the game you create is ready to be translated to each language by the BGA community. To make this possible, you only need to specify which string must be translated and how to combine them.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
== Localization Overview ==&lt;br /&gt;
&lt;br /&gt;
Localization for BGA games happens largely on the CLIENT. Games must be developed in English and English strings are sent to the client.&lt;br /&gt;
&lt;br /&gt;
It&#039;s only at the client that your English strings will be displayed with the translation for the user&#039;s language, when such a translation exists.&lt;br /&gt;
&lt;br /&gt;
For anyone who has worked on a system where translation happens at the server and localized strings are sent to the client: you must unlearn what you have learned. Just stick with English and send the untranslated English strings. The magic happens at the client.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== How will my strings be translated? ==&lt;br /&gt;
&lt;br /&gt;
When developing your game, all strings must be in English. Strings must be coherent with the English version of the game.&lt;br /&gt;
&lt;br /&gt;
Once your game enters Beta, the BGA player community will descend upon your game like a plague of locusts and translate it into dozens of languages before you can say &amp;quot;Je ne parle pas anglais&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== What do I have to do from a programming standpoint? ==&lt;br /&gt;
&lt;br /&gt;
Not as much as you think. Read on for full details, but the golden rules are:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# Make sure that any string on the server side that needs to be translated on the client side is wrapped in a clienttranslate() function when defined. For example: $my_response = clienttranslate(&#039;Hey translators, please translate this string&#039;). clienttranslate doesn&#039;t actually do anything at all (it just passes the text through) but the translation engine searches your code for strings wrapped in that function and uses them to build the list of strings that need to be translated.&lt;br /&gt;
# On the client side, just display your text, but wrap it in _().&lt;br /&gt;
## If you pass a string constant to _() - such as _(&#039;This is my string&#039;) then the parser will automatically detect and add your string to the list of strings that need to be translated, AND it will display the local translation for it when displaying.&lt;br /&gt;
## If you pass a variable to _() - such as _(args.my_message) then MAKE SURE that the variable is set to an English string that is either defined somewhere in your PHP code in a clienttranslate() function or somewhere else in your javascript code in a _() function. As long as it is, the translators will provide translations for it, and the _() function will display the local translation of your English string.&lt;br /&gt;
# A string used as the message for notifyAllPlayers or notifyPlayer will automatically have its translation displayed on the client - you don&#039;t need to do anything EXCEPT make sure that it is wrapped in a clienttranslate() on the server, so that it gets translated.&lt;br /&gt;
# A string used as the &amp;quot;description&amp;quot; or &amp;quot;descriptionmyturn&amp;quot; for a state in your state machine will also be automatically translated on the client - you don&#039;t need to do anything EXCEPT make sure that it is wrapped in a clienttranslate() on the server, so that it gets translated.&lt;br /&gt;
# A string used in the pre-games option screen will also automatically have any translation displayed at the client - you don&#039;t need to do anything EXCEPT make sure that it is wrapped in a totranslate() on the server (nota bene: you should not use clienttranslate() here as this file is processed specifically and those strings will not be included in the game translation file but in the main site translation file - with a prefix to keep translations isolated by module - as they have to be translated on main site pages. If you need exactly the same string in your game for a client side translation, it should be declared somewhere else in your code wrapped inside a clienttranslate() to be included in the game translation file.&lt;br /&gt;
# A string used in the statistics screen will operate like a string in the pre-game options screen. It will automatically have any translation displayed at the client as long as you make sure that it is wrapped in a totranslate() on the server.&lt;br /&gt;
# If you are using parameters for a call to notifyAllPlayers or notifyPlayers, or for a state&#039;s &amp;quot;description&amp;quot; or &amp;quot;descriptionmyturn&amp;quot; and those parameters contain text that needs to be translated, you will need to tell the system to display the translated versions of them by using the &#039;i18n&#039; argument. See below for full details.&lt;br /&gt;
&lt;br /&gt;
== What strings should be translated? ==&lt;br /&gt;
&lt;br /&gt;
Every text that can be visible by the player when the game is running normally. This includes tooltips, texts on cards, error messages.&lt;br /&gt;
&lt;br /&gt;
This does NOT include error messages that are not supposed to happen (unexpected errors).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== What rules should I follow for the original English strings? ==&lt;br /&gt;
&lt;br /&gt;
For a coherent and homogeneous interface, here are some rules about ending a sentence with a final period &#039;.&#039;&lt;br /&gt;
&lt;br /&gt;
* As a general rule:&lt;br /&gt;
** If a sentence is displayed isolated in the interface =&amp;gt; no final period&lt;br /&gt;
** If a sentence is followed or could be followed by another sentence in the same interface space =&amp;gt; final period.&lt;br /&gt;
&lt;br /&gt;
* In detail:&lt;br /&gt;
** No final period:&lt;br /&gt;
*** button labels&lt;br /&gt;
*** section titles&lt;br /&gt;
*** menu elements&lt;br /&gt;
*** links triggering an isolated action&lt;br /&gt;
*** anything that is not a full sentence&lt;br /&gt;
*** current actions in the status bar&lt;br /&gt;
** Final period:&lt;br /&gt;
*** complete sentences (e.g., explanations and descriptions) that can be chained with other sentences&lt;br /&gt;
** Either a period or no period is acceptable (but this should be consistent throughout the game) for:&lt;br /&gt;
*** isolated tooltips / small sentences&lt;br /&gt;
*** game logs (no period is usually preferable)&lt;br /&gt;
*** error messages (unless there is more than one sentence in the error message; final period is mandatory in this case)&lt;br /&gt;
&lt;br /&gt;
Otherwise, you should try to follow as closely as possible the general style and format (including capitalization) used in the published English rulebook and game materials.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Focus on translating notifications ==&lt;br /&gt;
&lt;br /&gt;
Usually, translating a website is simple: you just call a function on every string you have to translate, and the string is translated in the player&#039;s language. On Board Game Arena, this is exactly the same with the &amp;quot;_( string )&amp;quot; function.&lt;br /&gt;
&lt;br /&gt;
However, there is one difference on BGA: notifications. The server is sending notifications to players, and most of the time the notifications are the same for every players, no matter what language each player is using. This is why notifications are translated on client side in the proper language, even if the strings are defined on server side.&lt;br /&gt;
&lt;br /&gt;
== How to not make translators crazy ;) ==&lt;br /&gt;
&lt;br /&gt;
* Try to reuse the exact same strings (with the same case, etc.) to minimize the number of strings to translate.&lt;br /&gt;
** &#039;&#039;&#039;Example&#039;&#039;&#039;: Consider replacing &amp;lt;pre&amp;gt;self::_(&amp;quot;Winner&amp;quot;)&amp;lt;/pre&amp;gt; and &amp;lt;pre&amp;gt;self::_(&amp;quot;Winners&amp;quot;)&amp;lt;/pre&amp;gt; (two strings to translate) with &amp;lt;pre&amp;gt;self::_(&amp;quot;Winner(s)&amp;quot;)&amp;lt;/pre&amp;gt;&lt;br /&gt;
** &#039;&#039;&#039;Example 2&#039;&#039;&#039;: &amp;lt;pre&amp;gt;clienttranslate(&amp;quot;play a card&amp;quot;)&amp;lt;/pre&amp;gt; and &amp;lt;pre&amp;gt;clienttranslate(&amp;quot;Play a card&amp;quot;)&amp;lt;/pre&amp;gt; means there will be two strings to translate.&lt;br /&gt;
* Do not mark as translatable a game element that does not have to be translated (e.g., if the name of a monster on a card is &amp;quot;Zzzzz&amp;quot;, maybe there&#039;s no need to translate it).&lt;br /&gt;
* Words does not come in the same order in each language. Thus, when you have to translate a string with an argument, do not write something like:&lt;br /&gt;
&amp;lt;pre&amp;gt;self::_(&amp;quot;First part of the string, &amp;quot;).$argument.&#039; &#039;.self::_(&amp;quot;second part of the string&amp;quot;)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Write instead:&lt;br /&gt;
&amp;lt;pre&amp;gt;sprintf( self::_(&amp;quot;First part of the string, %s second part of the string&amp;quot;), $argument )&amp;lt;/pre&amp;gt;&lt;br /&gt;
(or the equivalent &amp;quot;dojo.string.substitute&amp;quot; in Javascript)&lt;br /&gt;
* When translators are going to translate your game, the most difficult task for them is to get the context of the string to be translated. The shorter the string is, the more difficult the task is for them. As a rule of thumb, try to avoid short, insignificant strings that require knowledge of their surrounding context. You can also leave a comment on the context of the string in the translation program (English to English) if you are the developer of the game.&lt;br /&gt;
* The BGA translation policy is to be flexible on grammar. We prefer to write &amp;quot;player gets 1 coin(s)&amp;quot; rather than write two versions of the same string for plural and singular - it reduces the number of strings to translate.&lt;br /&gt;
* Instead of writing elaborate strings like &amp;quot;With the effect of ZZZ, player XXX gains a new YYY&amp;quot;, which is very difficult to translate, write strings like &amp;quot;ZZZ: XXX gets YYY&amp;quot;.&lt;br /&gt;
* Use present tense instead of past. E.g., &amp;quot;player gets wood&amp;quot; instead of &amp;quot;player got wood&amp;quot;.&lt;br /&gt;
* Avoid using gender-specific wording as much as possible. If needed be aware that [[https://forum.boardgamearena.com/viewtopic.php?f=11&amp;amp;t=19432&amp;amp;start=10#p88592 a pronoun replacement system]] is in place, and cannot work if your use &amp;quot;their&amp;quot; as a singular genderless pronoun, as it removes the information that it&#039;s singular. E.g., you should write &amp;quot;playerX returns card to *his* hand&amp;quot; or &amp;quot;playerX returns card to *his/her* hand&amp;quot; and not &amp;quot;playerX returns card to *their* hand&amp;quot; as in the 2 first case the system will substitute the proper pronoun his/her/their depending on playerX declared/undeclared gender, but in the second case it will always stay &amp;quot;their&amp;quot; whatever the player preference setting.&lt;br /&gt;
* Where two strings are identical apart from (say) a number, use the same string with a ${parameter}, and call format_string_recursive (on the client) or use args (for notifications and state descriptions) to provide the details. But *never* do that for composing multiple sentences with words: other languages have different grammar and it would most likely create untranslatable strings.&lt;br /&gt;
&lt;br /&gt;
== WARNING: Make sure your strings will be translated! ==&lt;br /&gt;
&lt;br /&gt;
For each game, our translation tool does a full scan of the code, looking for translation markers like &amp;quot;_()&amp;quot; or &amp;quot;clienttranslate()&amp;quot;. (See below for the full list of translation markers.)&lt;br /&gt;
&lt;br /&gt;
If your original string is not completely contained inside one of these markers, it won&#039;t be translated.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    // Examples: the following strings will be translated:&lt;br /&gt;
    var mystring_translated = _(&amp;quot;my string&amp;quot;);       // JS&lt;br /&gt;
    $mystring_translated = self::_(&amp;quot;my string&amp;quot;);    // PHP&lt;br /&gt;
    $mystring_translated = sprintf( self::_(&amp;quot;my string with an %s argument&amp;quot;), $argument );   // PHP&lt;br /&gt;
&lt;br /&gt;
    // Examples: the following strings WILL NOT be translated:&lt;br /&gt;
    $my_string = &amp;quot;my string&amp;quot;;&lt;br /&gt;
    $not_translated = self::_( $my_string );   // The original string is not contained within a translator marker =&amp;gt; no translation&lt;br /&gt;
    $not_translated = self::_( sprintf( &amp;quot;my string with a %s argument&amp;quot;, $argument ) ); // Ditto&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== On client side (Javascript) ==&lt;br /&gt;
&lt;br /&gt;
On client side, things are quite simple: you just have to use the &amp;quot;_()&amp;quot; function for all strings you want to translate.&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// Get a string in player&#039;s language:&lt;br /&gt;
var translated = _(&amp;quot;original english string&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
// Get a string in player&#039;s language with parameter:&lt;br /&gt;
var translated = dojo.string.substitute( _(&amp;quot;You can pick ${p} cards and discard ${d}&amp;quot;), {&lt;br /&gt;
    p: 2,&lt;br /&gt;
    d: 4&lt;br /&gt;
} );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;WARNING:&#039;&#039;&#039; in Javascript strings to translate, you should never use &#039;\n&#039;, &#039;\t&#039; or such, as it will break the translation bundle and result in all the Javascript translation to fail. In any case, the strings will result in HTML code, and such character codes won&#039;t have any impact on the HTML rendering. You should use HTML markup instead.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ANOTHER WARNING:&#039;&#039;&#039; you cannot use this function _() in the javascript object constructor, but you can achieve the same if you use it the setup method&lt;br /&gt;
&lt;br /&gt;
== On server side (PHP) ==&lt;br /&gt;
&lt;br /&gt;
On PHP side, you can use 3 different functions to specify that a string must be translated.&lt;br /&gt;
&lt;br /&gt;
=== Function clienttranslate ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;clienttranslate( &#039;string to translate&#039; ):&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This function is &#039;&#039;transparent&#039;&#039;: it will return the original English string without any change. Its only purpose is to mark this string as &amp;quot;must be translated&amp;quot;, and to make sure the translated version of the string will be available on client side.&lt;br /&gt;
&lt;br /&gt;
In general, you use clienttranslate:&lt;br /&gt;
* In your &#039;&#039;&#039;states.inc.php&#039;&#039;&#039;, for the fields &amp;quot;description&amp;quot; and &amp;quot;descriptionmyturn&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
      &amp;quot;description&amp;quot; =&amp;gt; clienttranslate(&#039;${card_name}: ${actplayer} must discard 4 identical energies&#039;),&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* In &#039;&#039;&#039;material.inc.php&#039;&#039;&#039;, when defining text for game materials that must be displayed on the client side.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$this-&amp;gt;card_types = array(&lt;br /&gt;
&lt;br /&gt;
     1 =&amp;gt; array(&lt;br /&gt;
        &#039;name&#039; =&amp;gt; clienttranslate(&#039;Amulet of Air&#039;), // Thus, we can use &amp;quot;_( card_name )&amp;quot; on Javascript side.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* When sending a notification with &#039;&#039;notifyAllPlayers&#039;&#039; or &#039;&#039;notifyPlayer&#039;&#039;, in the game log string and all game log arguments that need a translation.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
     // A game log string with no argument:&lt;br /&gt;
     self::notifyAllPlayers( &#039;pickLibraryCards&#039;, clienttranslate(&#039;Everyone draw cards from their library&#039;), [] );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As a consequence there is no point passing variables to this function. E.g.:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    notif=&amp;quot;foo&amp;quot;;&lt;br /&gt;
    self::notifyAllPlayers( &#039;log&#039;, clienttranslate(notif),[]); // BAD&lt;br /&gt;
    &lt;br /&gt;
    notif=clienttranslate(&amp;quot;foo&amp;quot;);&lt;br /&gt;
    self::notifyAllPlayers( &#039;log&#039;, notif,[]); // GOOD&lt;br /&gt;
&lt;br /&gt;
    self::notifyAllPlayers( &#039;log&#039;, clienttranslate(&amp;quot;player gains ${num} gems&amp;quot;),[num=&amp;gt;2]); // BAD it is dynamic string enterpreted by php &lt;br /&gt;
    self::notifyAllPlayers( &#039;log&#039;, clienttranslate(&#039;player gains ${num} gems&#039;),[num=&amp;gt;2]); // GOOD, difference is single quotes&lt;br /&gt;
&lt;br /&gt;
    self::notifyAllPlayers( &#039;log&#039;, clienttranslate(&amp;quot;player gains &amp;quot;.${num}.&amp;quot; gems&amp;quot;),[num=&amp;gt;2]); // BAD concatenation &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Translating arguments is a little bit more complex. This uses the &#039;&#039;&#039;i18n&#039;&#039;&#039; special argument as below:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 // In the following example, we translate the game log itself, but also the &amp;quot;card_name&amp;quot; argument:&lt;br /&gt;
&lt;br /&gt;
 self::notifyAllPlayers( &#039;winPoints&#039;, clienttranslate(&#039;${card_name}: ${player_name} gains ${points} point(s)&#039;), array(&lt;br /&gt;
                &#039;i18n&#039; =&amp;gt; array( &#039;card_name&#039; ),     // &amp;lt;===== We specify here that &amp;quot;card_name&amp;quot; argument must be translated&lt;br /&gt;
                &#039;player_id&#039; =&amp;gt; $player_id,&lt;br /&gt;
                &#039;player_name&#039; =&amp;gt; self::getActivePlayerName(),&lt;br /&gt;
                &#039;points&#039; =&amp;gt; $points,&lt;br /&gt;
                &#039;card_name&#039; =&amp;gt; $this-&amp;gt;card_types[8][&#039;name&#039;] // &amp;lt;==== Here, we provide original English string.&lt;br /&gt;
            ) ); &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To ensure the translation of the i18n argument will be made, clienttranslate must have been used somewhere, for instance:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$this-&amp;gt;card_types = array(&lt;br /&gt;
...&lt;br /&gt;
     8 =&amp;gt; array(&lt;br /&gt;
        &#039;name&#039; =&amp;gt; clienttranslate(&amp;quot;Amulet of Fire&amp;quot;),&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Pay attention when using the &#039;&#039;&#039;i18n&#039;&#039;&#039; argument when translating arguments for the client: do NOT use same argument for both translations AND key codes for client-side actions (like using &#039;card_name&#039; to move it on the player board as described in the example). It&#039;s pretty obvious in the example, but it can be very tricky when translation is made at the end of the development (which is often the case). Use explicit argument names like &#039;card_name_translated&#039; by example.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;WARNING:&#039;&#039;&#039; you should NEVER use concatenation with &#039;&#039;clienttranslate&#039;&#039;, as it would result in a different string to translate at runtime than the one retrieved statically in the translation system, and so translation would not be applied. If you need to compose a string, use substitution and the i18n parameter (but you also have to pay attention not to compose sentences in a way that is dependent upon the English language specific syntax, or it may be impossible to translate correctly in another language: sometimes, you need multiple full sentences rather than relying on substitution).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Method _ (underscore) ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;self::_( &amp;quot;my string to translate&amp;quot; ):&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This function returns a string translated in the language of CURRENT user (i.e. player who send the request to the server) (be careful, this is NOT the active player).&lt;br /&gt;
&lt;br /&gt;
This can be used like self::_(&#039;bla&#039;) or this-&amp;gt;(&#039;bla&#039;). You cannot use static underscore function _(&#039;bla&#039;) in php, it is not the same, it will not translate strings from your game.&lt;br /&gt;
&lt;br /&gt;
The returned string will be surrounded by HTML tags, so you cannot use it in places where pure text is required or your string already has another html markup.&lt;br /&gt;
&lt;br /&gt;
Most of the time, you don&#039;t need to translate strings on server side, except on the following situations:&lt;br /&gt;
* Throwing user exceptions&lt;br /&gt;
* Creating the labels for the game interface used in your template&lt;br /&gt;
* Rarely, in your material.inc.php, if for example you need to use some string elements in your exceptions&lt;br /&gt;
* Rarely, in your &amp;quot;getAllDatas&amp;quot; PHP method, as the data return by this method is used only by current user&lt;br /&gt;
&lt;br /&gt;
Imporant! This function does two things:&lt;br /&gt;
* Mark string for translation&lt;br /&gt;
* Translates in runtime&lt;br /&gt;
As a consequence you absolutely cannot have $var in there! Or string concatenations.&lt;br /&gt;
I.e.&lt;br /&gt;
  $food=self::_(&amp;quot;Banana&amp;quot;);// good&lt;br /&gt;
  self::_(&amp;quot;User gives $food to a cat&amp;quot;); // bad&lt;br /&gt;
For the translator we will have two strings &amp;quot;Banana&amp;quot; and &amp;quot;User gives $food to a cat&amp;quot;, but in runtime we will be&lt;br /&gt;
&amp;quot;Banana&amp;quot; and &amp;quot;User gives Banana to a cat&amp;quot; and second string would not match anything. And this is as bad&lt;br /&gt;
  self::_(&amp;quot;User gives &amp;quot;.$food.&amp;quot; to a cat&amp;quot;);// bad&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Throwing an exception because the player did a forbidden move ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// This will display a translatable red message to the player that just did some wrong action:&lt;br /&gt;
throw new BgaUserException( self::_(&#039;You must choose 3 cards&#039;) );&lt;br /&gt;
&lt;br /&gt;
// ... notice the use of BgaUserException that signals that this exception is &amp;quot;expected&amp;quot;. In theory, all exception that are expected should be translated.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Creating labels ====&lt;br /&gt;
&lt;br /&gt;
In &amp;quot;yourgame.view.php&amp;quot;, when creating the labels for the game interface used in your template (.tpl) file.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$this-&amp;gt;tpl[&#039;CARDS_FOR_YEAR_2&#039;] = self::_(&amp;quot;Your cards for year II&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Nota bene:&#039;&#039;&#039; it is recommended to set translated text in your interface client side rather than use template variables and server translation, so that translation works natively in replays (that don&#039;t have server side translations). For simple strings, the framework will handle moving the translation client side, but for more complex strings it may not work. In particular, you should not use server side translation for templates with substitution variables (or use the specific function &amp;quot;gameview_str_replace( $search, $replace, $string )&amp;quot; if not possible otherwise or for old code compatibility). Also, you should never use a &amp;quot;to_translate&amp;quot; class in your .tpl as it is used internally by the framework.&lt;br /&gt;
&lt;br /&gt;
Example with view.php:&lt;br /&gt;
in .tpl:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  &amp;lt;div id=&amp;quot;empire_title_{COLOR}&amp;quot; class=&amp;quot;side_title color_{COLOR}&amp;quot;&amp;gt;{EMPIRE_LABEL}&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
in view.php:&lt;br /&gt;
        $this-&amp;gt;page-&amp;gt;insert_block(&amp;quot;player_board&amp;quot;, array (&amp;quot;COLOR&amp;quot; =&amp;gt; $color,&amp;quot;PLAYER_NAME&amp;quot; =&amp;gt; $name,&amp;quot;PLAYER_NO&amp;quot; =&amp;gt; $no,&lt;br /&gt;
                &amp;quot;PLAYER_ID&amp;quot; =&amp;gt; $player_id, &amp;quot;CLASSES&amp;quot; =&amp;gt; $own?&amp;quot;own&amp;quot;:&amp;quot;&amp;quot;, &lt;br /&gt;
                &amp;quot;EMPIRE_LABEL&amp;quot; =&amp;gt; self::raw(gameview_str_replace(&#039;${player_name}&#039;, $name, self::_(&#039;${player_name}\&#039;s EMPIRE&#039;)))&lt;br /&gt;
              ));&lt;br /&gt;
Example with client side:&lt;br /&gt;
in .tpl:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  &amp;lt;div id=&amp;quot;empire_title_{COLOR}&amp;quot; class=&amp;quot;side_title color_{COLOR}&amp;quot;&amp;gt;Stub&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
in .js:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  for (var player_id in this.gamedatas.players) {&lt;br /&gt;
      var player_color = this.gamedatas.players[player_id].color;&lt;br /&gt;
      var player_name = this.gamedatas.players[player_id].name;&lt;br /&gt;
      $(&#039;empire_title_&#039;+player_color).innerHTML=this.format_string_recursive(_(&amp;quot;${player_name}&#039;s EMPIRE&amp;quot;), {player_name: player_name});&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Translating strings in material file ====&lt;br /&gt;
&lt;br /&gt;
Rarely, in your material.inc.php, if for example you need to use some string elements in your exceptions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// In material.inc.php, $this-&amp;gt;energies[n][&#039;nametr&#039;] has been created with the self::_() method. Now we can do this:&lt;br /&gt;
throw new BgaUserException( self::_(&amp;quot;To execute this action you need more: &amp;quot;).&#039; &#039;.$this-&amp;gt;energies[$resource_id][&#039;nametr&#039;] );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: you could also do this, so you don&#039;t need to pollute your material file&lt;br /&gt;
   throw new BgaUserException( self::_(&amp;quot;To execute this action you need more: &amp;quot;).&#039; &#039;.self::_($this-&amp;gt;energies[$resource_id][&#039;name&#039;]) );&lt;br /&gt;
&lt;br /&gt;
where $this-&amp;gt;energies[$resource_id][&#039;name&#039;] were marked in material file using regular clienttranslate function&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  $this-&amp;gt;energies = [&lt;br /&gt;
      22 =&amp;gt; [&lt;br /&gt;
          &#039;name&#039; =&amp;gt; clienttranslate(&#039;Sun&#039;)&lt;br /&gt;
          ...&lt;br /&gt;
      ]&lt;br /&gt;
  ];&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Strings in getAllDatas ====&lt;br /&gt;
&lt;br /&gt;
Rarely, in your &amp;quot;getAllDatas&amp;quot; PHP method, as the data return by this method is used only by current user.&lt;br /&gt;
&lt;br /&gt;
Note: not sure why would you send strings from the server in this case, as same can be achieved on the client usually.&lt;br /&gt;
&lt;br /&gt;
=== Function totranslate ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;totranslate( &amp;quot;my string to translate&amp;quot; ):&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This function works exactly like &#039;clienttranslate&#039;, except it tells BGA that the string is not needed on client side.&lt;br /&gt;
&lt;br /&gt;
You should not use this function, except on the following cases:&lt;br /&gt;
* Statistics name in stats.inc.php&lt;br /&gt;
* Option names and option values name in gameoptions.inc.php&lt;br /&gt;
&lt;br /&gt;
== Top Secret Undocumented Features ==&lt;br /&gt;
&lt;br /&gt;
If your string contains the clause &#039;$${value}&#039; (such as &#039;You gain $${value}.&#039;) then the translation system seems to move the position of the $ to a localized location (eg $5 in English but 5$ in French). This only seems to occur when using the argument &#039;value&#039;.&lt;br /&gt;
&lt;br /&gt;
In JavaScript, you can get the current user&#039;s language by retrieving the translation for the special string &amp;quot;$locale&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
    var lang = _(&#039;$locale&#039;); // en, fr, etc.&lt;br /&gt;
&lt;br /&gt;
== On server side - advanced (PHP) ==&lt;br /&gt;
&lt;br /&gt;
If you want to use translation system in your custom static modules, you will first need to expose the _() function :&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class mygame extends Table {&lt;br /&gt;
  // Exposing protected method translation&lt;br /&gt;
  public static function totranslate($text) {&lt;br /&gt;
    return self::_($text);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then you&#039;ll be able to use this directly in other modules by doing&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
throw new BgaUserException(mygame::totranslate(&amp;quot;Translated error from my awesome module file&amp;quot;));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Notice how the &amp;quot;totranslate&amp;quot; is also used by the static analysis to detect your string. So the following will not work :&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$msg = &amp;quot;Translated error from my awesome module file&amp;quot;;&lt;br /&gt;
throw new BgaUserException(mygame::totranslate($msg));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Analyze your project ==&lt;br /&gt;
&lt;br /&gt;
It looks super complex but there is help!&lt;br /&gt;
On studio control panel you can find a button &amp;quot;Check project&amp;quot; - it runs bunch of static analysis on your project including scanning for bad translations and missing translations.&lt;br /&gt;
It also will extact all you translation keys as translator will see them so you can double check - and run spell checker on them.&lt;br /&gt;
&lt;br /&gt;
== Other Useful Links ==&lt;br /&gt;
&lt;br /&gt;
* BLOG post about translations https://bga-devs.github.io/blog/posts/translations-summary/&lt;/div&gt;</summary>
		<author><name>Archduke</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Studio:Home&amp;diff=12414</id>
		<title>Studio:Home</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Studio:Home&amp;diff=12414"/>
		<updated>2022-03-25T19:23:20Z</updated>

		<summary type="html">&lt;p&gt;Archduke: Created page with &amp;quot;Placeholder content&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Placeholder content&lt;/div&gt;</summary>
		<author><name>Archduke</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Gamehelpfeastforodin&amp;diff=9412</id>
		<title>Gamehelpfeastforodin</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Gamehelpfeastforodin&amp;diff=9412"/>
		<updated>2021-09-18T08:15:00Z</updated>

		<summary type="html">&lt;p&gt;Archduke: How to play A Feast for Odin&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Placing goods==&lt;br /&gt;
&lt;br /&gt;
There are two placement controls available for the game. You can switch between them in options, but by default drag’n’drop will be used on desktop, and crosshair on mobile.&lt;br /&gt;
&lt;br /&gt;
===Drag’n’drop===&lt;br /&gt;
&lt;br /&gt;
Drag goods from your inventory to a board. You can click the expand icon above a board to make this easier. You can also drag ore and silver to boards in the same way.&lt;br /&gt;
&lt;br /&gt;
===Crosshair===&lt;br /&gt;
&lt;br /&gt;
Click the expand icon above a board to start placing goods. Click a good, ore or silver to select it, then click on the board to place it. There are buttons to rotate or cancel the last selected piece.&lt;br /&gt;
&lt;br /&gt;
===Feast===&lt;br /&gt;
&lt;br /&gt;
The feast board can only be saved during the Feast phase. You can provisionally place goods on the board outside of this phase, you just can’t save.&lt;br /&gt;
&lt;br /&gt;
===Boats and houses===&lt;br /&gt;
&lt;br /&gt;
To place ore on boats, or stone and wood in sheds and houses, simply click the appropriate slot. On mobile, you may find you need to tap twice.&lt;br /&gt;
&lt;br /&gt;
==Raiding and Pillaging==&lt;br /&gt;
&lt;br /&gt;
Once you roll the die for the first time, you cannot undo your turn. Before clicking “success”, make sure you select as many “sword” cards and stone as you would like to spend. After clicking “success”, you can select the reward you would like.&lt;/div&gt;</summary>
		<author><name>Archduke</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Your_game_state_machine:_states.inc.php&amp;diff=1147</id>
		<title>Your game state machine: states.inc.php</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Your_game_state_machine:_states.inc.php&amp;diff=1147"/>
		<updated>2014-06-16T09:38:51Z</updated>

		<summary type="html">&lt;p&gt;Archduke: /* Private infos in args */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
This file describes the game states machine of your game (all the game states properties, and the transitions to get from one state to another).&lt;br /&gt;
&lt;br /&gt;
Important: to understand the game state machine, the best is to read this presentation first:&lt;br /&gt;
&lt;br /&gt;
[http://www.slideshare.net/boardgamearena/bga-studio-focus-on-bga-game-state-machine Focus on BGA game state machine]&lt;br /&gt;
&lt;br /&gt;
== Overall structure ==&lt;br /&gt;
&lt;br /&gt;
The machine states is described by a PHP associative array.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$machinestates = array(&lt;br /&gt;
&lt;br /&gt;
    // The initial state. Please do not modify.&lt;br /&gt;
    1 =&amp;gt; array(&lt;br /&gt;
        &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;gameSetup&amp;quot;,&lt;br /&gt;
        &amp;quot;description&amp;quot; =&amp;gt; clienttranslate(&amp;quot;Game setup&amp;quot;),&lt;br /&gt;
        &amp;quot;type&amp;quot; =&amp;gt; &amp;quot;manager&amp;quot;,&lt;br /&gt;
        &amp;quot;action&amp;quot; =&amp;gt; &amp;quot;stGameSetup&amp;quot;,&lt;br /&gt;
        &amp;quot;transitions&amp;quot; =&amp;gt; array( &amp;quot;&amp;quot; =&amp;gt; 2 )&lt;br /&gt;
    ),&lt;br /&gt;
    &lt;br /&gt;
    // Note: ID=2 =&amp;gt; your first state&lt;br /&gt;
&lt;br /&gt;
    2 =&amp;gt; array(&lt;br /&gt;
    		&amp;quot;name&amp;quot; =&amp;gt; &amp;quot;playerTurn&amp;quot;,&lt;br /&gt;
    		&amp;quot;description&amp;quot; =&amp;gt; clienttranslate(&#039;${actplayer} must play a card or pass&#039;),&lt;br /&gt;
    		&amp;quot;descriptionmyturn&amp;quot; =&amp;gt; clienttranslate(&#039;${you} must play a card or pass&#039;),&lt;br /&gt;
    		&amp;quot;type&amp;quot; =&amp;gt; &amp;quot;activeplayer&amp;quot;,&lt;br /&gt;
    		&amp;quot;possibleactions&amp;quot; =&amp;gt; array( &amp;quot;playCard&amp;quot;, &amp;quot;pass&amp;quot; ),&lt;br /&gt;
    		&amp;quot;transitions&amp;quot; =&amp;gt; array( &amp;quot;playCard&amp;quot; =&amp;gt; 2, &amp;quot;pass&amp;quot; =&amp;gt; 2 )&lt;br /&gt;
    ),&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Syntax ==&lt;br /&gt;
&lt;br /&gt;
=== id ===&lt;br /&gt;
&lt;br /&gt;
The keys determine game states IDs (in the example above: 1 and 2).&lt;br /&gt;
&lt;br /&gt;
IDs must be positive integers.&lt;br /&gt;
&lt;br /&gt;
ID=1 is reserved for the first game state and should not be used (and you must not modify it).&lt;br /&gt;
&lt;br /&gt;
ID=99 is reserved for the last game state of the game (end of the game) (and you must not modify it).&lt;br /&gt;
&lt;br /&gt;
Note: you may use any ID, even ID greater than 100. But you cannot use 1 and 99.&lt;br /&gt;
&lt;br /&gt;
Note²: You can&#039;t of course use the same ID twice.&lt;br /&gt;
&lt;br /&gt;
=== name ===&lt;br /&gt;
&lt;br /&gt;
(mandatory)&lt;br /&gt;
&lt;br /&gt;
The name of a game state is used to identify it in your game logic.&lt;br /&gt;
&lt;br /&gt;
Several game states can share the same name, however this is not recommended.&lt;br /&gt;
&lt;br /&gt;
PHP example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
// Get current game state&lt;br /&gt;
$state = $this-&amp;gt;gamestate-&amp;gt;state();&lt;br /&gt;
if( $state[&#039;name&#039;] == &#039;myGameState&#039; )&lt;br /&gt;
{&lt;br /&gt;
...&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
JS example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        onEnteringState: function( stateName, args )&lt;br /&gt;
        {&lt;br /&gt;
            console.log( &#039;Entering state: &#039;+stateName );&lt;br /&gt;
            &lt;br /&gt;
            switch( stateName )&lt;br /&gt;
            case &#039;myGameState&#039;:&lt;br /&gt;
            &lt;br /&gt;
                // Do some stuff at the beginning at this game state&lt;br /&gt;
                ....&lt;br /&gt;
                &lt;br /&gt;
                break;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== type ===&lt;br /&gt;
&lt;br /&gt;
(mandatory)&lt;br /&gt;
&lt;br /&gt;
You can use 3 types of game states:&lt;br /&gt;
* activeplayer (1 player is active and must play)&lt;br /&gt;
* multipleactiveplayer (1..N players can be active and must play)&lt;br /&gt;
* game (no player is active. This is a transitional state to do something automatic specified by game rules)&lt;br /&gt;
&lt;br /&gt;
=== description ===&lt;br /&gt;
&lt;br /&gt;
(mandatory)&lt;br /&gt;
&lt;br /&gt;
The description is the string that is displayed in the main action bar (top of the screen) when the state is active.&lt;br /&gt;
&lt;br /&gt;
When a string is specified as a description, you must use &amp;quot;clienttranslate&amp;quot; in order the string can be translate on the client side:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 		&amp;quot;description&amp;quot; =&amp;gt; clienttranslate(&#039;${actplayer} must play a card or pass&#039;),&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the description string, you can use ${actplayer} to refer to the active player.&lt;br /&gt;
&lt;br /&gt;
You can also use custom arguments in your description. These custom arguments correspond to values returned by your &amp;quot;args&amp;quot; PHP method (see below &amp;quot;args&amp;quot; field).&lt;br /&gt;
&lt;br /&gt;
Example of custom field:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In states.inc.php:&lt;br /&gt;
        &amp;quot;description&amp;quot; =&amp;gt; clienttranslate(&#039;${actplayer} must choose ${nbr} identical energies&#039;),&lt;br /&gt;
        &amp;quot;args&amp;quot; =&amp;gt; &amp;quot;argMyArgumentMethod&amp;quot;&lt;br /&gt;
&lt;br /&gt;
In mygame.game.php:&lt;br /&gt;
    function argMyArgumentMethod()&lt;br /&gt;
    {&lt;br /&gt;
        return array(&lt;br /&gt;
            &#039;nbr&#039; =&amp;gt; 2  // In this case ${nbr} in the description will be replaced by &amp;quot;2&amp;quot;&lt;br /&gt;
        );    &lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: You may specify an empty string (&amp;quot;&amp;quot;) here if it never happens that the game remains in this state (ie: if this state immediately jump to another state when activated).&lt;br /&gt;
&lt;br /&gt;
Note²: Usually, you specify a string for &amp;quot;activeplayer&amp;quot; and &amp;quot;multipleactiveplayer&amp;quot; game states, and you specify an empty string for &amp;quot;game&amp;quot; game states. BUT, if you are using synchronous notifications, the client can remains few seconds on a &amp;quot;game&amp;quot; type game state, and in this case this may be useful to display a description in the status bar during this state.&lt;br /&gt;
&lt;br /&gt;
=== descriptionmyturn ===&lt;br /&gt;
&lt;br /&gt;
(mandatory for &amp;quot;activeplayer&amp;quot; and &amp;quot;multipleactiveplayer&amp;quot; game states type)&lt;br /&gt;
&lt;br /&gt;
&amp;quot;descriptionmyturn&amp;quot; has exactly the same role and properties than &amp;quot;description&amp;quot;, except that this value is displayed to the current active player - or to all active players in case of a multipleactiveplayer game state.&lt;br /&gt;
&lt;br /&gt;
In general, we have this situation:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        &amp;quot;description&amp;quot; =&amp;gt; clienttranslate(&#039;${actplayer} can take some actions&#039;),&lt;br /&gt;
        &amp;quot;descriptionmyturn&amp;quot; =&amp;gt; clienttranslate(&#039;${you} can take some actions&#039;),&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: you can use ${you} in description my turn in order the description can display &amp;quot;You&amp;quot; instead of the name of the player.&lt;br /&gt;
&lt;br /&gt;
=== action ===&lt;br /&gt;
&lt;br /&gt;
(mandatory for &amp;quot;game&amp;quot; game state type)&lt;br /&gt;
&lt;br /&gt;
&amp;quot;action&amp;quot; specify a PHP method to call when entering into this game state.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
In states.inc.php:&lt;br /&gt;
    28 =&amp;gt; array(&lt;br /&gt;
        &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;startPlayerTurn&amp;quot;,&lt;br /&gt;
        &amp;quot;description&amp;quot; =&amp;gt; &#039;&#039;,&lt;br /&gt;
        &amp;quot;type&amp;quot; =&amp;gt; &amp;quot;game&amp;quot;,&lt;br /&gt;
        &amp;quot;action&amp;quot; =&amp;gt; &amp;quot;stStartPlayerTurn&amp;quot;,&lt;br /&gt;
&lt;br /&gt;
In mygame.game.php:&lt;br /&gt;
    function stStartPlayerTurn()&lt;br /&gt;
    {   &lt;br /&gt;
        // ... do something at the beginning of this game state&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Usually, for &amp;quot;game&amp;quot; game state type, the action method is used to do some automatic stuff specified by the rules (ex: check victory conditions, deal cards for a new round, go to the next player...) and then jump to another game state.&lt;br /&gt;
&lt;br /&gt;
Note: a BGA convention specify that PHP method called with &amp;quot;action&amp;quot; are prefixed by &amp;quot;st&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== transitions ===&lt;br /&gt;
&lt;br /&gt;
(mandatory)&lt;br /&gt;
&lt;br /&gt;
With &amp;quot;transition&amp;quot; you specify in which game state you can jump from a given game state.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    25 =&amp;gt; array(&lt;br /&gt;
        &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;myGameState&amp;quot;,&lt;br /&gt;
        &amp;quot;transitions&amp;quot; =&amp;gt; array( &amp;quot;nextPlayer&amp;quot; =&amp;gt; 27, &amp;quot;endRound&amp;quot; =&amp;gt; 39 ),&lt;br /&gt;
        ....&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the example above, if &amp;quot;myGameState&amp;quot; is the current active game state, I can jump to game state with ID 27, or game state with ID 39.&lt;br /&gt;
&lt;br /&gt;
Example to jump to ID 27:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
In mygame.game.php:&lt;br /&gt;
    $this-&amp;gt;gamestate-&amp;gt;nextState( &amp;quot;nextPlayer&amp;quot; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Important: &amp;quot;nextPlayer&amp;quot; is the name of the transition, and NOT the name of the target game state. Several transitions can lead to the same game state.&lt;br /&gt;
&lt;br /&gt;
Note: if you have only 1 transition, you may give it an empty name.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
In states.inc.php:&lt;br /&gt;
    &amp;quot;transitions&amp;quot; =&amp;gt; array( &amp;quot;&amp;quot; =&amp;gt; 27 ),&lt;br /&gt;
&lt;br /&gt;
In mygame.game.php:&lt;br /&gt;
    $this-&amp;gt;gamestate-&amp;gt;nextState(  );     // We don&#039;t need to specify a transition as there is only one here&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== possibleactions ===&lt;br /&gt;
&lt;br /&gt;
(mandatory for &amp;quot;activeplayer&amp;quot; and &amp;quot;multipleactiveplayer&amp;quot; game states)&lt;br /&gt;
&lt;br /&gt;
&amp;quot;possibleactions&amp;quot; defines the actions possible by the players at this game state.&lt;br /&gt;
&lt;br /&gt;
By defining &amp;quot;possibleactions&amp;quot;, you make sure players can&#039;t do actions that they are not allowed to do at this game states.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
In states.game.php:&lt;br /&gt;
       	&amp;quot;possibleactions&amp;quot; =&amp;gt; array( &amp;quot;playCard&amp;quot;, &amp;quot;pass&amp;quot; ),&lt;br /&gt;
&lt;br /&gt;
In mygame.game.php:&lt;br /&gt;
        function playCard( ...)&lt;br /&gt;
        {&lt;br /&gt;
             self::checkAction( &amp;quot;playCard&amp;quot; );    // Will failed if &amp;quot;playCard&amp;quot; is not specified in &amp;quot;possibleactions&amp;quot; in current game state.&lt;br /&gt;
&lt;br /&gt;
            ....&lt;br /&gt;
&lt;br /&gt;
In mygame.js:&lt;br /&gt;
        playCard: function( ... )&lt;br /&gt;
        {&lt;br /&gt;
            if( this.checkAction( &amp;quot;playCard&amp;quot; ) ) // Will failed if &amp;quot;playCard&amp;quot; is not specified in &amp;quot;possibleactions&amp;quot; in current game state.&lt;br /&gt;
            {  return ;   }&lt;br /&gt;
&lt;br /&gt;
            ....&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== args ===&lt;br /&gt;
&lt;br /&gt;
(optional)&lt;br /&gt;
&lt;br /&gt;
From time to time, it happens that you need some information on the client side (ie : for your game interface) only for a specific game state.&lt;br /&gt;
&lt;br /&gt;
Example 1 : for Reversi, the list of possible moves during playerTurn state.&lt;br /&gt;
Example 2 : in Caylus, the number of remaining king&#039;s favor to choose in the state where the player is choosing a favor.&lt;br /&gt;
Example 3 : in Can&#039;t stop, the list of possible die combination to be displayed to the active player in order he can choose among them.&lt;br /&gt;
&lt;br /&gt;
In such a situation, you can specify a method name as the « args » argument for your game state. This method must get some piece of information about the game (ex : for Reversi, the possible moves) and return them.&lt;br /&gt;
&lt;br /&gt;
Thus, this data can be transmitted to the clients and used by the clients to display it. It should always be an associative array.&lt;br /&gt;
&lt;br /&gt;
Let&#039;s see a complete example using args with « Reversi » game :&lt;br /&gt;
&lt;br /&gt;
In states.inc.php, we specify some « args » argument for gamestate « playerTurn » :&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    10 =&amp;gt; array(&lt;br /&gt;
        &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;playerTurn&amp;quot;,&lt;br /&gt;
		&amp;quot;description&amp;quot; =&amp;gt; clienttranslate(&#039;${actplayer} must play a disc&#039;),&lt;br /&gt;
		&amp;quot;descriptionmyturn&amp;quot; =&amp;gt; clienttranslate(&#039;${you} must play a disc&#039;),&lt;br /&gt;
        &amp;quot;type&amp;quot; =&amp;gt; &amp;quot;activeplayer&amp;quot;,&lt;br /&gt;
        &amp;quot;args&amp;quot; =&amp;gt; &amp;quot;argPlayerTurn&amp;quot;,    &amp;lt;================================== HERE&lt;br /&gt;
        &amp;quot;possibleactions&amp;quot; =&amp;gt; array( &#039;playDisc&#039; ),&lt;br /&gt;
        &amp;quot;transitions&amp;quot; =&amp;gt; array( &amp;quot;playDisc&amp;quot; =&amp;gt; 11, &amp;quot;zombiePass&amp;quot; =&amp;gt; 11 )&lt;br /&gt;
    ),&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It corresponds to a « argPlayerTurn » method in our PHP code (reversi.game.php):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    function argPlayerTurn()&lt;br /&gt;
    {&lt;br /&gt;
        return array(&lt;br /&gt;
            &#039;possibleMoves&#039; =&amp;gt; self::getPossibleMoves()&lt;br /&gt;
        );&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then, when we enter into « playerTurn » game state on the client side, we can highlight the possible moves on the board using information returned by argPlayerTurn :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        onEnteringState: function( stateName, args )&lt;br /&gt;
        {&lt;br /&gt;
           console.log( &#039;Entering state: &#039;+stateName );&lt;br /&gt;
            &lt;br /&gt;
            switch( stateName )&lt;br /&gt;
            {&lt;br /&gt;
            case &#039;playerTurn&#039;:&lt;br /&gt;
                this.updatePossibleMoves( args.args.possibleMoves );&lt;br /&gt;
                break;&lt;br /&gt;
            }&lt;br /&gt;
        },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: you can also use values returned by your &amp;quot;args&amp;quot; method to have some custom values in your &amp;quot;description&amp;quot;/&amp;quot;descriptionmyturn&amp;quot; (see above).&lt;br /&gt;
&lt;br /&gt;
Note: as a BGA convention, PHP methods called with &amp;quot;args&amp;quot; are prefixed by &amp;quot;arg&amp;quot; (ex: argPlayerTurn).&lt;br /&gt;
&lt;br /&gt;
==== Private infos in args ====&lt;br /&gt;
&lt;br /&gt;
By default, all data provided through this method are PUBLIC TO ALL PLAYERS. Please do not send any private data with this method, as a cheater could see it even it is not used explicitly by the game interface logic.&lt;br /&gt;
&lt;br /&gt;
This is although possible to specify that some data should be sent to some specific players only:&lt;br /&gt;
&lt;br /&gt;
Example 1: send an information to active player(s) only:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    function argPlayerTurn()&lt;br /&gt;
    {&lt;br /&gt;
        return array(&lt;br /&gt;
            &#039;_private&#039; =&amp;gt; array(          // Using &amp;quot;_private&amp;quot; keyword, all data inside this array will be made private&lt;br /&gt;
&lt;br /&gt;
                &#039;active&#039; =&amp;gt; array(       // Using &amp;quot;active&amp;quot; keyword inside &amp;quot;_private&amp;quot;, you select active player(s)&lt;br /&gt;
                    &#039;somePrivateData&#039; =&amp;gt; self::getSomePrivateData()   // will be send only to active player(s)&lt;br /&gt;
                )&lt;br /&gt;
            ),&lt;br /&gt;
&lt;br /&gt;
            &#039;possibleMoves&#039; =&amp;gt; self::getPossibleMoves()          // will be send to all players&lt;br /&gt;
        );&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Inside the js file, these variables will be available through `args._private`. (e.g. `args._private.somePrivateData` -- it is not `args._private.active.somePrivateData` nor is it `args.somePrivateData`)&lt;br /&gt;
&lt;br /&gt;
Example 2: send an information to a specific player (&amp;lt;specific_player_id&amp;gt;) only:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    function argPlayerTurn()&lt;br /&gt;
    {&lt;br /&gt;
        return array(&lt;br /&gt;
            &#039;_private&#039; =&amp;gt; array(          // Using &amp;quot;_private&amp;quot; keyword, all data inside this array will be made private&lt;br /&gt;
&lt;br /&gt;
                &amp;lt;specific_player_id&amp;gt; =&amp;gt; array(       // you select one specific player with its id&lt;br /&gt;
                    &#039;somePrivateData&#039; =&amp;gt; self::getSomePrivateData()   // will be send only to &amp;lt;specific_player_id&amp;gt;&lt;br /&gt;
                )&lt;br /&gt;
            ),&lt;br /&gt;
&lt;br /&gt;
            &#039;possibleMoves&#039; =&amp;gt; self::getPossibleMoves()          // will be send to all players&lt;br /&gt;
        );&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
IMPORTANT: in certain situation (ex: multipleactiveplayer game state) these &amp;quot;private data&amp;quot; features can have a big performance impact. Please do not use if not needed.&lt;br /&gt;
&lt;br /&gt;
=== updateGameProgression ===&lt;br /&gt;
&lt;br /&gt;
(optional)&lt;br /&gt;
&lt;br /&gt;
IF you specify &amp;quot;updateGameProgression =&amp;gt; true&amp;quot; in a game state, your &amp;quot;getGameProgression&amp;quot; PHP method will be called at the beginning of this game state - and thus the game progression of the game will be updated.&lt;br /&gt;
&lt;br /&gt;
At least one of your game state (any of them) must specify updateGameProgression=&amp;gt;true.&lt;/div&gt;</summary>
		<author><name>Archduke</name></author>
	</entry>
</feed>