internationalization.rst 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. Internationalization and Localization
  2. =====================================
  3. To internationalize your extension, the following tasks are required:
  4. .. note::
  5. Please read carefully the :ref:`internationalization-rules` as they are strong constraints for internationalization to work.
  6. 1. Add the token ``ITranslator`` from ``@jupyterlab/translation`` package to your plugin dependencies.
  7. .. code:: typescript
  8. const extension: JupyterFrontEndPlugin<void> = {
  9. id: 'jupyterlab-extension',
  10. autoStart: true,
  11. requires: [ITranslator],
  12. activate: (app: JupyterFrontEnd, translator: ITranslator) => {}
  13. };
  14. 2. Get the translation bundle from the domain on which your extension is translated.
  15. .. code:: typescript
  16. const trans = translator.load('my_domain');
  17. .. note::
  18. A good practice is to use your extension named using only letters, numbers and ``_``
  19. characters.
  20. Domain are normalized by replacing ``-`` with ``_`` characters.
  21. 3. Wraps all translatable strings with one of the `gettext functions <https://jupyterlab.readthedocs.io/en/3.4.x/api/modules/translation.html#translationbundle>`_.
  22. Examples:
  23. .. code:: typescript
  24. this._trans.__('String to be translated');
  25. this._trans.__('%1 is argument of a translated string', adjective);
  26. this._trans._n('Singular string for %1', 'Plural string for %1', n);
  27. You could also look at the following pull requests on the
  28. `spellchecker extension <https://github.com/jupyterlab-contrib/spellchecker/pull/84/files>`_.
  29. 4. Create and publish the translation for your extension.
  30. There are two options: you can either add your extension to the JupyterLab `language packs <https://github.com/jupyterlab/language-packs/#adding-a-new-extension>`_
  31. or you can create a python package to distribute your extension translation (see below).
  32. Create translation python package
  33. ---------------------------------
  34. Jupyter Lab follows Gettext's approach for translation. Gettext extracts strings from source code, and compiles them with provided translation. This `article <https://www.labri.fr/perso/fleury/posts/programming/a-quick-gettext-tutorial.html>`_ briefly explains how Gettext works.
  35. By using `jupyterlab-translate <https://github.com/jupyterlab/jupyterlab-translate>`_, you can extract, update, and compile your translation.
  36. After that, you must include your compiled translation (.json, .mo) to your python package. This can be done by editing these two files.
  37. setup.py:
  38. .. code:: python
  39. from setuptools import setup
  40. setup(
  41. # ...
  42. entry_points={"jupyterlab.locale": ["jupyterlab_some_package = jupyterlab_some_package"]},
  43. )
  44. MANIFEST.in:
  45. .. code:: text
  46. recursive-include jupyterlab_some_package *.json
  47. recursive-include jupyterlab_some_package *.mo
  48. .. note::
  49. An example is available in the `server test <https://github.com/jupyterlab/jupyterlab_server/tree/main/tests/translations/jupyterlab-some-package>`_
  50. Settings translation
  51. --------------------
  52. Settings schema can also be translated. The translatable strings are extracted using regex selectors
  53. on JSON path. By default, the following selectors are used:
  54. - ``title``: Settings title
  55. - ``description``: Settings description
  56. - ``properties/.*/title``: Property titles
  57. - ``properties/.*/description``: Property descriptions
  58. - ``definitions/.*/properties/.*/title``: Property titles in definitions
  59. - ``definitions/.*/properties/.*/description``: Property descriptions in definitions
  60. - ``jupyter\.lab\.setting-icon-label``: Settings icon label in JupyterLab
  61. - ``jupyter\.lab\.menus/.*/label``: Menu label in JupyterLab
  62. - ``jupyter\.lab\.toolbars/.*/label``: Toolbar item label in JupyterLab
  63. Those selectors can be configured using the ``jupyter.lab.internationalization`` key in
  64. the schema. The following example will pick the default value for ``myprop`` property:
  65. .. code:: json
  66. "jupyter.lab.internationalization": {
  67. "selectors": [
  68. "properties/myprop/default",
  69. ],
  70. "domain": "my_jlab_extension"
  71. }
  72. In the example above, a specific domain in which the translations are defined is also
  73. specified (here ``my_jlab_extension``). If no domain is specified, it defaults to
  74. ``jupyterlab``.
  75. .. _internationalization-rules:
  76. Rules
  77. -----
  78. In order for the strings to be extracted from the code, the following rules must be followed.
  79. - Domain name are normalized by replacing ``-`` to ``_``
  80. - Translation bundle variable must be one of:
  81. - ``trans``
  82. - ``this.trans``
  83. - ``this._trans``
  84. - ``this.props.trans``
  85. - ``props.trans``
  86. Examples that work:
  87. .. code:: typescript
  88. trans.__('This translatable string will be found');
  89. this.trans.__('This translatable string will be found');
  90. this._trans.__('This translatable string will be found');
  91. this.props.trans.__('This translatable string will be found');
  92. props.trans.__('This translatable string will be found');
  93. Examples that will **not** work:
  94. .. code:: typescript
  95. translator.__('This translatable string WONT be found');
  96. __('This translatable string WONT be found');
  97. this.__('This translatable string WONT be found');
  98. To fix this issue, alter your variable to use an accepted name:
  99. .. code:: typescript
  100. const trans = translator;
  101. trans.__('This translatable string will be found');
  102. - String must be passed directly to the function; don't use variables or constants
  103. Example that will **not** work:
  104. .. code:: typescript
  105. const errorMessage = 'This translatable string WONT be found'
  106. trans.__(errorMessage);
  107. To fix this issue, pass the string directly:
  108. .. code:: typescript
  109. trans.__('This translatable string will be found');