diff --git a/.gitignore b/.gitignore index 42f07ea..0eb1830 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ *.jl.cov *.jl.mem +docs/build/ diff --git a/README.md b/README.md index 9b4d44c..2fc862c 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,6 @@ Documentation: This package offers facilities for [internationalization and localization (i18n and l10n)](https://en.wikipedia.org/wiki/Internationalization_and_localization) of software in the Julia programming language, using the standard [`gettext`](https://en.wikipedia.org/wiki/Gettext) system. -Essentially, Gettext.jl allows the programmer to mark user-visible messages (strings) for translation, typically by simply replacing `"..."` strings with `_"..."`. Then, translators can localize a Julia program or package by providing a list of translations in the standard `.po` format (a human-readable/editable file, supported by many software tools). +Essentially, Gettext.jl allows the programmer to mark user-visible messages (strings) for translation, typically by simply replacing `"..."` strings with `_"..."`. Then, translators can localize a Julia program or package by providing a list of translations in the standard `.po` format (a human-readable/editable file, supported by many software tools). (This package calls GNU gettext's `libintl` library directly from Julia, via the `GettextRuntime_jll` package compiled for Julia by [Yggdrasil](https://github.com/JuliaPackaging/Yggdrasil); this is automatically installed for you by Julia's [package manager](https://github.com/JuliaLang/Pkg.jl). GNU gettext is free/open-source software licensed under the [GNU LGPL](https://www.gnu.org/software/gettext/manual/html_node/GNU-LGPL.html).) diff --git a/docs/make.jl b/docs/make.jl index 4758a5f..3b57c5a 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -9,6 +9,7 @@ makedocs( "Home" => "index.md", "Internationalization (i18n) API" => "i18n.md", "Localization (l10n) and PO files" => "l10n.md", + "Reference" => "reference.md", ], ) diff --git a/docs/src/i18n.md b/docs/src/i18n.md index 33d6346..8763ffb 100644 --- a/docs/src/i18n.md +++ b/docs/src/i18n.md @@ -2,19 +2,17 @@ ## Marking strings for translation -The most basic i18n task is to **mark every user-visible string** for possible translation. This is typically done with the macros describe in the following subsections. +The most basic i18n task is to **mark every user-visible string** for possible translation. This is typically done with the macros described in the following subsections. -(Note: we use macros, rather than functions, so that they can automatically -substitute the current [`__GETTEXT_DOMAIN__`](@ref module_gettext) when used in a module.) +(Note: we use macros, rather than functions, so that they can automatically substitute the current [`__GETTEXT_DOMAIN__`](@ref module_gettext) when used in a module.) See also the GNU gettext manual's tips on how to [prepare translatable strings](https://www.gnu.org/software/gettext/manual/html_node/Preparing-Strings.html) in your code. In short, they recommend **translating entire English sentences/paragraphs** (avoiding forming sentences by concatenation), splitting at paragraphs, with placeholders for interpolation/substitution (see below). ### Simple literal strings: `_"..."` -For most literal strings, you can simply replace `"..."` with [`_"..."`](@ref `@__str`), i.e. prepend an underscore. +For most literal strings, you can simply replace `"..."` with [`_"..."`](@ref @__str), i.e. prepend an underscore. -`_"..."` acts just like an ordinary Julia literal string, but internally it corresponds to a call to [`@gettext("...")`](@ref), returning a translated string if appropriate (assuming a translation exists for the current locale). The only other big difference from a typical Julia string is that [`$` interpolation](https://docs.julialang.org/en/v1/manual/strings/#string-interpolation) is **not** supported in `_"..."` (any `$` is treated literally). This is intentional: translation strings should not depend on runtime values, because a `.po` file contains only a finite number of translations, so runtime interpolation should be employed -judiciously as described below. +`_"..."` acts just like an ordinary Julia literal string, but internally it corresponds to a call to [`@gettext("...")`](@ref), returning a translated string if appropriate (assuming a translation exists for the current locale). The only other big difference from a typical Julia string is that [`$` interpolation](https://docs.julialang.org/en/v1/manual/strings/#string-interpolation) is **not** supported in `_"..."` (any `$` is treated literally). This is intentional: translation strings should not depend on runtime values, because a `.po` file contains only a finite number of translations, so runtime interpolation should be employed judiciously as described below. ### Interpolating into translated strings @@ -40,14 +38,13 @@ In this case, a simple placeholder for `n` is not enough. Instead, you can use ```jl @ngettext("Your birthday is in %d day.", "Your birthday is in %d days.", "%d"=>n) ``` -Here, we provide both singular and plural forms of the string to be translated, and -`@ngettext` will choose one based on the runtime value of `n`. (In fact, for some languages, gettext may choose among [multiple plural forms](https://www.gnu.org/software/gettext/manual/html_node/Plural-forms.html).) The translation strings should also have a `%d` placeholder, and the `"%d"=>n` argument tells `@ngettext` to substitute `string(n)` for `%d` in the final result (using `replace`). +Here, we provide both singular and plural forms of the string to be translated, and `@ngettext` will choose one based on the runtime value of `n`. (In fact, for some languages, gettext may choose among [multiple plural forms](https://www.gnu.org/software/gettext/manual/html_node/Plural-forms.html).) The translation strings should also have a `%d` placeholder, and the `"%d"=>n` argument tells `@ngettext` to substitute `string(n)` for `%d` in the final result (using `replace`). If you want to perform more complicated numeric formatting on your own, e.g. with `Printf`, you can pass `n` instead of `"%d"=>n` and no substitution will be performed on the result. ### Providing additional translation context: `@pgettext` -Sometimes, the *same string* might be used in different contexts in a program that require *different translations*. This is especially common for very short strings (e.g. single words). For example, the string `"Open"` in a File menu might be translated into Spanish as a verb `"Abrir"` (*to open* a file), but the same string might be translated as an adjective `"Abierto"` to indicate that a door is *open* in a game. +Sometimes, the *same string* might be used in different contexts in a program that require *different translations*. This is especially common for very short strings (e.g. single words). For example, the string `"Open"` in a File menu might be translated into Spanish as a verb `"Abrir"` (*to open* a file), but the same string might be translated as an adjective `"Abierto"` to indicate that a door is *open* in a game. To support this case, Gettext allows you to pass an additional *context* string for a translation, using the macro [`@pgettext`](@ref). For example: @@ -56,8 +53,7 @@ To support this case, Gettext allows you to pass an additional *context* string @pgettext("Door", "Open") # translate an "Open" sign attached to a door ``` -Similarly, there is a macro [`@npgettext`](@ref) that is like `@ngettext` but -has an additional context string as the first argument. +Similarly, there is a macro [`@npgettext`](@ref) that is like `@ngettext` but has an additional context string as the first argument. ### Macro reference The following are the string-i18n macros: @@ -73,7 +69,7 @@ Gettext.@N__str ## [Domains](@id domains) -Every translation in Gettext is relative to a "domain", which usually corresponds to a single program or package. Each domain has a list of strings to be translated, and can have `domain.po` files that give translations for particular locales (see [Localization (l10n) and PO files](@ref)). To control the domain being used, you need to do two things: +Every translation in Gettext is relative to a "domain", which usually corresponds to a single program or package. Each domain has a list of strings to be translated, and can have `domain.po` files that give translations for particular locales (see [Localization (l10n) and PO files](@ref)). To control the domain being used, you need to do two things: 1. Call [`bindtextdomain`](@ref) to specify the path of the `po` directory containing translations for that domain. This is typically done in a module's `__init__` function (see below). 2. Specify the domain you are using: this is done via the [`__GETTEXT_DOMAIN__`](@ref module_gettext) constant in modules/packages (below), or is done by setting a global domain with [`textdomain`](@ref) for code running in Julia's [`Main`](https://docs.julialang.org/en/v1/base/base/#Main) module (scripts and interactive work). @@ -106,18 +102,11 @@ end end ``` -In `"MyPackage-"`, the `` denotes the unique [UUID -identifier of your package](https://pkgdocs.julialang.org/v1/toml-files/#The-uuid-field) — this ensures that two packages will not have the same gettext domain, even if they happen to have the same name. +In `"MyPackage-"`, the `` denotes the unique [UUID identifier of your package](https://pkgdocs.julialang.org/v1/toml-files/#The-uuid-field) — this ensures that two packages will not have the same gettext domain, even if they happen to have the same name. When they are used in *any* module (other than Julia's implicit [`Main`](https://docs.julialang.org/en/v1/base/base/#Main) module for scripts and interactive work), the macros, `_"..."`, `@gettext`, and so on (see above) pass this global variable `__GETTEXT_DOMAIN__` to the corresponding low-level functions. You will get an [`UndefVarError`](https://docs.julialang.org/en/v1/base/base/#Core.UndefVarError) if you use those macros in a module that does not define `__GETTEXT_DOMAIN__`. (In the `Main` module, the same macros instead use the global [`textdomain`](@ref).) -The `bindtextdomain` call in the example above assumes that you -have a top-level directory `po` in your package, which is a good -default location. This directory is used to store translation -(`.po`) files `po//LC_MESSAGES/MyModule-.po`, where -`` is the standard locale identifier, e.g. `en` (English) or -`en_GB` (English, Great Britain), and `MyModule-` is your -domain name from above. +The `bindtextdomain` call in the example above assumes that you have a top-level directory `po` in your package, which is a good default location. This directory is used to store translation (`.po`) files `po//LC_MESSAGES/MyModule-.po`, where `` is the standard locale identifier, e.g. `en` (English) or `en_GB` (English, Great Britain), and `MyModule-` is your domain name from above. If your package has submodules, in most cases they can simply employ the same domain as your top-level module `MyModule`, via: diff --git a/docs/src/index.md b/docs/src/index.md index 9c4aa9f..1bac8f9 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -10,9 +10,9 @@ This package offers facilities for [internationalization and localization (i18n `gettext` is a popular system, dating back to 1990, for i18n and l10n of **messages** (strings) exposed to users in a program's interface: prompts, menu items, error messages, and so on. This consists of two parts: -* **i18n**: in your program, *any string that might need translation* should be wrapped in a call to a `gettext` function. In Gettext.jl, this is usually accomplished by macros: For a typical string `"..."`, you simply replace it with [`_"..."`](@ref `@__str`) to make it translatable. There are also more specialized macros, such as [`@ngettext`](@ref) for strings with runtime-dependent singular and plural forms. See the [Internationalization (i18n) API](@ref) chapter. +* **i18n**: in your program, *any string that might need translation* should be wrapped in a call to a `gettext` function. In Gettext.jl, this is usually accomplished by macros: For a typical string `"..."`, you simply replace it with [`_"..."`](@ref @__str) to make it translatable. There are also more specialized macros, such as [`@ngettext`](@ref) for strings with runtime-dependent singular and plural forms. See the [Internationalization (i18n) API](@ref) chapter. -* **l10n**: for any locale, one can create a `.po` file that lists the translations of strings in a human-readable text format — this format is designed so that non-programmers can easily contribute translations, and there are many software tools to help create `.po` files (either manually or via automated translation). These `.po` files are then placed in a standardized directory for your package, and are converted to a binary `.mo` format with the [GNU `msgfmt` program](https://www.gnu.org/software/gettext/manual/html_node/Binaries.html). At runtime, Gettext.jl then automatically looks up translations (if any) from the current locale (as indicated by the operating system) and substitutes them for strings like `_"..."` in your program. See the [Localization (l10n) and PO files](@ref) chapter. +* **l10n**: for any locale, one can create a `.po` file that lists the translations of strings in a human-readable text format — this format is designed so that non-programmers can easily contribute translations, and there are many software tools to help create `.po` files (either manually or via automated translation). These `.po` files are then placed in a standardized directory for your package, and are converted to a binary `.mo` format with the [GNU `msgfmt` program](https://www.gnu.org/software/gettext/manual/html_node/Binaries.html). At runtime, Gettext.jl then automatically looks up translations (if any) from the current locale (as indicated by the operating system) and substitutes them for strings like `_"..."` in your program. See the [Localization (l10n) and PO files](@ref) chapter. (Other forms of i18n and l10n, such as locale-specific formatting of numbers and dates, are outside the scope of `gettext`, but are provided by other libraries such as `libc`.) @@ -29,14 +29,14 @@ To i18n it, the first step is simply to change the code to: using Gettext println(_"Hello, world!") ``` -which tells Gettext.jl to translate the string `"Hello, world!"` for the current locale, if possible. By default, if no translation is found, [`_"..."`](@ref `@__str`) will simply return the original untranslated string, and the program will have the same output as before. +which tells Gettext.jl to translate the string `"Hello, world!"` for the current locale, if possible. By default, if no translation is found, [`_"..."`](@ref @__str) will simply return the original untranslated string, and the program will have the same output as before. -The Gettext.jl package comes with a sample `.po` translation file that includes a translation of `"Hello, world!"` into French. In particular, the Gettext.jl package has a text file `po/fr/LC_MESSAGES/sample.po` (along with its binary-format equivalent `po/fr/LC_MESSAGES/sample.mo`) that includes the translation: +The Gettext.jl package comes with a sample `.po` translation file that includes a translation of `"Hello, world!"` into French. In particular, the Gettext.jl package has a text file `po/fr/LC_MESSAGES/sample.po` (along with its binary-format equivalent `po/fr/LC_MESSAGES/sample.mo`) that includes the translation: ``` msgid "Hello, world!" msgstr "Bonjour le monde !" ``` -Here, in the `sample.po` file, the `msgid` is the original string and `msgstr` is the translation. The `po` directory (typically at the top level of the package) is where a package's translations are placed, and `po/fr/LC_MESSAGES` contains translations for French-language (`fr`) locales in the default "category" `LC_MESSAGES`. Inside this directory, `sample.po` contains the translations for the "domain" we called `"sample"` — there will typically be one such domain per independent package/component of a program (see [Gettext for modules and packages](@ref module_gettext)). We need to tell Gettext.jl where to find the translations we are using, which we could do here via: +Here, in the `sample.po` file, the `msgid` is the original string and `msgstr` is the translation. The `po` directory (typically at the top level of the package) is where a package's translations are placed, and `po/fr/LC_MESSAGES` contains translations for French-language (`fr`) locales in the default "category" `LC_MESSAGES`. Inside this directory, `sample.po` contains the translations for the "domain" we called `"sample"` — there will typically be one such domain per independent package/component of a program (see [Gettext for modules and packages](@ref module_gettext)). We need to tell Gettext.jl where to find the translations we are using, which we could do here via: ```jl using Gettext bindtextdomain("sample", joinpath(dirname(pathof(Gettext)), "..", "po")) @@ -44,17 +44,9 @@ textdomain("sample") # set domain for the global Main module only println(_"Hello, world!") ``` -Here, [`bindtextdomain`](@ref) specifies the path of the `po` directory for -a given domain. For scripts (or interactive sessions) running in Julia's -[`Main`](https://docs.julialang.org/en/v1/base/base/#Main) module, you then call -[`textdomain`](@ref) to set the global domain. Inside packages and -other modules, you instead define a [`__GETTEXT_DOMAIN__`](@ref module_gettext) global to set a package-specific domain, so that each package can have independent -translations. - -Now, when you run the code, you will *still* see `"Hello, world!"` if you are in any -non-French locale, but *French* locales will instead print `"Bonjour le monde !"`. -On Unix-like systems, you can set the locale simply via the [`LANGUAGE` environment -variable](https://www.gnu.org/software/gettext/manual/html_node/Locale-Environment-Variables.htmls). This can even be changed at runtime, so +Here, [`bindtextdomain`](@ref) specifies the path of the `po` directory for a given domain. For scripts (or interactive sessions) running in Julia's [`Main`](https://docs.julialang.org/en/v1/base/base/#Main) module, you then call [`textdomain`](@ref) to set the global domain. Inside packages and other modules, you instead define a [`__GETTEXT_DOMAIN__`](@ref module_gettext) global to set a package-specific domain, so that each package can have independent translations. + +Now, when you run the code, you will *still* see `"Hello, world!"` if you are in any non-French locale, but *French* locales will instead print `"Bonjour le monde !"`. On Unix-like systems, you can set the locale simply via the [`LANGUAGE` environment variable](https://www.gnu.org/software/gettext/manual/html_node/Locale-Environment-Variables.htmls). This can even be changed at runtime, so ```jl using Gettext bindtextdomain("sample", joinpath(dirname(pathof(Gettext)), "..", "po")) diff --git a/docs/src/l10n.md b/docs/src/l10n.md index fa2809f..62c19c6 100644 --- a/docs/src/l10n.md +++ b/docs/src/l10n.md @@ -2,9 +2,9 @@ Once you have internationalized your code by marking translatable strings (see [Internationalization (i18n) API](@ref)), you are ready to start creating translations: this is **localization** (**l10n**) of your program, which is achieved by authoring a `.po` file with a list of translated strings. -In fact, the `.po` files need not be created by the programmer — they can instead be contributed by users, which allows native speakers of other languages to help you out. There are numerous software tools to help people create and edit `.po` files, some of which we mention below. +In fact, the `.po` files need not be created by the programmer — they can instead be contributed by users, which allows native speakers of other languages to help you out. There are numerous software tools to help people create and edit `.po` files, some of which we mention below. -Localization involves three components: setting up the `po` directory to hold translations, extracting the strings to be translated, and creating/editing `.po` files for various locales. We summarize each of these components below. +Localization involves three components: setting up the `po` directory to hold translations, extracting the strings to be translated, and creating/editing `.po` files for various locales. We summarize each of these components below. ## The `po` directory @@ -21,12 +21,11 @@ po//LC_MESSAGES/.mo * `` is the name of the Gettext domain used by the program or package (see [Domains](@ref domains)), typically the name of the program or package followed by a unique identifier like a UUID; for a package/module, this is the value of [`__GETTEXT_DOMAIN__`](@ref module_gettext). -* The `.po` file is a human-readable/editable text file containing the translated messages. The `.mo` file is a condensed binary representation of the `.po` data, which can be generated from `.po` by the [GNU `msgfmt` program](https://www.gnu.org/software/gettext/manual/html_node/Binaries.html). +* The `.po` file is a human-readable/editable text file containing the translated messages. The `.mo` file is a condensed binary representation of the `.po` data, which can be generated from `.po` by the [GNU `msgfmt` program](https://www.gnu.org/software/gettext/manual/html_node/Binaries.html). ## Extracting the strings to be translated -The strings to be translated consist of every call to the localization macros `_"..."`, -`@ngettext`, and so on in the program or package (see [Internationalization (i18n) API](@ref)). +The strings to be translated consist of every call to the localization macros `_"..."`, `@ngettext`, and so on in the program or package (see [Internationalization (i18n) API](@ref)). Currently, this list of strings must be extracted manually, but in the near future we hope to automate this process. See: [Gettext.jl#22](https://github.com/Julia-i18n/Gettext.jl/issues/22). diff --git a/docs/src/reference.md b/docs/src/reference.md new file mode 100644 index 0000000..47a9407 --- /dev/null +++ b/docs/src/reference.md @@ -0,0 +1,5 @@ +# Reference + +```@autodocs +Modules = [Gettext] +``` diff --git a/src/Gettext.jl b/src/Gettext.jl index 6b2db3a..f58a009 100644 --- a/src/Gettext.jl +++ b/src/Gettext.jl @@ -5,10 +5,10 @@ This module offers facilities for internationalization and localization (i18n an of software in the Julia programming language, using the standard `gettext` system. Essentially, `Gettext` allows the programmer to mark user-visible messages (strings) for translation, -typically by simply replacing `"..."` strings with [`_"..."`](@ref `@__str`). +typically by simply replacing `"..."` strings with [`_"..."`](@ref @__str). -Then, translators can localize a Julia program or package by providing a list of translations in the -standard `.po` format (a human-readable/editable file, supported by many software tools). +Then, translators can localize a Julia program or package by providing a list of translations +in the standard `.po` format (a human-readable/editable file, supported by many software tools). """ module Gettext @@ -25,12 +25,11 @@ end """ textdomain([domain::AbstractString]) -Set the global Gettext domain to `domain` (if supplied), returning the current -global domain. +Set the global Gettext domain to `domain` (if supplied), returning the current global domain. This domain is used for calls to low-level functions like [`gettext`](@ref) -when no domain argument is passed, and also for macros like [`_"..."`](@ref `@__str`) -and [`@getext`](@ref) when used from the `Main` module. +when no domain argument is passed, and also for macros like [`_"..."`](@ref @__str) +and [`@gettext`](@ref) when used from the `Main` module. """ textdomain @@ -61,17 +60,17 @@ end Specify that the `po` directory for `domain` is at `path` (if supplied), returning the current (absolute) `path` for `domain`. -(If this function is not called, then `gettext` will look in a system-specific -directory like `/usr/local/share/locale` for translation catalogs.) +(If this function is not called, then `gettext` will look in a system-specific directory +like `/usr/local/share/locale` for translation catalogs.) """ bindtextdomain """ gettext([domain::AbstractString], msgid::AbstractString) -Look up the translation (if any) of `msgid` in `domain` (if supplied, or -in the global [`textdomain`](@ref) otherwise), returning the translated -string, or returning `msgid` if no translation was found. +Look up the translation (if any) of `msgid` in `domain` +(if supplied, or in the global [`textdomain`](@ref) otherwise), +returning the translated string, or returning `msgid` if no translation was found. See also [`@gettext`](@ref) to use the domain of the current module. """ @@ -82,17 +81,18 @@ gettext(domain::AbstractString, msgid::AbstractString) = unsafe_string(ccall((:l ngettext([domain::AbstractString], msgid::AbstractString, msgid_plural::AbstractString, n::Integer) ngettext([domain::AbstractString], msgid::AbstractString, msgid_plural::AbstractString, nsub::Pair{<:AbstractString, <:Integer}) -Look up the translation (if any) of `msgid` in `domain` (if supplied, or -in the global [`textdomain`](@ref) otherwise), with the plural form -given by `msgid_plural`, returning the singular form if `n == 1` and -a plural form if `n != 1` (`n` must be nonnegative), giving a translated -string if available. +Look up the translation (if any) of `msgid` in `domain` +(if supplied, or in the global [`textdomain`](@ref) otherwise), +with the plural form given by `msgid_plural`, returning the singular form if `n == 1` +and a plural form if `n != 1` (`n` must be nonnegative), +giving a translated string if available. Instead of passing an integer `n`, you can pass a `Pair` `placeholder=>n`, -in which case case the string `placeholder` is replaced by `n` in the returned -string; most commonly, `placeholder == "%d"` (in `printf` style). (Note that this -is a simple string replacement; if you want more complicated `printf`-style formating -like `"%05d"` then you will need to call a library like `Printf` yourself.) +in which case case the string `placeholder` is replaced by `n` in the returned string; +most commonly, `placeholder == "%d"` (in `printf` style). +(Note that this is a simple string replacement; +if you want more complicated `printf`-style formating like `"%05d"` +then you will need to call a library like `Printf` yourself.) See also [`@ngettext`](@ref) to use the domain of the current module. """ @@ -128,8 +128,8 @@ end npgettext([domain::AbstractString], context::AbstractString, msgid::AbstractString, msgid_plural::AbstractString, nsub::Pair{<:AbstractString, <:Integer}) Like [`ngettext`](@ref), but also supplies a `context` string for looking up `msgid` -or its plural form `msgid_plural` (depending on `n`), optionally performing a -text substitution if a `Pair` is passed for the final argument. +or its plural form `msgid_plural` (depending on `n`), +optionally performing a text substitution if a `Pair` is passed for the final argument. See also [`@npgettext`](@ref) to use the domain of the current module. """ @@ -145,8 +145,8 @@ function npgettext(domain::AbstractString, context::AbstractString, msgid::Abstr end ################################################################################################ -# simplify the common replace(ngettext(...), "%d"=>n) idiom by instead -# allowing ngettext(singular, plural, "%d"=>n): +# simplify the common replace(ngettext(...), "%d"=>n) idiom +# by instead allowing ngettext(singular, plural, "%d"=>n): ngettext(msgid::AbstractString, msgid_plural::AbstractString, nsub::Pair{<:AbstractString,<:Integer}) = replace(ngettext(msgid, msgid_plural, nsub.second), nsub) @@ -159,8 +159,8 @@ npgettext(domain::AbstractString, context::AbstractString, msgid::AbstractString ################################################################################################ # macro versions … not only are these shorter, but they also implicitly use the current module's -# @__MODULE__().__GETTEXT_DOMAIN__ instead of the global domain (unless @__MODULE__() == Main). This -# is important to ensure that translations from different packages do not conflict. +# @__MODULE__().__GETTEXT_DOMAIN__ instead of the global domain (unless @__MODULE__() == Main). +# This is important to ensure that translations from different packages do not conflict. function _gettext_macro(gettext_func, gettext_args...) args = esc.(gettext_args) @@ -178,9 +178,9 @@ end Returns the translation (if any) for the given literal string `"..."` via [`@gettext`](@ref). -This string can contain backslash escapes like ordinary Julia literal strings, but `\$` is -treated literally (*not* used for interpolations): translation strings should not generally -contain runtime values. +This string can contain backslash escapes like ordinary Julia literal strings, +but `\$` is treated literally (*not* used for interpolations): +translation strings should not generally contain runtime values. """ macro __str(s) _gettext_macro(gettext, unescape_string(s)) @@ -189,11 +189,11 @@ end """ @gettext(msgid::AbstractString) -Look up the translation (if any) of `msgid`, returning the translated -string, or returning `msgid` if no translation was found. +Look up the translation (if any) of `msgid`, returning the translated string, +or returning `msgid` if no translation was found. -In a module `!= Main`, this passes the module's `__GETTEXT_DOMAIN__` as the domain argument -to [`gettext`](@ref), whereas the global [`textdomain`](@ref) is used in the `Main` module. +In a module `!= Main`, this passes the module's `__GETTEXT_DOMAIN__` as the domain argument to [`gettext`](@ref), +whereas the global [`textdomain`](@ref) is used in the `Main` module. """ macro gettext(msgid) _gettext_macro(gettext, msgid) @@ -203,19 +203,19 @@ end @ngettext(msgid::AbstractString, msgid_plural::AbstractString, n::Integer) @ngettext(msgid::AbstractString, msgid_plural::AbstractString, nsub::Pair{<:AbstractString, <:Integer}) -Look up the translation (if any) of `msgid`, with the plural form -given by `msgid_plural`, returning the singular form if `n == 1` and -a plural form if `n != 1` (`n` must be nonnegative), giving a translated -string if available. +Look up the translation (if any) of `msgid`, with the plural form given by `msgid_plural`, +returning the singular form if `n == 1` and a plural form if `n != 1` (`n` must be nonnegative), +giving a translated string if available. Instead of passing an integer `n`, you can pass a `Pair` `placeholder=>n`, -in which case case the string `placeholder` is replaced by `n` in the returned -string; most commonly, `placeholder == "%d"` (in `printf` style). (Note that this -is a simple string replacement; if you want more complicated `printf`-style formating -like `"%05d"` then you will need to call a library like `Printf` yourself.) - -In a module `!= Main`, this passes the module's `__GETTEXT_DOMAIN__` as the domain argument -to [`ngettext`](@ref), whereas the global [`textdomain`](@ref) is used in the `Main` module. +in which case case the string `placeholder` is replaced by `n` in the returned string; +most commonly, `placeholder == "%d"` (in `printf` style). +(Note that this is a simple string replacement; +if you want more complicated `printf`-style formating like `"%05d"` +then you will need to call a library like `Printf` yourself.) + +In a module `!= Main`, this passes the module's `__GETTEXT_DOMAIN__` as the domain argument to [`ngettext`](@ref), +whereas the global [`textdomain`](@ref) is used in the `Main` module. """ macro ngettext(msgid, msgid_plural, n) _gettext_macro(ngettext, msgid, msgid_plural, n) @@ -227,8 +227,8 @@ end Like [`@gettext`](@ref), but also supplies a `context` string for looking up `msgid`, returning the translation (if any) or `msgid` (if no translation was found). -In a module `!= Main`, this passes the module's `__GETTEXT_DOMAIN__` as the domain argument -to [`pgettext`](@ref), whereas the global [`textdomain`](@ref) is used in the `Main` module. +In a module `!= Main`, this passes the module's `__GETTEXT_DOMAIN__` as the domain argument to [`pgettext`](@ref), +whereas the global [`textdomain`](@ref) is used in the `Main` module. """ macro pgettext(context, msgid) _gettext_macro(pgettext, context, msgid) @@ -239,11 +239,11 @@ end @npgettext(context::AbstractString, msgid::AbstractString, msgid_plural::AbstractString, nsub::Pair{<:AbstractString, <:Integer}) Like [`@ngettext`](@ref), but also supplies a `context` string for looking up `msgid` -or its plural form `msgid_plural` (depending on `n`), optionally performing a -text substitution if a `Pair` is passed for the final argument. +or its plural form `msgid_plural` (depending on `n`), +optionally performing a text substitution if a `Pair` is passed for the final argument. -In a module `!= Main`, this passes the module's `__GETTEXT_DOMAIN__` as the domain argument -to [`npgettext`](@ref), whereas the global [`textdomain`](@ref) is used in the `Main` module. +In a module `!= Main`, this passes the module's `__GETTEXT_DOMAIN__` as the domain argument to [`npgettext`](@ref), +whereas the global [`textdomain`](@ref) is used in the `Main` module. """ macro npgettext(context, msgid, msgid_plural, n) _gettext_macro(npgettext, context, msgid, msgid_plural, n) @@ -254,11 +254,11 @@ end "No-op" translation, equivalent to `"..."`, for strings that do *not* require translation. -This string can contain backslash escapes like ordinary Julia literal strings, but `\$` is -treated literally (*not* used for interpolations). +This string can contain backslash escapes like ordinary Julia literal strings, +but `\$` is treated literally (*not* used for interpolations). -(The main use of this macro is to explicitly mark strings to ensure that they are excluded -from automated translation tools.) +(The main use of this macro is to explicitly mark strings +to ensure that they are excluded from automated translation tools.) """ macro N__str(s) :($(esc(unescape_string(s))))