localization_using_gettext.rst 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342
  1. .. _doc_localization_using_gettext:
  2. Localization using gettext (PO files)
  3. =====================================
  4. In addition to importing translations in
  5. :ref:`CSV format <doc_localization_using_spreadsheets>`, Godot also
  6. supports loading translation files written in the GNU gettext format
  7. (text-based ``.po`` and compiled ``.mo``).
  8. .. note:: For an introduction to gettext, check out
  9. `A Quick Gettext Tutorial <https://www.labri.fr/perso/fleury/posts/programming/a-quick-gettext-tutorial.html>`_.
  10. It's written with C projects in mind, but much of the advice
  11. also applies to Godot (with the exception of ``xgettext``).
  12. For the complete documentation, see `GNU Gettext <https://www.gnu.org/software/gettext/manual/gettext.html>`_.
  13. Advantages
  14. ----------
  15. - gettext is a standard format, which can be edited using any text editor
  16. or GUI editors such as `Poedit <https://poedit.net/>`_. This can be significant
  17. as it provides a lot of tools for translators, such as marking outdated
  18. strings, finding strings that haven't been translated, etc.
  19. - gettext is supported by translation platforms such as
  20. `Transifex <https://www.transifex.com/>`_ and `Weblate <https://weblate.org/>`_,
  21. which makes it easier for people to collaborate to localization.
  22. - Compared to CSV, gettext files work better with version control systems like Git,
  23. as each locale has its own messages file.
  24. - Multiline strings are more convenient to edit in gettext PO files compared
  25. to CSV files.
  26. Disadvantages
  27. -------------
  28. - gettext PO files have a more complex format than CSV and can be harder to grasp for
  29. people new to software localization.
  30. - People who maintain localization files will have to install gettext tools
  31. on their system. However, as Godot supports using text-based message files
  32. (``.po``), translators can test their work without having to install gettext tools.
  33. - gettext PO files usually use English as the base language. Translators will use
  34. this base language to translate to other languages. You could still user other
  35. languages as the base language, but this is not common.
  36. Installing gettext tools
  37. ------------------------
  38. The command line gettext tools are required to perform maintenance operations,
  39. such as updating message files. Therefore, it's strongly recommended to
  40. install them.
  41. - **Windows:** Download an installer from
  42. `this page <https://mlocati.github.io/articles/gettext-iconv-windows.html>`_.
  43. Any architecture and binary type (shared or static) works;
  44. if in doubt, choose the 64-bit static installer.
  45. - **macOS:** Install gettext either using `Homebrew <https://brew.sh/>`_
  46. with the ``brew install gettext`` command, or using
  47. `MacPorts <https://www.macports.org/>`_ with the
  48. ``sudo port install gettext`` command.
  49. - **Linux:** On most distributions, install the ``gettext`` package from
  50. your distribution's package manager.
  51. For a GUI tool you can get Poedit from its `Official website <https://poedit.net/>`_.
  52. The basic version is open source and available under the MIT license.
  53. Creating the PO template
  54. ------------------------
  55. Automatic generation using the editor
  56. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  57. The editor can generate a PO template automatically from
  58. specified scene and GDScript files. This POT generation also supports translation
  59. contexts and pluralization if used in a script, with the optional second
  60. argument of ``tr()`` and the ``tr_n()`` method.
  61. Open :menu:`Project > Project Settings > Localization > Template Generation`, then use the
  62. :button:`Add…` button to specify the path to your project's scenes and scripts that
  63. contain localizable strings:
  64. .. figure:: img/localization_using_gettext_pot_generation.webp
  65. :align: center
  66. :alt: Creating a PO template in the Localization > Template Generation tab of the Project Settings
  67. Creating a PO template in the :menu:`Localization > Template Generation` tab of the :ui:`Project Settings`
  68. After adding at least one scene or script, click :button:`Generate` in the
  69. top-right corner, then specify the path to the output file with a ``pot`` file extension. This file can be
  70. placed anywhere in the project directory, but it's recommended to keep it in a
  71. subdirectory such as ``locale``, as each locale will be defined in its own file.
  72. See :ref:`below <doc_localization_using_gettext_gdscript>` for how to add comments for translators
  73. or exclude some strings from being added to the PO template for GDScript files.
  74. You can then move over to
  75. :ref:`creating a messages file from a PO template <doc_localization_using_gettext_messages_file>`.
  76. .. note::
  77. Remember to regenerate the PO template after making any changes to
  78. localizable strings, or after adding new scenes or scripts. Otherwise, newly
  79. added strings will not be localizable and translators won't be able to
  80. update translations for outdated strings.
  81. Manual creation
  82. ~~~~~~~~~~~~~~~
  83. If the automatic generation approach doesn't work out for your needs, you can
  84. create a PO template by hand in a text editor. This file can be placed anywhere
  85. in the project directory, but it's recommended to keep it in a subdirectory, as
  86. each locale will be defined in its own file.
  87. Create a directory named ``locale`` in the project directory. In this directory,
  88. save a file named ``messages.pot`` with the following content:
  89. ::
  90. # Don't remove the two lines below, they're required for gettext to work correctly.
  91. msgid ""
  92. msgstr ""
  93. # Example of a regular string.
  94. msgid "Hello world!"
  95. msgstr ""
  96. # Example of a string with pluralization.
  97. msgid "There is %d apple."
  98. msgid_plural "There are %d apples."
  99. msgstr[0] ""
  100. msgstr[1] ""
  101. # Example of a string with a translation context.
  102. msgctxt "Actions"
  103. msgid "Close"
  104. msgstr ""
  105. Messages in gettext are made of ``msgid`` and ``msgstr`` pairs.
  106. ``msgid`` is the source string (usually in English), ``msgstr`` will be
  107. the translated string.
  108. .. warning::
  109. The ``msgstr`` value in PO template files (``.pot``) should **always** be
  110. empty. Localization will be done in the generated ``.po`` files instead.
  111. .. _doc_localization_using_gettext_messages_file:
  112. Creating a messages file from a PO template
  113. -------------------------------------------
  114. The ``msginit`` command is used to turn a PO template into a messages file.
  115. For instance, to create a French localization file, use the following command
  116. while in the ``locale`` directory:
  117. .. code-block:: shell
  118. msginit --no-translator --input=messages.pot --locale=fr
  119. The command above will create a file named ``fr.po`` in the same directory
  120. as the PO template.
  121. Alternatively, you can do that graphically using Poedit, or by uploading the
  122. POT file to your web platform of choice.
  123. Loading a messages file in Godot
  124. --------------------------------
  125. To register a messages file as a translation in a project, open the
  126. :ui:`Project Settings`, then go to :menu:`Localization > Translations`,
  127. click :button:`Add…` then choose the ``.po`` or ``.mo`` file
  128. in the file dialog. The locale will be inferred from the
  129. ``"Language: <code>\n"`` property in the messages file.
  130. .. note:: See :ref:`doc_internationalizing_games` for more information on
  131. importing and testing translations in Godot.
  132. Updating message files to follow the PO template
  133. ------------------------------------------------
  134. After updating the PO template, you will have to update message files so
  135. that they contain new strings, while removing strings that are no longer
  136. present in the PO template. This can be done automatically using the
  137. ``msgmerge`` tool:
  138. .. code-block:: shell
  139. # The order matters: specify the message file *then* the PO template!
  140. msgmerge --update --backup=none fr.po messages.pot
  141. If you want to keep a backup of the original message file (which would be
  142. saved as ``fr.po~`` in this example), remove the ``--backup=none`` argument.
  143. .. note::
  144. After running ``msgmerge``, strings which were modified in the source language
  145. will have a "fuzzy" comment added before them in the ``.po`` file. This comment
  146. denotes that the translation should be updated to match the new source string,
  147. as the translation will most likely be inaccurate until it's updated.
  148. Strings with "fuzzy" comments will **not** be read by Godot until the
  149. translation is updated and the "fuzzy" comment is removed.
  150. Checking the validity of a PO file or template
  151. ----------------------------------------------
  152. It is possible to check whether a gettext file's syntax is valid.
  153. If you open with Poeditor, it will display the appropriate warnings if there's some
  154. syntax errors. You can also verify by running the gettext command below:
  155. .. code-block:: shell
  156. msgfmt fr.po --check
  157. If there are syntax errors or warnings, they will be displayed in the console.
  158. Otherwise, ``msgfmt`` won't output anything.
  159. Using binary MO files (useful for large projects only)
  160. ------------------------------------------------------
  161. For large projects with several thousands of strings to translate or more,
  162. it can be worth it to use binary (compiled) MO message files instead of text-based
  163. PO files. Binary MO files are smaller and faster to read than the equivalent
  164. PO files.
  165. You can generate an MO file with the command below:
  166. .. code-block:: shell
  167. msgfmt fr.po --no-hash -o fr.mo
  168. If the PO file is valid, this command will create an ``fr.mo`` file besides
  169. the PO file. This MO file can then be loaded in Godot as described above.
  170. The original PO file should be kept in version control so you can update
  171. your translation in the future. In case you lose the original PO file and
  172. wish to decompile an MO file into a text-based PO file, you can do so with:
  173. .. code-block:: shell
  174. msgunfmt fr.mo > fr.po
  175. The decompiled file will not include comments or fuzzy strings, as these are
  176. never compiled in the MO file in the first place.
  177. .. _doc_localization_using_gettext_gdscript:
  178. Extracting localizable strings from GDScript files
  179. --------------------------------------------------
  180. The built-in `editor plugin <https://github.com/godotengine/godot/blob/master/modules/gdscript/editor/gdscript_translation_parser_plugin.h>`_
  181. recognizes a variety of patterns in source code to extract localizable strings
  182. from GDScript files, including but not limited to the following:
  183. - ``tr()``, ``tr_n()``, ``atr()``, and ``atr_n()`` calls;
  184. - assigning properties ``text``, ``placeholder_text``, and ``tooltip_text``;
  185. - ``add_tab()``, ``add_item()``, ``set_tab_title()``, and other calls;
  186. - ``FileDialog`` filters like ``"*.png ; PNG Images"``.
  187. .. note::
  188. The argument or right operand must be a constant string, otherwise the plugin
  189. will not be able to evaluate the expression and will ignore it.
  190. If the plugin extracts unnecessary strings, you can ignore them with the ``NO_TRANSLATE`` comment.
  191. You can also provide additional information for translators using the ``TRANSLATORS:`` comment.
  192. These comments must be placed either on the same line as the recognized pattern or precede it.
  193. ::
  194. $CharacterName.text = "???" # NO_TRANSLATE
  195. # NO_TRANSLATE: Language name.
  196. $TabContainer.set_tab_title(0, "Python")
  197. item.text = "Tool" # TRANSLATORS: Up to 10 characters.
  198. # TRANSLATORS: This is a reference to Lewis Carroll's poem "Jabberwocky",
  199. # make sure to keep this as it is important to the plot.
  200. say(tr("He took his vorpal sword in hand. The end?"))
  201. Using context
  202. -------------
  203. The ``context`` parameter can be used to differentiate the situation where a translation
  204. is used, or to differentiate polysemic words (words with multiple meanings).
  205. For example:
  206. ::
  207. tr("Start", "Main Menu")
  208. tr("End", "Main Menu")
  209. tr("Shop", "Main Menu")
  210. tr("Shop", "In Game")
  211. In a gettext PO file, a string with a context can be defined as follows:
  212. ::
  213. # Example of a string with a translation context.
  214. msgctxt "Main Menu"
  215. msgid "Shop"
  216. msgstr ""
  217. # A different source string that is identical, but with a different context.
  218. msgctxt "In Game"
  219. msgid "Shop"
  220. msgstr ""
  221. Updating PO files
  222. -----------------
  223. Some time or later, you'll add new content to our game, and there will
  224. be new strings that need to be translated. When this happens, you'll
  225. need to update the existing PO files to include the new strings.
  226. First, generate a new POT file containing all the existing strings plus
  227. the newly added strings. After that, merge the existing PO files
  228. with the new POT file. There are two ways to do this:
  229. - Use a gettext editor, and it should have an option to update a PO file
  230. from a POT file.
  231. - Use the gettext ``msgmerge`` tool:
  232. .. code-block:: shell
  233. # The order matters: specify the message file *then* the PO template!
  234. msgmerge --update --backup=none fr.po messages.pot
  235. If you want to keep a backup of the original message file (which would be saved
  236. as ``fr.po~`` in this example), remove the ``--backup=none`` argument.
  237. POT generation custom plugin
  238. ----------------------------
  239. If you have any extra file format to deal with, you could write a custom plugin
  240. to parse and and extract the strings from the custom file. This custom plugin
  241. will extract the strings and write into the POT file when you hit **Generate POT**.
  242. To learn more about how to create the translation parser plugin, see
  243. :ref:`EditorTranslationParserPlugin <class_EditorTranslationParserPlugin>`.