# Localizing Ghostty: The Translators' Guide

First of all, thanks for helping us localize Ghostty!

To begin contributing, please make sure that you have installed `gettext`
on your system, which should be available under the `gettext` package
for most Linux and macOS package managers.

You can install `gettext` on Windows in a few ways:

- Through [an installer](https://mlocati.github.io/articles/gettext-iconv-windows.html);
- Through package managers like Scoop (`scoop install gettext`) and
  WinGet (`winget install gettext`) which repackages the aforementioned installer;
- Through Unix-like environments like [Cygwin](https://cygwin.com/cygwin/packages/summary/gettext.html)
  and [MSYS2](https://packages.msys2.org/base/gettext).

> [!WARNING]
>
> Unlike what some tutorials suggest, **we do not recommend installing `gettext`
> through GnuWin32**, since it hasn't been updated since 2010 and very likely
> does not work on modern Windows versions.

You can verify that `gettext` has been successfully installed by running the
command `gettext -V`. If everything went correctly, you should see an output like this:

```console
$ gettext -V
gettext (GNU gettext-runtime) 0.21.1
Copyright (C) 1995-2022 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Written by Ulrich Drepper.
```

With this, you're ready to localize!

## Locale names

A locale name always consists of a [two letter language
code](https://en.wikipedia.org/wiki/List_of_ISO_639_language_codes) (e.g.
`de`, `es`, `fr`). Sometimes, for languages that have regional variations
(such as `zh` and `es`), the locale name includes a [two letter
country code](https://en.wikipedia.org/wiki/List_of_ISO_3166_country_codes).
One example is `es_AR` for Spanish as spoken in Argentina.

Full locale names are more complicated, but Ghostty does not use all parts. [The
`gettext` documentation](https://www.gnu.org/software/gettext/manual/gettext.html#Locale-Names-1)
has more information on locale names.

## Translation file names

All translation files lie in the `po/` directory, including the main _template_
file called `com.mitchellh.ghostty.pot`. **Do not edit this file.** The
template is generated automatically from Ghostty's code and resources, and is
intended to be regenerated by code contributors. If there is a problem with
the template file, please reach out to a code contributor.

Translation file names consist of the locale name and the extension
`.po`. For example: `de.po`, `zh_CN.po`.

## Editing translation files

> [!NOTE]
>
> If the translation file for your locale does not yet exist, see the
> ["Creating new translation files" section](#creating-new-translation-files)
> of this document on how to create one.

The translation file contains a list of entries that look like this:

```po
#. Translators: the category in the right-click context menu that contains split items for all directions
#: src/apprt/gtk/ui/1.0/menu-surface-context-menu.blp:38
#  译注：其他终端程序对 Split 皆有不同翻译，此处采取最直观的翻译方式
msgctxt "Context menu"
msgid "Split"
msgstr "分屏"
```

The `msgid` line contains the original string in English, and the `msgstr` line
should contain the translation for your language. Occasionally there will also
be a `msgctxt` line that differentiates strings that are identical in English,
based on its context.

Lines beginning with `#` are comments, of which there are several kinds:

- Pay attention to comments beginning with `#.`. They are comments left
  by _developers_ providing more context to the string.

- Comments that begin with `#:` are _source comments_: they link
  the string to source code or resource files. You normally don't need to
  consider these in your translations.

- You may also leave comments of your own to be read by _other translators_,
  beginning with `# `. These comments are specific to your locale and don't
  affect translators in other locales.

The first entry of the `.po` file has an empty `msgid`. This entry is special
as it stores the metadata related to the `.po` file itself. You should update
`PO-Revision-Date` and `Last-Translator` once you have finished your edits, but
you normally do not need to modify other metadata.

## Creating new translation files

You can use the `msginit` tool to create new translation files.

Run the command below, replacing `X` with your [locale name](#locale-names).

```console
$ msginit -i po/com.mitchellh.ghostty.pot -l X -o "po/X.po"
```

`msginit` may prompt you for other information such as your email address,
which should be filled in accordingly. You can then add your translations
within the newly created translation file.

Afterwards, you need to update the list of known locales within Ghostty's
build system. To do so, open `src/os/i18n_locales.zig` and find the list of
locale names after the comments, then add your locale name into the list.

The order matters, so make sure to place your locale name in the correct
position. Read the comments present in the file for more details on the order.
If you're unsure, place it at the end of the list.

```zig
const locales = [_][]const u8{
    "zh_CN",
    // <- Add your locale name here (probably)
}
```

You should then be able to run `zig build run` and see your translations in
action! See the ["Viewing translations" section](#viewing-translations) below.

Before opening a pull request with the new translation file, you should also
update the `CODEOWNERS` file. This is described in more detail in the
["Localization teams" section](#localization-teams)—don't forget to read that
section before submitting a pull request!

## Viewing translations

> [!NOTE]
> The localization system is not yet implemented for macOS, so it is not
> possible to view your translations there.

Simply run `zig build run`. Ghostty uses your system language by default; if
your translations are for a different language, use
`zig build run -- --language=X` (where `X` is your locale name). You can
alternatively set the `LANGUAGE` environment variable to your locale name.

On some desktop environments, such as KDE Plasma, Ghostty uses server-side
decorations by default. This hides many strings from the UI, which is
undesirable when viewing your translations. You can force Ghostty to use
client-side decorations with `zig build run -- --window-decoration=client`.

Some strings are present in multiple places! A notable example is the context
menus: the hamburger menu in the header bar duplicates many strings present in
the right click menu.

## Localization teams

Every locale has a _localization team_ consisting of the locale's _maintainers_.
These maintainers are responsible for upkeep of their locale's translations.
Anyone can contribute strings for any language's translations, and may also
volunteer to join that locale's team; a locale maintainer is only distinguished
from other speakers of the language in that:

1. Locale maintainers _declare commitment_ to updating their translations.
2. Locale maintainers are _occasionally pinged_, via GitHub's @mentions, when
   there are untranslated strings.
3. Locale maintainers are _informed of updates_ to the translations they
   maintain via GitHub's review requests.

That's all there is to it, really. If you wish, you may leave your localization
teams at any point in the future.

Each localization team must have at least two maintainers, who can review each
other's translations. Likewise, if you open a pull request for a new language,
it won't be merged until at least two people volunteer. You—the creator of the
PR—likely intend to continue helping out with them, so please make it clear
up-front if that is not your intent.

There is no requirement that locale maintainers must not know each other. If you
are adding translations for languages that have few speakers, you might wish to
ask a friend of yours who also speaks that language whether they'd be willing to
help with Ghostty translations.

### `CODEOWNERS`

Localization teams are represented as teams in the Ghostty GitHub organization.
GitHub reads a `CODEOWNERS` file, which maps files to teams, to identify
relevant maintainers. When **introducing support for a language**, you should
add the `.po` file to `CODEOWNERS`.

To do this, find the `# Localization` section near the bottom of the file, and
add a line like so:

```diff
 # Localization
 /po/README_TRANSLATORS.md @ghostty-org/localization
 /po/com.mitchellh.ghostty.pot @ghostty-org/localization
 /po/zh_CN.po @ghostty-org/zh_CN
+/po/X.po @ghostty-org/yy_ZZ
```

`X.po` here is the name of the translation file you created. Unlike the
translation file's name, localization team names **always include a language and
country code**; `yy` here is the _language code_, and `ZZ` is the _country
code_.

When adding a new entry, try to keep the list in **alphabetical order** if
possible.

## Style guide

These are general style guidelines for translations. Naturally, the specific
recommended standards differ based on the specific language/locale, but these
should serve as a baseline for the tone and voice of any translation.

- **Prefer an instructive, yet professional tone.**

  In languages that exhibit distinctions based on formality,
  prefer the formality that is expected of instructive material on the internet.
  The user should be considered an equal peer of the program and the translator,
  not an esteemed customer.

- **Use simple to understand language and avoid jargon.**

  Explain concepts that may be familiar in an English-speaking context,
  but are uncommon in your language.

- **Do not overly literally translate foreign concepts to your language.**

  Care should be taken so that your translations make sense to a reader without
  any background knowledge of the English source text. To _localize_ is to
  transfer a concept between languages, not to translate each word at face value.

- **Be consistent with stylistic and tonal choices.**

  Consult the translations made by previous translators, and try to emulate them.
  Do not overwrite someone else's hard work without substantial justification.

- **Make Ghostty fit in with surrounding applications.**

  Follow existing translations for terms and concepts if possible, even when
  they are suboptimal. Follow the writing styles prescribed by the human
  interface guidelines of each platform Ghostty is available for, including the
  [GNOME Human Interface Guidelines](https://developer.gnome.org/hig/guidelines/writing-style.html)
  on Linux, and [Apple's Human Interface Guidelines](https://developer.apple.com/design/human-interface-guidelines/writing)
  on macOS.

## Common issues

Some mistakes are frequently made during translation. The most common ones are
listed below.

### Unicode ellipses

English source strings use the ellipses character, `…`, instead of three full
stops, `...`. If your language uses ellipses, use the ellipses character instead
of three full stops in your translations. You can copy this character from the
English source string itself.

### Title case

Title case is a feature of English writing where most words start with a capital
letter: This Clause Is Written In Title Case. It is commonly found in titles,
hence its name; however, English is one of the only languages that uses title
case. If your language does not use title case, **do not use title case for the
sake of copying the English source**. Please use the casing conventions of your
language instead.

### `X-Generator` field

Many `.po` file editors add an `X-Generator` field to the metadata section.
These should be removed as other translators might overwrite them when using
a different editor, and some (such as Poedit) update the line when a different
_version_ is used—this adds unnecessary changes to the diff.

You can remove the `X-Generator` field by simply deleting that line from the
file with a plain text editor.

### Updating metadata (revision date)

It is very easy to overlook the `PO-Revision-Date` field in the metadata at the
top of the file. Please update this when you are done modifying the
translations!

Depending on who last translated the file, the `Last-Translator` field might
also need updating: make sure it has your name and email. Finally, if your name
and email are not present in the copyright comment at the top of the file,
consider adding it there.
