GitHub user mike-jumper opened a pull request:

    https://github.com/apache/guacamole-client/pull/356

    GUACAMOLE-699: Add helper script for verifying translations.

    This change adds a utility script, `guacamole/util/check-translation.py`, 
which performs automated comparisons between the JSON files that define 
Guacamole's translated strings.
    
    By default, strings which are present in English but absent in the 
translation will be listed (these will need to be added), as well as strings 
which are present in the translation but not in English (these are likely 
incorrect and should be removed). These checks can be disabled with command 
line options, if desired.
    
    An additional duplicate string check can be enabled to test whether strings 
were incorrectly copied verbatim from English without being translated at all. 
This check includes some obvious exclusions (empty strings, simple numbers, 
protocol names, "Apache Guacamole"), but will likely produce false positives. 
It is disabled by default unless requested on the command line.
    
    Usage
    -----
    
    ```
    usage: check-translation.py [-h] [--no-missing] [--no-unused] 
[--check-copied]
                                [ORIGINAL] TRANSLATED
    
    Compares two JSON translation files, as used by the Apache Guacamole web
    application, listing the strings which appear to be missing or incorrect.
    
    positional arguments:
      ORIGINAL        The JSON file which should be used as the basis for
                      comparison. This should be JSON which can be expected to
                      contain every string used by the web application and no
                      others. Typically, this will be the primary, original
                      language of the web application. In the case of Apache
                      Guacamole, this should be English. If omitted, the file
                      "en.json" within the same directory as TRANSLATED will be
                      used by default.
      TRANSLATED      The JSON file which should be compared against ORIGINAL.
                      This should be the JSON which has been translated from
                      ORIGINAL, and thus should contain the same set of strings 
if
                      the translation is complete.
    
    optional arguments:
      -h, --help      show this help message and exit
      --no-missing    Disables checking for strings which are present in 
ORIGINAL
                      but are missing from TRANSLATED. Assuming ORIGINAL
                      represents the set of strings actually used by the web
                      application, these strings are those which are missing and
                      need to be defined for the translation to be complete. By
                      default, the comparison will check for missing 
translations.
      --no-unused     Disables checking for strings which are present in
                      TRANSLATED but not in ORIGINAL. Assuming ORIGINAL 
represents
                      the set of strings actually used by the web application,
                      these strings are those which are defined by the 
translation
                      but unused. By default, the comparison will check for 
unused
                      translations.
      --check-copied  Enables checking for strings defined in TRANSLATED which 
are
                      identical to the corresponding strings in ORIGINAL. Such
                      strings may have been incorrectly copied verbatim from the
                      original without being translated at all. It is also
                      possible that both languages simply use the same text for
                      that string, and the string is correct. As this test can
                      produce false positives, it is disabled by default.
    ```
    
    Example output
    -------------
    
    ```
    [mjumper@dev-mjumper guacamole]$ ./util/check-translation.py --check-copied 
src/main/webapp/translations/de.json 
    Original language: en (English)
    Translation language: de (Deutsch)
    
    The following strings are missing from the translation and should be added:
    
        APP.ACTION_DOWNLOAD
        APP.ACTION_MANAGE_USER_GROUPS
        APP.ACTION_SHARE
        APP.ERROR_PAGE_UNAVAILABLE
        APP.TEXT_ANONYMOUS_USER
        CLIENT.ACTION_SHARE
        CLIENT.ERROR_CLIENT_207
        CLIENT.ERROR_CLIENT_208
        CLIENT.ERROR_CLIENT_209
        CLIENT.ERROR_CLIENT_20A
        CLIENT.ERROR_CLIENT_20B
        CLIENT.ERROR_TUNNEL_207
        CLIENT.ERROR_TUNNEL_208
        CLIENT.HELP_SHARE_LINK
        CLIENT.INFO_CONNECTION_SHARED
        CLIENT.TEXT_CLIENT_STATUS_UNSTABLE
        LIST.TEXT_ANONYMOUS_USER
        MANAGE_CONNECTION.TABLE_HEADER_HISTORY_REMOTEHOST
        MANAGE_CONNECTION_GROUP.ACTION_CLONE
        MANAGE_SHARING_PROFILE.DIALOG_HEADER_CONFIRM_DELETE
        MANAGE_SHARING_PROFILE.FIELD_HEADER_PRIMARY_CONNECTION
        MANAGE_SHARING_PROFILE.SECTION_HEADER_EDIT_SHARING_PROFILE
        MANAGE_SHARING_PROFILE.TEXT_CONFIRM_DELETE
        MANAGE_USER.FIELD_HEADER_CREATE_NEW_SHARING_PROFILES
        MANAGE_USER.FIELD_HEADER_CREATE_NEW_USER_GROUPS
        MANAGE_USER.HELP_NO_USER_GROUPS
        MANAGE_USER.INFO_NO_USER_GROUPS_AVAILABLE
        MANAGE_USER.SECTION_HEADER_ALL_CONNECTIONS
        MANAGE_USER.SECTION_HEADER_CURRENT_CONNECTIONS
        MANAGE_USER.SECTION_HEADER_USER_GROUPS
        MANAGE_USER_GROUP.ACTION_ACKNOWLEDGE
        MANAGE_USER_GROUP.ACTION_CANCEL
        MANAGE_USER_GROUP.ACTION_CLONE
        MANAGE_USER_GROUP.ACTION_DELETE
        MANAGE_USER_GROUP.ACTION_SAVE
        MANAGE_USER_GROUP.DIALOG_HEADER_CONFIRM_DELETE
        MANAGE_USER_GROUP.DIALOG_HEADER_ERROR
        MANAGE_USER_GROUP.FIELD_HEADER_ADMINISTER_SYSTEM
        MANAGE_USER_GROUP.FIELD_HEADER_CHANGE_OWN_PASSWORD
        MANAGE_USER_GROUP.FIELD_HEADER_CREATE_NEW_CONNECTIONS
        MANAGE_USER_GROUP.FIELD_HEADER_CREATE_NEW_CONNECTION_GROUPS
        MANAGE_USER_GROUP.FIELD_HEADER_CREATE_NEW_SHARING_PROFILES
        MANAGE_USER_GROUP.FIELD_HEADER_CREATE_NEW_USERS
        MANAGE_USER_GROUP.FIELD_HEADER_CREATE_NEW_USER_GROUPS
        MANAGE_USER_GROUP.FIELD_HEADER_USER_GROUP_NAME
        MANAGE_USER_GROUP.FIELD_PLACEHOLDER_FILTER
        MANAGE_USER_GROUP.HELP_NO_MEMBER_USERS
        MANAGE_USER_GROUP.HELP_NO_MEMBER_USER_GROUPS
        MANAGE_USER_GROUP.HELP_NO_USER_GROUPS
        MANAGE_USER_GROUP.INFO_NO_USERS_AVAILABLE
        MANAGE_USER_GROUP.INFO_NO_USER_GROUPS_AVAILABLE
        MANAGE_USER_GROUP.INFO_READ_ONLY
        MANAGE_USER_GROUP.SECTION_HEADER_ALL_CONNECTIONS
        MANAGE_USER_GROUP.SECTION_HEADER_CONNECTIONS
        MANAGE_USER_GROUP.SECTION_HEADER_CURRENT_CONNECTIONS
        MANAGE_USER_GROUP.SECTION_HEADER_EDIT_USER_GROUP
        MANAGE_USER_GROUP.SECTION_HEADER_MEMBER_USERS
        MANAGE_USER_GROUP.SECTION_HEADER_MEMBER_USER_GROUPS
        MANAGE_USER_GROUP.SECTION_HEADER_PERMISSIONS
        MANAGE_USER_GROUP.SECTION_HEADER_USER_GROUPS
        MANAGE_USER_GROUP.TEXT_CONFIRM_DELETE
        PROTOCOL_RDP.FIELD_HEADER_CREATE_RECORDING_PATH
        PROTOCOL_RDP.FIELD_HEADER_DISABLE_BITMAP_CACHING
        PROTOCOL_RDP.FIELD_HEADER_DISABLE_GLYPH_CACHING
        PROTOCOL_RDP.FIELD_HEADER_DISABLE_OFFSCREEN_CACHING
        PROTOCOL_RDP.FIELD_HEADER_DRIVE_NAME
        PROTOCOL_RDP.FIELD_HEADER_ENABLE_AUDIO_INPUT
        PROTOCOL_RDP.FIELD_HEADER_LOAD_BALANCE_INFO
        PROTOCOL_RDP.FIELD_HEADER_PRECONNECTION_BLOB
        PROTOCOL_RDP.FIELD_HEADER_PRECONNECTION_ID
        PROTOCOL_RDP.FIELD_HEADER_PRINTER_NAME
        PROTOCOL_RDP.FIELD_HEADER_RECORDING_EXCLUDE_MOUSE
        PROTOCOL_RDP.FIELD_HEADER_RECORDING_EXCLUDE_OUTPUT
        PROTOCOL_RDP.FIELD_HEADER_RECORDING_INCLUDE_KEYS
        PROTOCOL_RDP.FIELD_HEADER_RECORDING_NAME
        PROTOCOL_RDP.FIELD_HEADER_RECORDING_PATH
        PROTOCOL_RDP.FIELD_HEADER_RESIZE_METHOD
        PROTOCOL_RDP.FIELD_HEADER_SFTP_HOST_KEY
        PROTOCOL_RDP.FIELD_HEADER_SFTP_ROOT_DIRECTORY
        PROTOCOL_RDP.FIELD_HEADER_SFTP_SERVER_ALIVE_INTERVAL
        PROTOCOL_RDP.FIELD_OPTION_RESIZE_METHOD_DISPLAY_UPDATE
        PROTOCOL_RDP.FIELD_OPTION_RESIZE_METHOD_EMPTY
        PROTOCOL_RDP.FIELD_OPTION_RESIZE_METHOD_RECONNECT
        PROTOCOL_RDP.FIELD_OPTION_SERVER_LAYOUT_EN_GB_QWERTY
        PROTOCOL_RDP.FIELD_OPTION_SERVER_LAYOUT_ES_ES_QWERTY
        PROTOCOL_RDP.FIELD_OPTION_SERVER_LAYOUT_FR_CH_QWERTZ
        PROTOCOL_RDP.FIELD_OPTION_SERVER_LAYOUT_JA_JP_QWERTY
        PROTOCOL_RDP.FIELD_OPTION_SERVER_LAYOUT_PT_BR_QWERTY
        PROTOCOL_RDP.FIELD_OPTION_SERVER_LAYOUT_TR_TR_QWERTY
        PROTOCOL_RDP.SECTION_HEADER_GATEWAY
        PROTOCOL_RDP.SECTION_HEADER_LOAD_BALANCING
        PROTOCOL_RDP.SECTION_HEADER_PRECONNECTION_PDU
        PROTOCOL_RDP.SECTION_HEADER_RECORDING
        PROTOCOL_SSH.FIELD_HEADER_BACKSPACE
        PROTOCOL_SSH.FIELD_HEADER_CREATE_RECORDING_PATH
        PROTOCOL_SSH.FIELD_HEADER_CREATE_TYPESCRIPT_PATH
        PROTOCOL_SSH.FIELD_HEADER_HOST_KEY
        PROTOCOL_SSH.FIELD_HEADER_RECORDING_EXCLUDE_MOUSE
        PROTOCOL_SSH.FIELD_HEADER_RECORDING_EXCLUDE_OUTPUT
        PROTOCOL_SSH.FIELD_HEADER_RECORDING_INCLUDE_KEYS
        PROTOCOL_SSH.FIELD_HEADER_RECORDING_NAME
        PROTOCOL_SSH.FIELD_HEADER_RECORDING_PATH
        PROTOCOL_SSH.FIELD_HEADER_SERVER_ALIVE_INTERVAL
        PROTOCOL_SSH.FIELD_HEADER_SFTP_ROOT_DIRECTORY
        PROTOCOL_SSH.FIELD_HEADER_TERMINAL_TYPE
        PROTOCOL_SSH.FIELD_HEADER_TYPESCRIPT_NAME
        PROTOCOL_SSH.FIELD_HEADER_TYPESCRIPT_PATH
        PROTOCOL_SSH.FIELD_OPTION_BACKSPACE_127
        PROTOCOL_SSH.FIELD_OPTION_BACKSPACE_8
        PROTOCOL_SSH.FIELD_OPTION_BACKSPACE_EMPTY
        PROTOCOL_SSH.FIELD_OPTION_TERMINAL_TYPE_ANSI
        PROTOCOL_SSH.FIELD_OPTION_TERMINAL_TYPE_EMPTY
        PROTOCOL_SSH.FIELD_OPTION_TERMINAL_TYPE_LINUX
        PROTOCOL_SSH.FIELD_OPTION_TERMINAL_TYPE_VT100
        PROTOCOL_SSH.FIELD_OPTION_TERMINAL_TYPE_VT220
        PROTOCOL_SSH.FIELD_OPTION_TERMINAL_TYPE_XTERM
        PROTOCOL_SSH.FIELD_OPTION_TERMINAL_TYPE_XTERM_256COLOR
        PROTOCOL_SSH.SECTION_HEADER_BEHAVIOR
        PROTOCOL_SSH.SECTION_HEADER_RECORDING
        PROTOCOL_SSH.SECTION_HEADER_TYPESCRIPT
        PROTOCOL_TELNET.FIELD_HEADER_BACKSPACE
        PROTOCOL_TELNET.FIELD_HEADER_CREATE_RECORDING_PATH
        PROTOCOL_TELNET.FIELD_HEADER_CREATE_TYPESCRIPT_PATH
        PROTOCOL_TELNET.FIELD_HEADER_LOGIN_FAILURE_REGEX
        PROTOCOL_TELNET.FIELD_HEADER_LOGIN_SUCCESS_REGEX
        PROTOCOL_TELNET.FIELD_HEADER_RECORDING_EXCLUDE_MOUSE
        PROTOCOL_TELNET.FIELD_HEADER_RECORDING_EXCLUDE_OUTPUT
        PROTOCOL_TELNET.FIELD_HEADER_RECORDING_INCLUDE_KEYS
        PROTOCOL_TELNET.FIELD_HEADER_RECORDING_NAME
        PROTOCOL_TELNET.FIELD_HEADER_RECORDING_PATH
        PROTOCOL_TELNET.FIELD_HEADER_TERMINAL_TYPE
        PROTOCOL_TELNET.FIELD_HEADER_TYPESCRIPT_NAME
        PROTOCOL_TELNET.FIELD_HEADER_TYPESCRIPT_PATH
        PROTOCOL_TELNET.FIELD_HEADER_USERNAME_REGEX
        PROTOCOL_TELNET.FIELD_OPTION_BACKSPACE_127
        PROTOCOL_TELNET.FIELD_OPTION_BACKSPACE_8
        PROTOCOL_TELNET.FIELD_OPTION_BACKSPACE_EMPTY
        PROTOCOL_TELNET.FIELD_OPTION_TERMINAL_TYPE_ANSI
        PROTOCOL_TELNET.FIELD_OPTION_TERMINAL_TYPE_EMPTY
        PROTOCOL_TELNET.FIELD_OPTION_TERMINAL_TYPE_LINUX
        PROTOCOL_TELNET.FIELD_OPTION_TERMINAL_TYPE_VT100
        PROTOCOL_TELNET.FIELD_OPTION_TERMINAL_TYPE_VT220
        PROTOCOL_TELNET.FIELD_OPTION_TERMINAL_TYPE_XTERM
        PROTOCOL_TELNET.FIELD_OPTION_TERMINAL_TYPE_XTERM_256COLOR
        PROTOCOL_TELNET.SECTION_HEADER_BEHAVIOR
        PROTOCOL_TELNET.SECTION_HEADER_RECORDING
        PROTOCOL_TELNET.SECTION_HEADER_TYPESCRIPT
        PROTOCOL_VNC.FIELD_HEADER_CREATE_RECORDING_PATH
        PROTOCOL_VNC.FIELD_HEADER_RECORDING_EXCLUDE_MOUSE
        PROTOCOL_VNC.FIELD_HEADER_RECORDING_EXCLUDE_OUTPUT
        PROTOCOL_VNC.FIELD_HEADER_RECORDING_INCLUDE_KEYS
        PROTOCOL_VNC.FIELD_HEADER_RECORDING_NAME
        PROTOCOL_VNC.FIELD_HEADER_RECORDING_PATH
        PROTOCOL_VNC.FIELD_HEADER_SFTP_HOST_KEY
        PROTOCOL_VNC.FIELD_HEADER_SFTP_ROOT_DIRECTORY
        PROTOCOL_VNC.FIELD_HEADER_SFTP_SERVER_ALIVE_INTERVAL
        PROTOCOL_VNC.SECTION_HEADER_RECORDING
        SETTINGS_CONNECTIONS.ACTION_NEW_SHARING_PROFILE
        SETTINGS_CONNECTION_HISTORY.ACTION_DOWNLOAD
        SETTINGS_CONNECTION_HISTORY.FILENAME_HISTORY_CSV
        SETTINGS_CONNECTION_HISTORY.TABLE_HEADER_SESSION_REMOTEHOST
        SETTINGS_USERS.TABLE_HEADER_FULL_NAME
        SETTINGS_USERS.TABLE_HEADER_LAST_ACTIVE
        SETTINGS_USERS.TABLE_HEADER_ORGANIZATION
        SETTINGS_USER_GROUPS.ACTION_ACKNOWLEDGE
        SETTINGS_USER_GROUPS.ACTION_NEW_USER_GROUP
        SETTINGS_USER_GROUPS.DIALOG_HEADER_ERROR
        SETTINGS_USER_GROUPS.FIELD_PLACEHOLDER_FILTER
        SETTINGS_USER_GROUPS.FORMAT_DATE
        SETTINGS_USER_GROUPS.HELP_USER_GROUPS
        SETTINGS_USER_GROUPS.SECTION_HEADER_USER_GROUPS
        SETTINGS_USER_GROUPS.TABLE_HEADER_USER_GROUP_NAME
        USER_ATTRIBUTES.FIELD_HEADER_GUAC_EMAIL_ADDRESS
        USER_ATTRIBUTES.FIELD_HEADER_GUAC_FULL_NAME
        USER_ATTRIBUTES.FIELD_HEADER_GUAC_ORGANIZATION
        USER_ATTRIBUTES.FIELD_HEADER_GUAC_ORGANIZATIONAL_ROLE
        USER_MENU.ACTION_MANAGE_USER_GROUPS
        USER_MENU.ACTION_VIEW_HISTORY
    
    The following strings are either NOT defined for the original language or 
are
    expected to be inherited from the original language and should be removed:
    
        CLIENT.ERROR_CLIENT_205
    
    The following strings are identical to the original language and MIGHT be
    untranslated:
    
        APP.ACTION_ACKNOWLEDGE
        APP.FIELD_PLACEHOLDER_FILTER
        CLIENT.NAME_KEY_ALT
        CLIENT.NAME_KEY_ESC
        CLIENT.NAME_KEY_TAB
        CLIENT.NAME_MOUSE_MODE_ABSOLUTE
        CLIENT.NAME_MOUSE_MODE_RELATIVE
        CLIENT.TEXT_FILE_TRANSFER_PROGRESS
        FORM.FIELD_PLACEHOLDER_DATE
        FORM.FIELD_PLACEHOLDER_TIME
        MANAGE_CONNECTION.FIELD_HEADER_NAME
        MANAGE_CONNECTION.INFO_CONNECTION_DURATION_UNKNOWN
        MANAGE_CONNECTION_GROUP.FIELD_HEADER_NAME
        MANAGE_CONNECTION_GROUP.NAME_TYPE_BALANCING
        MANAGE_SHARING_PROFILE.FIELD_HEADER_NAME
        PROTOCOL_RDP.FIELD_HEADER_GATEWAY_HOSTNAME
        PROTOCOL_RDP.FIELD_HEADER_GATEWAY_PORT
        PROTOCOL_RDP.FIELD_HEADER_HOSTNAME
        PROTOCOL_RDP.FIELD_HEADER_PORT
        PROTOCOL_RDP.FIELD_HEADER_SFTP_HOSTNAME
        PROTOCOL_RDP.FIELD_HEADER_SFTP_PASSPHRASE
        PROTOCOL_RDP.FIELD_HEADER_SFTP_PORT
        PROTOCOL_RDP.FIELD_OPTION_SERVER_LAYOUT_FAILSAFE
        PROTOCOL_SSH.FIELD_HEADER_HOSTNAME
        PROTOCOL_SSH.FIELD_HEADER_PASSPHRASE
        PROTOCOL_SSH.FIELD_HEADER_PORT
        PROTOCOL_TELNET.FIELD_HEADER_HOSTNAME
        PROTOCOL_TELNET.FIELD_HEADER_PORT
        PROTOCOL_VNC.FIELD_HEADER_CURSOR
        PROTOCOL_VNC.FIELD_HEADER_HOSTNAME
        PROTOCOL_VNC.FIELD_HEADER_PORT
        PROTOCOL_VNC.FIELD_HEADER_SFTP_HOSTNAME
        PROTOCOL_VNC.FIELD_HEADER_SFTP_PASSPHRASE
        PROTOCOL_VNC.FIELD_HEADER_SFTP_PORT
        PROTOCOL_VNC.FIELD_OPTION_CLIPBOARD_ENCODING_CP1252
        PROTOCOL_VNC.FIELD_OPTION_CLIPBOARD_ENCODING_ISO8859_1
        PROTOCOL_VNC.FIELD_OPTION_CLIPBOARD_ENCODING_UTF_16
        PROTOCOL_VNC.FIELD_OPTION_CLIPBOARD_ENCODING_UTF_8
        PROTOCOL_VNC.SECTION_HEADER_AUDIO
        PROTOCOL_VNC.SECTION_HEADER_REPEATER
        SETTINGS_CONNECTION_HISTORY.INFO_CONNECTION_DURATION_UNKNOWN
    
    220 error(s) total.
    [mjumper@dev-mjumper guacamole]$ 
    ```

You can merge this pull request into a Git repository by running:

    $ git pull https://github.com/mike-jumper/guacamole-client translator-utils

Alternatively you can review and apply these changes as the patch at:

    https://github.com/apache/guacamole-client/pull/356.patch

To close this pull request, make a commit to your master/trunk branch
with (at least) the following in the commit message:

    This closes #356
    
----
commit 28d5a4603d0786ce88e591218ee800f5ebc3480d
Author: Michael Jumper <mjumper@...>
Date:   2019-01-12T09:09:28Z

    GUACAMOLE-699: Add helper script for verifying translations.

----


---

Reply via email to