internationalizing_games.rst 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394
  1. .. _doc_internationalizing_games:
  2. Internationalizing games
  3. ========================
  4. Introduction
  5. ------------
  6. While indie or niche games usually
  7. do not need localization, games targeting a more massive market
  8. often require localization. Godot offers many tools to make this process
  9. more straightforward, so this tutorial is more like a collection of
  10. tips and tricks.
  11. Localization is usually done by specific studios hired for the job. Despite the
  12. huge amount of software and file formats available for this, the most common way
  13. to do localization to this day is still with spreadsheets. The process of
  14. creating the spreadsheets and importing them is already covered in the
  15. :ref:`doc_importing_translations` tutorial. If you haven't read the Importing
  16. translations page before, we recommend you give it a read before reading this
  17. page.
  18. .. note:: We will be using the official demo as an example; you can
  19. `download it from the Asset Library <https://godotengine.org/asset-library/asset/2776>`_.
  20. Configuring the imported translation
  21. ------------------------------------
  22. Translations can get updated and re-imported when they change, but
  23. they still have to be added to the project. This is done in
  24. **Project → Project Settings → Localization**:
  25. .. image:: img/localization_dialog.png
  26. The above dialog is used to add or remove translations project-wide.
  27. Localizing resources
  28. --------------------
  29. It is also possible to instruct Godot to use alternate versions of
  30. assets (resources) depending on the current language. This can be used for
  31. localized images such as in-game billboards or localized voices.
  32. The **Remaps** tab can be used for this:
  33. .. image:: img/localization_remaps.png
  34. Select the resource to be remapped then add some alternatives for each locale.
  35. .. note::
  36. The resource remapping system isn't supported for DynamicFonts. To use
  37. different fonts depending on the language's script, use the DynamicFont
  38. fallback system instead, which lets you define as many fallback fonts as you
  39. want.
  40. The upside of the DynamicFont fallback system is that it works regardless of
  41. the current language, making it ideal for things like multiplayer chat where
  42. the text language may not match the client's language.
  43. Automatically setting a language
  44. --------------------------------
  45. It is recommended to default to the user's preferred language which can be obtained via :ref:`OS.get_locale_language() <class_OS_method_get_locale_language>`.
  46. If your game is not available in that language, it will fall back to the :ref:`Fallback <class_ProjectSettings_property_internationalization/locale/fallback>`
  47. in **Project Settings > Internationalization > Locale**, or to ``en`` if empty.
  48. Nevertheless letting players change the language in game is recommended for various reasons (e.g. translation quality or player preference).
  49. .. tabs::
  50. .. code-tab:: gdscript
  51. var language = "automatic"
  52. # Load here language from the user settings file
  53. if language == "automatic":
  54. var preferred_language = OS.get_locale_language()
  55. TranslationServer.set_locale(preferred_language)
  56. else:
  57. TranslationServer.set_locale(language)
  58. Locale vs. language
  59. -------------------
  60. A :ref:`locale <doc_locales>` is commonly a combination of a language with a region or country, but can also contain information like a script or a variant.
  61. Examples:
  62. - ``en``: English language
  63. - ``en_GB``: English in Great Britain / British English
  64. - ``en_US``: English in the USA / American English
  65. - ``en_DE``: English in Germany
  66. Indie games generally only need to care about language, but read on for more information.
  67. Why locales exist can be illustrated through the USA and Great Britain. Both speak the same language (English), yet differ in many aspects:
  68. - Spelling: E.g. gray (USA), grey (GB)
  69. - Use of words: E.g. eggplant (USA), aubergine (GB)
  70. - Units or currencies: E.g. feet/inches (USA), metres/cm (GB)
  71. It can get more complex however. Imagine you offer different content in Europe and in China (e.g. in an MMO). You will need to translate each of those content variations into many languages and store and load them accordingly.
  72. Converting keys to text
  73. -----------------------
  74. Some controls, such as :ref:`Button <class_Button>` and :ref:`Label <class_Label>`,
  75. will automatically fetch a translation if their text matches a translation key.
  76. For example, if a label's text is "MAIN_SCREEN_GREETING1" and that key exists
  77. in the current translation, then the text will automatically be translated.
  78. This automatic translation behavior may be undesirable in certain cases. For
  79. instance, when using a Label to display a player's name, you most likely don't
  80. want the player's name to be translated if it matches a translation key. To
  81. disable automatic translation on a specific node, disable **Localization > Auto
  82. Translate** in the inspector.
  83. In code, the :ref:`Object.tr() <class_Object_method_tr>` function can be used.
  84. This will just look up the text in the translations and convert it if found:
  85. .. tabs::
  86. .. code-tab:: gdscript
  87. level.text = tr("LEVEL_5_NAME")
  88. status.text = tr("GAME_STATUS_%d" % status_index)
  89. .. code-tab:: csharp
  90. level.Text = Tr("LEVEL_5_NAME");
  91. status.Text = Tr($"GAME_STATUS_{statusIndex}");
  92. .. note::
  93. If no text is displayed after changing the language, try to use a different
  94. font. The default project font only supports a subset of the Latin-1 character set,
  95. which cannot be used to display languages like Russian or Chinese.
  96. A good resource for multilingual fonts is `Noto Fonts <https://www.google.com/get/noto/>`__.
  97. Make sure to download the correct variation if you're using a less common
  98. language.
  99. Once you've downloaded the font, load the TTF file into a DynamicFont
  100. resource and use it as a custom font of your Control node. For better
  101. reusability, associate a new a Theme resource to your root Control node and
  102. define the DynamicFont as the Default Font in the theme.
  103. Placeholders
  104. ~~~~~~~~~~~~
  105. To feature placeholders in your translated strings, use
  106. :ref:`doc_gdscript_printf` or the equivalent feature in C#. This lets
  107. translators move the location of the placeholder in the string freely, which
  108. allows translations to sound more natural. Named placeholders with the
  109. ``String.format()`` function should be used whenever possible, as they also
  110. allow translators to choose the *order* in which placeholders appear:
  111. .. tabs::
  112. .. code-tab:: gdscript
  113. # The placeholder's locations can be changed, but not their order.
  114. # This will probably not suffice for some target languages.
  115. message.text = tr("%s picked up the %s") % ["Ogre", "Sword"]
  116. # The placeholder's locations and order can be changed.
  117. # Additionally, this form gives more context for translators to work with.
  118. message.text = tr("{character} picked up the {weapon}").format({character = "Ogre", weapon = "Sword"})
  119. Translation contexts
  120. ~~~~~~~~~~~~~~~~~~~~
  121. If you're using plain English as source strings (rather than message codes
  122. ``LIKE_THIS``), you may run into ambiguities when you have to translate the same
  123. English string to different strings in certain target languages. You can
  124. optionally specify a *translation context* to resolve this ambiguity and allow
  125. target languages to use different strings, even though the source string is
  126. identical:
  127. .. tabs::
  128. .. code-tab:: gdscript
  129. # "Close", as in an action (to close something).
  130. button.set_text(tr("Close", "Actions"))
  131. # "Close", as in a distance (opposite of "far").
  132. distance_label.set_text(tr("Close", "Distance"))
  133. .. code-tab:: csharp
  134. // "Close", as in an action (to close something).
  135. GetNode<Button>("Button").Text = Tr("Close", "Actions");
  136. // "Close", as in a distance (opposite of "far").
  137. GetNode<Label>("Distance").Text = Tr("Close", "Distance");
  138. Pluralization
  139. ~~~~~~~~~~~~~
  140. Most languages require different strings depending on whether an object is in
  141. singular or plural form. However, hardcoding the "is plural" condition depending
  142. on whether there is more than 1 object is not valid in all languages.
  143. Some languages have more than two plural forms, and the rules on the number of
  144. objects required for each plural form vary. Godot offers support for
  145. *pluralization* so that the target locales can handle this automatically.
  146. Pluralization is meant to be used with positive (or zero) integer numbers only.
  147. Negative and floating-point values usually represent physical entities for which
  148. singular and plural don't clearly apply.
  149. .. tabs::
  150. .. code-tab:: gdscript
  151. var num_apples = 5
  152. label.text = tr_n("There is %d apple", "There are %d apples", num_apples) % num_apples
  153. .. code-tab:: csharp
  154. int numApples = 5;
  155. GetNode<Label>("Label").Text = string.Format(TrN("There is {0} apple", "There are {0} apples", numApples), numApples);
  156. This can be combined with a context if needed:
  157. .. tabs::
  158. .. code-tab:: gdscript
  159. var num_jobs = 1
  160. label.text = tr_n("%d job", "%d jobs", num_jobs, "Task Manager") % num_jobs
  161. .. code-tab:: csharp
  162. int numJobs = 1;
  163. GetNode<Label>("Label").Text = string.Format(TrN("{0} job", "{0} jobs", numJobs, "Task Manager"), numJobs);
  164. .. note::
  165. Providing pluralized translations is only supported with
  166. :ref:`doc_localization_using_gettext`, not CSV.
  167. Making controls resizable
  168. -------------------------
  169. The same text in different languages can vary greatly in length. For
  170. this, make sure to read the tutorial on :ref:`doc_size_and_anchors`, as
  171. dynamically adjusting control sizes may help.
  172. :ref:`Container <class_Container>` can be useful, as well as the text wrapping
  173. options available in :ref:`Label <class_Label>`.
  174. To check whether your UI can accommodate translations with longer strings than
  175. the original, you can enable *pseudolocalization* in the advanced Project
  176. Settings. This will replace all your localizable strings with longer versions of
  177. themselves, while also replacing some characters in the original strings with
  178. accented versions (while still being readable). Placeholders are kept as-is,
  179. so that they keep working when pseudolocalization is enabled.
  180. For example, the string ``Hello world, this is %s!`` becomes
  181. ``[Ĥéłłô ŵôŕłd́, ŧh̀íš íš %s!]`` when pseudolocalization is enabled.
  182. While looking strange at first, pseudolocalization has several benefits:
  183. - It lets you spot non-localizable strings quickly, so you can go over them and
  184. make them localizable (if it makes sense to do so).
  185. - It lets you check UI elements that can't fit long strings. Many languages will
  186. feature much longer translations than the source text, so it's important to
  187. ensure your UI can accommodate longer-than-usual strings.
  188. - It lets you check whether your font contains all the characters required to
  189. support various languages. However, since the goal of pseudolocalization is to
  190. keep the original strings readable, it's not an effective test for checking
  191. whether a font can support :abbr:`CJK (Chinese, Japanese, Korean)` or
  192. right-to-left languages.
  193. The project settings allow you to tune pseudolocalization behavior, so that you
  194. can disable parts of it if desired.
  195. TranslationServer
  196. -----------------
  197. Godot has a server handling low-level translation management
  198. called the :ref:`TranslationServer <class_TranslationServer>`.
  199. Translations can be added or removed during runtime;
  200. the current language can also be changed at runtime.
  201. .. _doc_internationalizing_games_bidi:
  202. Bidirectional text and UI Mirroring
  203. -----------------------------------
  204. Arabic and Hebrew are written from right to left (except for the numbers and Latin
  205. words mixed in), and the user interface for these languages should be mirrored as well.
  206. In some languages the shape of a glyph changes depending on the surrounding characters.
  207. Support for bidirectional writing systems and UI mirroring is transparent, you don't
  208. usually need to change anything or have any knowledge of the specific writing system.
  209. For RTL languages, Godot will automatically do the following changes to the UI:
  210. - Mirrors left/right anchors and margins.
  211. - Swaps left and right text alignment.
  212. - Mirrors horizontal order of the child controls in the containers, and items in Tree/ItemList controls.
  213. - Uses mirrored order of the internal control elements (e.g. OptionButton dropdown button, checkbox alignment, List column order, Tree item icons and connecting line alignment, e.t.c.), in some cases mirrored controls use separate theme styles.
  214. - Coordinate system is not mirrored, and non-UI nodes (sprites, e.t.c) are not affected.
  215. It is possible to override text and control layout direction by using the following control properties:
  216. - ``text_direction``, sets the base text direction. When set to "auto", direction depends on the first strong directional character in the text according to the Unicode Bidirectional Algorithm,
  217. - ``language``, overrides current project locale.
  218. - ``structured_text_bidi_override`` property and ``_structured_text_parser`` callback, enables special handling for structured text.
  219. - ``layout_direction``, overrides control mirroring.
  220. .. image:: img/ui_mirror.png
  221. .. seealso::
  222. You can see how right-to-left typesetting works in action using the
  223. `BiDI and Font Features demo project <https://github.com/godotengine/godot-demo-projects/tree/master/gui/bidi_and_font_features>`__.
  224. Adding break iterator data to exported project
  225. ----------------------------------------------
  226. Some languages are written without spaces, and word and line breaking requires more than rules over character sequences.
  227. Godot includes ICU rule and dictionary based, break iterator data, but this data is not included into exported projects by default.
  228. To include it go to **Project → Project Settings → Localization → Text Server Data** and click **Install support data...**. Break iterator data is about 4 MB large.
  229. .. image:: img/icu_data.png
  230. Structured text BiDi override
  231. -----------------------------
  232. Unicode BiDi algorithm is designed to work with natural text and it's incapable of
  233. handling text with the higher level order, like file names, URIs, email addresses,
  234. regular expressions or source code.
  235. .. image:: img/bidi_override.png
  236. For example, the path for this shown directory structure will be displayed incorrectly
  237. (top "LineEdit" control). "File" type structured text override splits text into segments,
  238. then BiDi algorithm is applied to each of them individually to correctly display directory
  239. names in any language and preserve correct order of the folders (bottom "LineEdit" control).
  240. Custom callbacks provide a way to override BiDi for the other types of structured text.
  241. Localizing numbers
  242. ------------------
  243. Controls specifically designed for number input or output (e.g. ProgressBar, SpinBox)
  244. will use localized numbering system automatically, for the other control
  245. :ref:`TextServer.format_number(string, language) <class_TextServer_method_format_number>`
  246. can be used to convert Western Arabic numbers (0..9) to the localized numbering system
  247. and :ref:`TextServer.parse_number(string, language) <class_TextServer_method_parse_number>`
  248. to convert it back.
  249. Localizing icons and images
  250. ---------------------------
  251. Icons with left and right pointing arrows which may need to be reversed for Arabic
  252. and Hebrew locales, in case they indicate movement or direction (e.g. back/forward
  253. buttons). Otherwise, they can remain the same.
  254. Testing translations
  255. --------------------
  256. You may want to test a project's translation before releasing it. Godot provides two ways
  257. to do this.
  258. First, in the Project Settings, under **Internationalization > Locale** (with advanced settings enabled), there is a **Test**
  259. property. Set this property to the locale code of the language you want to test. Godot will
  260. run the project with that locale when the project is run (either from the editor or when
  261. exported).
  262. .. image:: img/locale_test.webp
  263. Keep in mind that since this is a project setting, it will show up in version control when
  264. it is set to a non-empty value. Therefore, it should be set back to an empty value before
  265. committing changes to version control.
  266. Translations can also be tested when :ref:`running Godot from the command line <doc_command_line_tutorial>`.
  267. For example, to test a game in French, the following argument can be
  268. supplied:
  269. .. code-block:: shell
  270. godot --language fr
  271. Translating the project name
  272. ----------------------------
  273. The project name becomes the app name when exporting to different
  274. operating systems and platforms. To specify the project name in more
  275. than one language go to **Project > Project Settings> Application >
  276. Config**. From here click on the button that says ``Localizable String
  277. (Size 0)``. Now there should be a button below that which says ``Add
  278. Translation``. Click on that and it will take you to a page where you
  279. can choose the language (and country if needed) for your project name
  280. translation. After doing that you can now type in the localized name.
  281. .. image:: img/localized_name.webp
  282. If you are unsure about the language code to use, refer to the
  283. :ref:`list of locale codes <doc_locales>`.