# README.md - Localize HTML Tidy Thank you for your interest in helping us localize HTML Tidy and LibTidy. Users throughout the world will thank you. The document describes Tidy's localization philosophy and instructs you on how you can use standard `gettext` tools to generate language and region localizations that will work with Tidy. Optionally instructions are included in the event that you want to build Tidy with your new language. ## Contents: - [Introduction](#introduction) - [PO and POT files](#po-and-pot-files) - [H files](#h-files) - [Differences for translators](#differences-for-translators) - [`poconvert.rb` versus `gettext`' tools](#poconvertrb-versus-gettext-tools) - [How to Contribute](#how-to-contribute) - [Find or Create the Translation Files](#find-or-create-the-translation-files) - [Issue a Pull Request to HTML Tidy](#issue-a-pull-request-to-html-tidy) - [Using Git appropriately](#using-git-appropriately) - [Repository Notes](#repository-notes) - [Adding Languages to Tidy](#adding-languages-to-tidy) - [Best Practices](#best-practices) - [Language Inheritance](#language-inheritance) - [String Inheritance](#string-inheritance) - [Base Language First and Regional Variants](#base-language-first-and-regional-variants) - [Positional Parameters](#positional-parameters) - [Testing](#testing) - [Command line option](#command-line-option) - [Changing your locale](#changing-your-locale) - [East Asian Languages](#east-asian-languages) - [gettext](#gettext) - [poconvert.rb](#poconvertrb) - [Create a new POT file](#create-a-new-pot-file) - [Create a new POT file with non-English `msgid` strings](#create-a-new-pot-file-with-non-english-msgid-strings) - [Convert an existing H to PO](#convert-an-existing-h-to-po) - [Convert an existing H to PO using a different `msgid` language](#convert-an-existing-h-to-po-using-a-different-msgid-language) - [Create a blank PO file for a particular region](#create-a-blank-po-file-for-a-particular-region) - [Create a Tidy Language Header H file](#create-a-tidy-language-header-h-file) - [Prepare your non-English PO for a PR](#prepare-your-non-english-po-for-a-pr) - [Update your PO to match the new POT](#update-your-po-to-match-the-new-pot) - [Help Tidy Get Better](#help-tidy-get-better) ## Introduction HTML Tidy is built around the localization file `language_en.h`; without this file HTML Tidy will not work. As such _all_ language localization work originates from this single file. Language localizations use header files that are identical to `language_en.h`, except that they have different strings. For the convenience of language translators, though, Tidy source code includes a Ruby `poconvert.rb` script that enables _optional_ gettext PO/POT work streams that may be more comfortable to them. ### PO and POT files HTML Tidy provides PO and POT files for language translations. The file `tidy.pot` is the correct template to use as a basis for new translations. In a typical `gettext` workflow a translator will use the `tidy.pot` file to create a language translation PO file that contains original English strings and the translated strings. If a language has already been translated (or if the translation has begun) then PO files may already exist. These files are named `language_ll.po` or `langage_ll_CC.po`, where `ll` represents the language code, and optionally, `CC` represents the region code of the translation. Tidy does not use MO files that `gettext` tools generate from PO files. Please note that these PO and POT files are provided for translator convenience only. Tidy's [header files](#h-files) constitute the true, controlled source code for Tidy. ### H files Tidy does not use `gettext` to display strings and so `gettext`-generated MO files are not necessary. Instead translated PO files must be converted to Tidy's language header H file format. Translators are not required to perform this step, but we provide a tool to perform this function if desired. ### Differences for translators Experienced users and translators of PO files may note that we use the PO file's `msgctxt` field a bit uniquely. Rather than point to a line in the source code, it contains a reference to the string's identifier. Because the PO format does not allow for arbitrary metadata this is a requirement for generating our header files. If you're the type of translator the does dig into the source code, then this `msgtext` symbol is still useful to you and adds a single extra step to finding where a string is in context: a symbol or string search using the `msgctxt` value will reveal the context in source code. Finally the `msgid` field is a throwaway; Tidy's language tools do not use this value and so it's only for the translator's convenience. This fact makes it convenient for translators to translate from languages other than English, which is fully supported by our tools. ### `poconvert.rb` versus `gettext`' tools Please don't use `gettext`' tools with our PO and POT files (unless you are using our strings for a different project). Instead all workflows can be accomplished with our `poconvert.rb` tool. [More information about this tool](#h-files) can be found below. ## How to Contribute ### Find or Create the Translation Files If you've not already cloned the HTML Tidy source code repository that will be your first step. In the `localize/translations/` directory you can find existing languages, e.g., - `tidy.pot` (Tidy's POT template for translations). - `language_en_gb.po` (British English variants for the built in language) - …and perhaps more. In the `src/` directory you can find the master files for existing languages, e.g., - `language_en.h` (Tidy's native, built-in language, mostly U.S. English) - `language_en_gb.po` (British English variants for the built in language) - …and perhaps more. Although the header files are the master files for HTML Tidy, we understand that not all potential translators want to edit C files directly. Therefore as an option, the following workflow to use POT and PO files is offered. If the language that you want to work on is already present: - Simply open the file in your favorite PO editor and then get to work. - Note that although you can use a text editor, we recommend that you use a dedicated PO editor so that you don't accidentally make the file illegible to our conversion utility. If the language that you want to work on is _not_ already present: - You can open `tidy.pot` in your favorite PO editor and use its functions to begin a new translation into your desired language. - Note that although you can use a text editor, we recommend that you use a dedicated PO editor so that you don't accidentally make the file illegible to our conversion utility. - To perform the work manually: - Copy `tidy.pot` to `language_ll.po` (for a non-regional variant, or base language), or to `language_ll_cc.po` (for a region-specific variant), where `ll` indicates the two letter language code and `cc` indicates the two letter region or country code. - Change the pertinent PO header section accordingly. - Use `poconvert.rb` to generate a PO: - `poconvert.rb msginit --locale ll`, where `ll` indicates the language code for the language you want to translate to. The tool recognizes the same languages as `gettext`' `msginit`. If your chosen language is not supported, then please see the manual method, above. - See also `poconvert.rb help` for more options. - See GNU's [The Format of PO Files](https://www.gnu.org/software/gettext/manual/html_node/PO-Files.html) for more specific instructions and important information. ### Issue a Pull Request to HTML Tidy Once your translation is complete commit your entire HTML Tidy repository to GitHub and issue a pull request (PR) against the `master` branch. If accepted a friendly developer will convert your PO into a format useful to Tidy if your PR is a PO, or will simply merge your changed header file if you changed it directly. You are also welcome to perform any conversions yourself, add new languages to Tidy, and issue a PR for the whole change. ### Using Git appropriately 1. Fork the repository to your GitHub account. 2. Optionally create a **topical branch** - a branch whose name is succinct but explains what you're doing, such as "localize Portuguese". 3. Make your changes, committing at logical breaks. 4. Push your work to your personal account. 5. [Create a pull request](https://help.github.com/articles/using-pull-requests). 6. Watch for comments or acceptance. ### Repository Notes If you are working with PO files then please **only** commit PO files with _English_ `msgid` fields. The `gettext` convention specifies only English `msgid`, and other translators may not understand the original strings. Our `poconvert.rb` script can generate PO files using another language as `msgid`. This can be very useful if it's easier for you to translate from another language instead of English. It can also be useful for translating from a base language to a regional variant, such as from Spanish to Mexican Spanish. If you choose to work locally with a non-English PO, you can easily convert your PO to a Tidy header file and back to an English-based PO using our `poconvert.rb` script. See its documentation (`poconvert.rb help`) for instructions. ## Adding Languages to Tidy Although we don't require you to follow these steps to contribute a language to Tidy, you may want to add the language to Tidy yourself to test the translation, or to save one of the developer team a few extra steps. - Generate the header files if necessary: - Convert your PO file to a Tidy header file by executing `poconvert.rb msgfmt `. Note that on Windows you will likely have to preface this line with `ruby`. - The tool should generate a file named `language_ll_cc.h` in the working directory, where `ll_cc` will be replaced with the language/region of your translation. - Copy this `.h` file into `src/`. - Modify Tidy's source: - Edit the file `src/language.c` to ensure that the new `.h` file you added is in the `#include` section. - Look for the `static tidyLanguagesType tidyLanguages` structure starting near line 40, and look for the comment `These languages are installed.`. You can add your new language to the list along with the other languages present, following the same format. - Build Tidy: - Build Tidy per the usual instructions, and try it out using the `-lang` option. ## Best Practices ### Language Inheritance HTML Tidy will fallback from the specified language to the base language and then finally to the default English as required. This means, for example, a programmer might set `libtidy` to use “es_mx”, and if it doesn’t exist Tidy will automatically use “es”. If that doesn’t exist `libtidy` will continue to use whatever language it is currently using. ### String Inheritance HTML Tidy will also fallback for individual strings. For example if `libtidy` is set to use “es_mx” and a particular string is requested and not found, the library will look for the string in “es”. If the string is not found there then the “en” string will be given. ### Base Language First and Regional Variants Because of this inheritance we hope to localize base languages first, as the only strings then required for regional variants are the strings that differ. This will help us keep HTML Tidy and `libtidy` small. If you are working on a regional variation (such as “us_CA”) please only localize strings that are actually _different_ from the base language! ### Positional Parameters Please note that HTML Tidy does not currently support positional parameters. Due to the nature of most of Tidy's output, it's not expected that they will be required. In any case, please translate strings so that substitution values are in the same order as the original string. ## Testing We hope to develop a comprehensive test suite in the future, but in the meantime you can test localized output like this. ### Command line option Use the `-lang`/`-language` option and specify a POSIX or Windows language name. This option should be first option used because the console application parses and acts on options first-in, first-out. ### Changing your locale On Unix/Mac and Linux operating systems you can change your shell’s locale temporarily with: `export LANG=en_GB` `export LC_ALL=en_GB` …substituting, of course the language of your choice. ### East Asian Languages East Asian languages are completely supported and have been tested on Linux, Mac OS X, and Windows, although Windows requires you to set your operating system (not the console locale!) to an East Asian locale to enable this in Windows Console and PowerShell. Note that PowerShell ISE always supports East Asian languages without requiring you to change your operating system locale. ## gettext Although HTML Tidy uses `gettext`-compatible tools and PO files for language localization, Tidy itself does _not_ use `gettext`. Tidy's build philosophy is build it anywhere and build it with anything. As `gettext` is not universally available on every platform under the sun, Tidy cannot count on `gettext`. Instead Tidy builds all translations into its library (and command line executable if built monolithically), and can run on virtually any general purpose computer with any operating system. While this does not pose a significant problem for storage or execution space on modern PC's, we understand that certain applications may still be space critical. As such it's trivial to build Tidy without this extra language support using the `-DSUPPORT_LOCALIZATIONS=NO` switch. ## poconvert.rb Tidy's source code includes a Ruby batch file called `poconvert.rb` which can be used to generate POT, PO, and H files, and convert them back and forth. It has been designed to work in a similar fashion as `gettext`'s tools, and includes conveniences that let translators work in different source languages. Please use `poconvert.rb help` for complete information (`ruby poconvert.rb help` on Windows). Note that you must install Ruby on your system, as well as install the required dependencies. These can be manually installed with `[sudo] gem install xxx`, where `xxx` represents the packages listed in `Gemfile`. For convenience, if you have the Bundler gem installed, you can `bundle install` for automated dependency installation. Also take note of these two important characteristics: - `poconvert.rb` is currently dependent on its current path. You can move it from its current location, but you will have to change the values of the `@@default_en` and `@@header_template` variables within the script. - All files will be output in the current working directory. This will prevent accidental overwrites of important files while we all get used to the workflows. Below are some sample workflows. ### Create a new POT file Although we provide `tidy.pot` in the source, you can generate your own. `./poconvert.rb xgettext` This will put a fresh, new copy of `tidy.pot` in the working directory. ### Create a new POT file with non-English `msgid` strings Although `gettext` officially recognizes English as the one, true source language for PO and POT files, if you're more comfortable translating from a non-English language, we can support you. `./poconvert.rb xgettext ` Where `` is the path to an existing Tidy language header file. This will produce a `tidy.pot` using the translated strings as `msgid`, using English as a backup when translated strings are not present. This can be valuable in producing regional variant translations, e.g., when translating from `es` to `es_mx`. ### Convert an existing H to PO In many cases you may want to have a fresh PO generated from a Tidy H file. This can be accomplished with: `./poconvert.rb msgunfmt ` ### Convert an existing H to PO using a different `msgid` language If you want to generate a fresh PO file from a Tidy H file, but _also_ want to have untranslated strings from a language other than English, try: `./poconvert.rb msgunfmt --baselang=` ### Create a blank PO file for a particular region `./poconvert.rb msginit` or `./poconvert.rb msginit --locale=LOCALE` The first example will try to guess your current region, and the second will use a region specified. Tidy only knows about the same regions that `gettext` knows; if our `msginit` does not recognize the region you specify, you will have to create a new PO and modify the region settings yourself. To create the blank PO using `msgid` strings from a different Tidy language, you can use: `./poconvert.rb msginit [--locale=LOCALE]` ### Create a Tidy Language Header H file When you're ready to include the language in Tidy, you can generate its header file with: `./poconvert.rb msgfmt ` In the event you are creating a regional variant of a language, it's an excellent idea to have Tidy exclude strings that are already present in the parent language in order to reduce library and executable size. For example if `es` already includes the string "archivo" there is no reason for your translation to `es_mx` to include it, too. You can tell `poconvert.rb` to exclude strings matching another localization like so: `./poconvert.rb msgfmt --baselang=` ### Prepare your non-English PO for a PR Although we have provided tools to allow you to work in languages other than English, we can only accept PO's in the repository that have English `msgid` fields. It's easy to convert your PO back to English: `./poconvert msgfmt ` `./poconvert msgunfmt ` The first command converts your non-standard PO into a Tidy Language Header file, and the second will create a fresh, new PO file from the header that you've just created. ### Update your PO to match the new POT If Tidy's POT changes, e.g., new strings are added, new comments, etc., the simplest way to update your PO is to convert it to a header (which normalizes it to the latest Tidy standard), and then convert the header to a new PO again. `./poconvert msgfmt ` `./poconvert msgunfmt ` ## Help Tidy Get Better It goes without saying **all help is appreciated**. We need to work together to make Tidy better!