| # Core GIT Translations | |
| This directory holds the translations for the core of Git. This document | |
| describes how you can contribute to the effort of enhancing the language | |
| coverage and maintaining the translation. | |
| The localization (l10n) coordinator, Jiang Xin <worldhello.net@gmail.com>, | |
| coordinates our localization effort in the l10n coordinator repository: | |
| https://github.com/git-l10n/git-po/ | |
| We will use XX as an alias to refer to the language translation code in | |
| the following paragraphs, for example we use "po/XX.po" to refer to the | |
| translation file for a specific language. But this doesn't mean that | |
| the language code has only two letters. The language code can be in one | |
| of two forms: "ll" or "ll\_CC". Here "ll" is the ISO 639 two-letter | |
| language code and "CC" is the ISO 3166 two-letter code for country names | |
| and subdivisions. For example: "de" for German language code, "zh\_CN" | |
| for Simplified Chinese language code. | |
| ## Contributing to an existing translation | |
| As a contributor for a language XX, you should first check TEAMS file in | |
| this directory to see whether a dedicated repository for your language XX | |
| exists. Fork the dedicated repository and start to work if it exists. | |
| Sometime, contributors may find that the translations of their Git | |
| distributions are quite different with the translations of the | |
| corresponding version from Git official. This is because some Git | |
| distributions (such as from Ubuntu, etc.) have their own l10n workflow. | |
| For this case, wrong translations should be reported and fixed through | |
| their workflows. | |
| ## Creating a new language translation | |
| If you are the first contributor for the language XX, please fork this | |
| repository, prepare and/or update the translated message file "po/XX.po" | |
| (described later), and ask the l10n coordinator to pull your work. | |
| If there are multiple contributors for the same language, please first | |
| coordinate among yourselves and nominate the team leader for your | |
| language, so that the l10n coordinator only needs to interact with one | |
| person per language. | |
| ## Translation Process Flow | |
| The overall data-flow looks like this: | |
| +-------------------+ +------------------+ | |
| | Git source code | ----(2)---> | L10n coordinator | | |
| | repository | <---(5)---- | repository | | |
| +-------------------+ +------------------+ | |
| | | ^ | |
| (1) (3) (4) | |
| V v | | |
| +----------------------------------+ | |
| | Language Team XX | | |
| +----------------------------------+ | |
| - Translatable strings are marked in the source file. | |
| - Language teams can start translation iterations at any time, even | |
| before the l10n window opens: | |
| + Pull from the master branch of the source (1) | |
| + Update the message file by running "make po-update PO\_FILE=po/XX.po" | |
| + Translate the message file "po/XX.po" | |
| - The L10n coordinator pulls from source and announces the l10n window | |
| open (2) | |
| - Language team pulls from the l10n coordinator, starts another | |
| translation iteration against the l10n coordinator's tree (3) | |
| + Run "git pull --rebase" from the l10n coordinator | |
| + Update the message file by running "make po-update PO\_FILE=po/XX.po" | |
| + Translate the message file "po/XX.po" | |
| + Squash trivial l10n git commits using "git rebase -i" | |
| - Language team sends pull request to the l10n coordinator (4) | |
| - L10n coordinator checks and merges | |
| - L10n coordinator asks the result to be pulled (5). | |
| ## Dynamically generated POT files | |
| POT files are templates for l10n contributors to create or update their | |
| translation files. We used to have the "po/git.pot" file which was | |
| generated by the l10n coordinator, but this file had been removed from | |
| the tree. | |
| The two POT files "po/git.pot" and "po/git-core.pot" can be created | |
| dynamically when necessary. | |
| L10n contributors use "po/git.pot" to prepare translations for their | |
| languages, but they are not expected to modify it. The "po/git.pot" file | |
| can be generated manually with the following command: | |
| ```shell | |
| make po/git.pot | |
| ``` | |
| The "po/git-core.pot" file is the template for core translations. A core | |
| translation is the minimum set of work necessary to complete a | |
| translation of a new language. Since there are more than 5000 messages | |
| in the full set of template message file "po/git.pot" that need to be | |
| translated, this is not a piece of cake for new language contributors. | |
| The "core" template file "po/git-core.pot" can be generated manually | |
| by running: | |
| ```shell | |
| make po/git-core.pot | |
| ``` | |
| ## Initializing a "XX.po" file | |
| (This is done by the language teams). | |
| If your language XX does not have translated message file "po/XX.po" yet, | |
| you add a translation for the first time by running: | |
| ```shell | |
| make po-init PO_FILE=po/XX.po | |
| ``` | |
| where XX is the locale, e.g. "de", "is", "pt\_BR", "zh\_CN", etc. | |
| The newly generated message file "po/XX.po" is based on the core pot | |
| file "po/git-core.pot", so it contains only a minimal set of messages | |
| and it's a good start for a new language contribution. | |
| Once you are done testing the translation (see below), commit the result | |
| and ask the l10n coordinator to pull from you. | |
| ## Updating a "XX.po" file | |
| (This is done by the language teams). | |
| If you are replacing translation strings in an existing "XX.po" file to | |
| improve the translation, just edit the file. | |
| If you want to find new translatable strings in source files of upstream | |
| repository and propagate them to your "po/XX.po", run command: | |
| ```shell | |
| make po-update PO_FILE=po/XX.po | |
| ``` | |
| It will: | |
| - Call "make po/git.pot" to generate new "po/git.pot" file | |
| - Call "msgmerge --add-location --backup=off -U po/XX.po po/git.pot" | |
| to update your "po/XX.po" | |
| - The "--add-location" option for msgmerge will add location lines, | |
| and these location lines will help translation tools to locate | |
| translation context easily. | |
| ## Fuzzy translation | |
| Fuzzy translation is a translation marked by comment "fuzzy" to let you | |
| know that the translation is out of date because the "msgid" has been | |
| changed. A fuzzy translation will be ignored when compiling using "msgfmt". | |
| Fuzzy translation can be marked by hands, but for most cases they are | |
| marked automatically when running "msgmerge" to update your "XX.po" file. | |
| After fixing the corresponding translation, you must remove the "fuzzy" | |
| tag in the comment. | |
| ## Testing your changes | |
| (This is done by the language teams, after creating or updating "XX.po" file). | |
| Before you submit your changes go back to the top-level and do: | |
| ```shell | |
| make | |
| ``` | |
| On systems with GNU gettext (i.e. not Solaris) this will compile your | |
| changed PO file with `msgfmt --check`, the --check option flags many | |
| common errors, e.g. missing printf format strings, or translated | |
| messages that deviate from the originals in whether they begin/end | |
| with a newline or not. | |
| L10n coordinator will check your contributions using a helper program | |
| (see "PO helper" section below): | |
| ```shell | |
| git-po-helper check-po po/XX.po | |
| git-po-helper check-commits <rev-list-opts> | |
| ``` | |
| ## Preparing a "XX.po" file for commit | |
| Once you are done testing the translation, it's better to commit a | |
| location-less "po/XX.po" file to save repository space and make a | |
| user-friendly patch for review. | |
| To save a location-less "po/XX.po" automatically in the repository, | |
| follow these steps: | |
| First, check which filter is configured for your "po/XX.po" file: | |
| ``` | |
| git check-attr filter po/XX.po | |
| ``` | |
| The filter configuration is defined in the "po/.gitattributes" file. | |
| Then define the driver for the filter. Most languages use the | |
| "gettext-no-location" clean filter, which strips out both filenames and line | |
| numbers from location comments. To set this up, run the following command: | |
| ```shell | |
| git config --global filter.gettext-no-location.clean \ | |
| "msgcat --no-location -" | |
| ``` | |
| Some PO files use the "gettext-no-line-number" clean filter, which keeps | |
| filenames but strips line numbers. This filter requires gettext 0.20 or | |
| later. The only benefit is being able to locate source files from location | |
| comments when the .po file is not updated from the POT via `make po-update`. | |
| ```shell | |
| git config --global filter.gettext-no-line-number.clean \ | |
| "msgcat --add-location=file -" | |
| ``` | |
| You're now ready to ask the l10n coordinator to pull from you. | |
| ## Marking strings for translation | |
| (This is done by the core developers). | |
| Before strings can be translated they first have to be marked for | |
| translation. | |
| Git uses an internationalization interface that wraps the system's | |
| gettext library, so most of the advice in your gettext documentation | |
| (on GNU systems `info gettext` in a terminal) applies. | |
| General advice: | |
| - Don't mark everything for translation, only strings which will be | |
| read by humans (the porcelain interface) should be translated. | |
| The output from Git's plumbing utilities will primarily be read by | |
| programs and would break scripts under non-C locales if it was | |
| translated. Plumbing strings should not be translated, since | |
| they're part of Git's API. | |
| - Adjust the strings so that they're easy to translate. Most of the | |
| advice in `info '(gettext)Preparing Strings'` applies here. | |
| - Strings referencing numbers of items may need to be split into singular and | |
| plural forms; see the Q\_() wrapper in the C sub-section below for an | |
| example. | |
| - If something is unclear or ambiguous you can use a "TRANSLATORS" | |
| comment to tell the translators what to make of it. These will be | |
| extracted by xgettext(1) and put in the "po/\*.po" files, e.g. from | |
| git-am.sh: | |
| ```shell | |
| # TRANSLATORS: Make sure to include [y], [n], [e], [v] and [a] | |
| # in your translation. The program will only accept English | |
| # input at this point. | |
| gettext "Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all " | |
| ``` | |
| Or in C, from builtin/revert.c: | |
| ```c | |
| /* TRANSLATORS: %s will be "revert" or "cherry-pick" */ | |
| die(_("%s: Unable to write new index file"), action_name(opts)); | |
| ``` | |
| We provide wrappers for C, Shell and Perl programs. Here's how they're | |
| used: | |
| ### C | |
| Include builtin.h at the top, it'll pull in gettext.h, which | |
| defines the gettext interface. Consult with the list if you need to | |
| use gettext.h directly. | |
| The C interface is a subset of the normal GNU gettext | |
| interface. We currently export these functions: | |
| - \_() | |
| Mark and translate a string. E.g.: | |
| ```c | |
| printf(_("HEAD is now at %s"), hex); | |
| ``` | |
| - Q\_() | |
| Mark and translate a plural string. E.g.: | |
| ```c | |
| printf(Q_("%d commit", "%d commits", number_of_commits)); | |
| ``` | |
| This is just a wrapper for the ngettext() function. | |
| - N\_() | |
| A no-op pass-through macro for marking strings inside static | |
| initializations, e.g.: | |
| ```c | |
| static const char *reset_type_names[] = { | |
| N_("mixed"), N_("soft"), N_("hard"), N_("merge"), N_("keep"), NULL | |
| }; | |
| ``` | |
| And then, later: | |
| ```c | |
| die(_("%s reset is not allowed in a bare repository"), | |
| _(reset_type_names[reset_type])); | |
| ``` | |
| Here `_()` couldn't have statically determined what the translation | |
| string will be, but since it was already marked for translation | |
| with `N_()` the look-up in the message catalog will succeed. | |
| ### Shell | |
| The Git gettext shell interface is just a wrapper for | |
| gettext.sh. Import it right after git-sh-setup like this: | |
| ```shell | |
| . git-sh-setup | |
| . git-sh-i18n | |
| ``` | |
| And then use the `gettext` or `eval_gettext` functions: | |
| ```shell | |
| # For constant interface messages: | |
| gettext "A message for the user"; echo | |
| # To interpolate variables: | |
| details="oh noes" | |
| eval_gettext "An error occurred: \$details"; echo | |
| ``` | |
| In addition we have wrappers for messages that end with a trailing | |
| newline. I.e. you could write the above as: | |
| ```shell | |
| # For constant interface messages: | |
| gettextln "A message for the user" | |
| # To interpolate variables: | |
| details="oh noes" | |
| eval_gettextln "An error occurred: \$details" | |
| ``` | |
| More documentation about the interface is available in the GNU info | |
| page: `info '(gettext)sh'`. Looking at git-am.sh (the first shell | |
| command to be translated) for examples is also useful: | |
| ```shell | |
| git log --reverse -p --grep=i18n git-am.sh | |
| ``` | |
| ### Perl | |
| The Git::I18N module provides a limited subset of the | |
| Locale::Messages functionality, e.g.: | |
| ```perl | |
| use Git::I18N; | |
| print __("Welcome to Git!\n"); | |
| printf __("The following error occurred: %s\n"), $error; | |
| ``` | |
| Run `perldoc perl/Git/I18N.pm` for more info. | |
| ## Testing marked strings | |
| Git's tests are run under `LANG=C LC_ALL=C`. So the tests do not need be | |
| changed to account for translations as they're added. | |
| ## AI-assisted translation and review | |
| [po/AGENTS.md](AGENTS.md) describes optional workflows for AI coding assistants | |
| that help with Git localization: updating templates and PO files, translating | |
| `po/XX.po`, and reviewing translations. Those workflows often use git-po-helper | |
| together with the gettext tools; see the PO helper section below for what the | |
| program does and how to build or install it. AI assistants are optional; treat | |
| their output as a draft and have it reviewed by contributors who know Git and | |
| the target language well. | |
| When you prompt a coding assistant, mention that file explicitly, for example: | |
| "Translate po/XX.po with reference to po/AGENTS.md" (replace XX with your | |
| language code). | |
| ## PO helper | |
| `git-po-helper` is a helper for Git l10n coordinators and contributors. It | |
| automates checks that contributions follow project conventions (PO syntax, | |
| commit messages, which paths may change, and related rules) and can work with | |
| AI coding agents for tasks such as translating new entries, and reviewing | |
| translations. | |
| Build and install instructions are in [git-po-helper/README][]. | |
| ## Conventions | |
| There are some conventions that l10n contributors must follow: | |
| - The subject of each l10n commit should be prefixed with "l10n: ". | |
| - Do not use non-ASCII characters in the subject of a commit. | |
| - The length of commit subject (first line of the commit log) should | |
| be no more than 50 characters, and the length of other lines of the | |
| commit log should be no more than 72 characters. | |
| - Add "Signed-off-by" trailer to your commit log, like other commits | |
| in Git. You can automatically add the trailer by committing with | |
| the following command: | |
| ```shell | |
| git commit -s | |
| ``` | |
| - Check syntax with "msgfmt" or the following command before creating | |
| your commit: | |
| ```shell | |
| git-po-helper check-po <XX.po> | |
| ``` | |
| - Squash trivial commits to make history clear. | |
| - DO NOT edit files outside "po/" directory. | |
| - Other subsystems ("git-gui", "gitk", and Git itself) have their | |
| own workflow. See [Documentation/SubmittingPatches][] for | |
| instructions on how to contribute patches to these subsystems. | |
| To contribute for a new l10n language, contributor should follow | |
| additional conventions: | |
| - Initialize proper filename of the "XX.po" file conforming to | |
| iso-639 and iso-3166. | |
| - Must complete a minimal translation based on the "Core | |
| translation". See that section above. | |
| - Add a new entry in the "po/TEAMS" file with proper format, and check | |
| the syntax of "po/TEAMS" by running the following command: | |
| ```shell | |
| git-po-helper team --check | |
| ``` | |
| [git-po-helper/README]: https://github.com/git-l10n/git-po-helper#readme | |
| [Documentation/SubmittingPatches]: Documentation/SubmittingPatches |