@esgettext/runtime 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +19 -0
- package/README.md +411 -0
- package/_bundles/runtime.js +1356 -0
- package/_bundles/runtime.js.map +1 -0
- package/_bundles/runtime.min.js +2 -0
- package/_bundles/runtime.min.js.map +1 -0
- package/api-docs/assets/highlight.css +127 -0
- package/api-docs/assets/main.js +59 -0
- package/api-docs/assets/navigation.js +1 -0
- package/api-docs/assets/search.js +1 -0
- package/api-docs/assets/style.css +1414 -0
- package/api-docs/classes/Textdomain.html +364 -0
- package/api-docs/index.html +222 -0
- package/api-docs/interfaces/Catalog.html +20 -0
- package/api-docs/interfaces/CatalogEntries.html +11 -0
- package/api-docs/interfaces/LocaleContainer.html +19 -0
- package/api-docs/interfaces/Placeholders.html +9 -0
- package/api-docs/modules.html +6 -0
- package/lib/core/browser-environment.d.ts +1 -0
- package/lib/core/browser-environment.js +12 -0
- package/lib/core/browser-environment.js.map +1 -0
- package/lib/core/catalog-cache.d.ts +10 -0
- package/lib/core/catalog-cache.js +39 -0
- package/lib/core/catalog-cache.js.map +1 -0
- package/lib/core/catalog-cache.spec.d.ts +1 -0
- package/lib/core/catalog-cache.spec.js +24 -0
- package/lib/core/catalog-cache.spec.js.map +1 -0
- package/lib/core/catalog-format.spec.d.ts +1 -0
- package/lib/core/catalog-format.spec.js +35 -0
- package/lib/core/catalog-format.spec.js.map +1 -0
- package/lib/core/catalog.d.ts +9 -0
- package/lib/core/catalog.js +3 -0
- package/lib/core/catalog.js.map +1 -0
- package/lib/core/data-viewlet.d.ts +11 -0
- package/lib/core/data-viewlet.js +57 -0
- package/lib/core/data-viewlet.js.map +1 -0
- package/lib/core/data-viewlet.spec.d.ts +1 -0
- package/lib/core/data-viewlet.spec.js +62 -0
- package/lib/core/data-viewlet.spec.js.map +1 -0
- package/lib/core/explode-locale.d.ts +3 -0
- package/lib/core/explode-locale.js +37 -0
- package/lib/core/explode-locale.js.map +1 -0
- package/lib/core/explode-locale.spec.d.ts +1 -0
- package/lib/core/explode-locale.spec.js +41 -0
- package/lib/core/explode-locale.spec.js.map +1 -0
- package/lib/core/germanic-plural.d.ts +1 -0
- package/lib/core/germanic-plural.js +8 -0
- package/lib/core/germanic-plural.js.map +1 -0
- package/lib/core/gettext-impl.d.ts +10 -0
- package/lib/core/gettext-impl.js +38 -0
- package/lib/core/gettext-impl.js.map +1 -0
- package/lib/core/gettext.spec.d.ts +1 -0
- package/lib/core/gettext.spec.js +391 -0
- package/lib/core/gettext.spec.js.map +1 -0
- package/lib/core/index.d.ts +4 -0
- package/lib/core/index.js +21 -0
- package/lib/core/index.js.map +1 -0
- package/lib/core/locale-container.d.ts +8 -0
- package/lib/core/locale-container.js +3 -0
- package/lib/core/locale-container.js.map +1 -0
- package/lib/core/path-separator.d.ts +1 -0
- package/lib/core/path-separator.js +12 -0
- package/lib/core/path-separator.js.map +1 -0
- package/lib/core/resolve-impl.d.ts +3 -0
- package/lib/core/resolve-impl.js +253 -0
- package/lib/core/resolve-impl.js.map +1 -0
- package/lib/core/resolve.spec.d.ts +1 -0
- package/lib/core/resolve.spec.js +345 -0
- package/lib/core/resolve.spec.js.map +1 -0
- package/lib/core/select-locale.d.ts +1 -0
- package/lib/core/select-locale.js +43 -0
- package/lib/core/select-locale.js.map +1 -0
- package/lib/core/select-locale.spec.d.ts +1 -0
- package/lib/core/select-locale.spec.js +27 -0
- package/lib/core/select-locale.spec.js.map +1 -0
- package/lib/core/set-locale-browser.spec.d.ts +1 -0
- package/lib/core/set-locale-browser.spec.js +17 -0
- package/lib/core/set-locale-browser.spec.js.map +1 -0
- package/lib/core/set-locale-node.spec.d.ts +1 -0
- package/lib/core/set-locale-node.spec.js +26 -0
- package/lib/core/set-locale-node.spec.js.map +1 -0
- package/lib/core/split-locale.d.ts +7 -0
- package/lib/core/split-locale.js +39 -0
- package/lib/core/split-locale.js.map +1 -0
- package/lib/core/split-locale.spec.d.ts +1 -0
- package/lib/core/split-locale.spec.js +59 -0
- package/lib/core/split-locale.spec.js.map +1 -0
- package/lib/core/textdomain.d.ts +55 -0
- package/lib/core/textdomain.js +277 -0
- package/lib/core/textdomain.js.map +1 -0
- package/lib/core/textdomain.spec.d.ts +1 -0
- package/lib/core/textdomain.spec.js +33 -0
- package/lib/core/textdomain.spec.js.map +1 -0
- package/lib/core/user-locales.d.ts +1 -0
- package/lib/core/user-locales.js +12 -0
- package/lib/core/user-locales.js.map +1 -0
- package/lib/index-browser.d.ts +2 -0
- package/lib/index-browser.js +44 -0
- package/lib/index-browser.js.map +1 -0
- package/lib/index.d.ts +2 -0
- package/lib/index.js +37 -0
- package/lib/index.js.map +1 -0
- package/lib/parser/index.d.ts +2 -0
- package/lib/parser/index.js +19 -0
- package/lib/parser/index.js.map +1 -0
- package/lib/parser/parse-json-catalog.d.ts +3 -0
- package/lib/parser/parse-json-catalog.js +37 -0
- package/lib/parser/parse-json-catalog.js.map +1 -0
- package/lib/parser/parse-json-catalog.spec.d.ts +1 -0
- package/lib/parser/parse-json-catalog.spec.js +41 -0
- package/lib/parser/parse-json-catalog.spec.js.map +1 -0
- package/lib/parser/parse-mo-catalog.d.ts +2 -0
- package/lib/parser/parse-mo-catalog.js +86 -0
- package/lib/parser/parse-mo-catalog.js.map +1 -0
- package/lib/parser/parse-mo-catalog.spec.d.ts +1 -0
- package/lib/parser/parse-mo-catalog.spec.js +115 -0
- package/lib/parser/parse-mo-catalog.spec.js.map +1 -0
- package/lib/transport/fs.d.ts +4 -0
- package/lib/transport/fs.js +18 -0
- package/lib/transport/fs.js.map +1 -0
- package/lib/transport/http.d.ts +4 -0
- package/lib/transport/http.js +27 -0
- package/lib/transport/http.js.map +1 -0
- package/lib/transport/http.spec.d.ts +1 -0
- package/lib/transport/http.spec.js +119 -0
- package/lib/transport/http.spec.js.map +1 -0
- package/lib/transport/index.d.ts +3 -0
- package/lib/transport/index.js +20 -0
- package/lib/transport/index.js.map +1 -0
- package/lib/transport/transport.interface.d.ts +3 -0
- package/lib/transport/transport.interface.js +3 -0
- package/lib/transport/transport.interface.js.map +1 -0
- package/lib-esm/core/browser-environment.d.ts +1 -0
- package/lib-esm/core/browser-environment.js +8 -0
- package/lib-esm/core/browser-environment.js.map +1 -0
- package/lib-esm/core/catalog-cache.d.ts +10 -0
- package/lib-esm/core/catalog-cache.js +36 -0
- package/lib-esm/core/catalog-cache.js.map +1 -0
- package/lib-esm/core/catalog-cache.spec.d.ts +1 -0
- package/lib-esm/core/catalog-cache.spec.js +22 -0
- package/lib-esm/core/catalog-cache.spec.js.map +1 -0
- package/lib-esm/core/catalog-format.spec.d.ts +1 -0
- package/lib-esm/core/catalog-format.spec.js +33 -0
- package/lib-esm/core/catalog-format.spec.js.map +1 -0
- package/lib-esm/core/catalog.d.ts +9 -0
- package/lib-esm/core/catalog.js +2 -0
- package/lib-esm/core/catalog.js.map +1 -0
- package/lib-esm/core/data-viewlet.d.ts +11 -0
- package/lib-esm/core/data-viewlet.js +54 -0
- package/lib-esm/core/data-viewlet.js.map +1 -0
- package/lib-esm/core/data-viewlet.spec.d.ts +1 -0
- package/lib-esm/core/data-viewlet.spec.js +60 -0
- package/lib-esm/core/data-viewlet.spec.js.map +1 -0
- package/lib-esm/core/explode-locale.d.ts +3 -0
- package/lib-esm/core/explode-locale.js +33 -0
- package/lib-esm/core/explode-locale.js.map +1 -0
- package/lib-esm/core/explode-locale.spec.d.ts +1 -0
- package/lib-esm/core/explode-locale.spec.js +39 -0
- package/lib-esm/core/explode-locale.spec.js.map +1 -0
- package/lib-esm/core/germanic-plural.d.ts +1 -0
- package/lib-esm/core/germanic-plural.js +4 -0
- package/lib-esm/core/germanic-plural.js.map +1 -0
- package/lib-esm/core/gettext-impl.d.ts +10 -0
- package/lib-esm/core/gettext-impl.js +34 -0
- package/lib-esm/core/gettext-impl.js.map +1 -0
- package/lib-esm/core/gettext.spec.d.ts +1 -0
- package/lib-esm/core/gettext.spec.js +389 -0
- package/lib-esm/core/gettext.spec.js.map +1 -0
- package/lib-esm/core/index.d.ts +4 -0
- package/lib-esm/core/index.js +5 -0
- package/lib-esm/core/index.js.map +1 -0
- package/lib-esm/core/locale-container.d.ts +8 -0
- package/lib-esm/core/locale-container.js +2 -0
- package/lib-esm/core/locale-container.js.map +1 -0
- package/lib-esm/core/path-separator.d.ts +1 -0
- package/lib-esm/core/path-separator.js +8 -0
- package/lib-esm/core/path-separator.js.map +1 -0
- package/lib-esm/core/resolve-impl.d.ts +3 -0
- package/lib-esm/core/resolve-impl.js +249 -0
- package/lib-esm/core/resolve-impl.js.map +1 -0
- package/lib-esm/core/resolve.spec.d.ts +1 -0
- package/lib-esm/core/resolve.spec.js +340 -0
- package/lib-esm/core/resolve.spec.js.map +1 -0
- package/lib-esm/core/select-locale.d.ts +1 -0
- package/lib-esm/core/select-locale.js +39 -0
- package/lib-esm/core/select-locale.js.map +1 -0
- package/lib-esm/core/select-locale.spec.d.ts +1 -0
- package/lib-esm/core/select-locale.spec.js +25 -0
- package/lib-esm/core/select-locale.spec.js.map +1 -0
- package/lib-esm/core/set-locale-browser.spec.d.ts +1 -0
- package/lib-esm/core/set-locale-browser.spec.js +15 -0
- package/lib-esm/core/set-locale-browser.spec.js.map +1 -0
- package/lib-esm/core/set-locale-node.spec.d.ts +1 -0
- package/lib-esm/core/set-locale-node.spec.js +24 -0
- package/lib-esm/core/set-locale-node.spec.js.map +1 -0
- package/lib-esm/core/split-locale.d.ts +7 -0
- package/lib-esm/core/split-locale.js +35 -0
- package/lib-esm/core/split-locale.js.map +1 -0
- package/lib-esm/core/split-locale.spec.d.ts +1 -0
- package/lib-esm/core/split-locale.spec.js +57 -0
- package/lib-esm/core/split-locale.spec.js.map +1 -0
- package/lib-esm/core/textdomain.d.ts +55 -0
- package/lib-esm/core/textdomain.js +274 -0
- package/lib-esm/core/textdomain.js.map +1 -0
- package/lib-esm/core/textdomain.spec.d.ts +1 -0
- package/lib-esm/core/textdomain.spec.js +31 -0
- package/lib-esm/core/textdomain.spec.js.map +1 -0
- package/lib-esm/core/user-locales.d.ts +1 -0
- package/lib-esm/core/user-locales.js +8 -0
- package/lib-esm/core/user-locales.js.map +1 -0
- package/lib-esm/index-browser.d.ts +2 -0
- package/lib-esm/index-browser.js +26 -0
- package/lib-esm/index-browser.js.map +1 -0
- package/lib-esm/index.d.ts +2 -0
- package/lib-esm/index.js +19 -0
- package/lib-esm/index.js.map +1 -0
- package/lib-esm/parser/index.d.ts +2 -0
- package/lib-esm/parser/index.js +3 -0
- package/lib-esm/parser/index.js.map +1 -0
- package/lib-esm/parser/parse-json-catalog.d.ts +3 -0
- package/lib-esm/parser/parse-json-catalog.js +32 -0
- package/lib-esm/parser/parse-json-catalog.js.map +1 -0
- package/lib-esm/parser/parse-json-catalog.spec.d.ts +1 -0
- package/lib-esm/parser/parse-json-catalog.spec.js +39 -0
- package/lib-esm/parser/parse-json-catalog.spec.js.map +1 -0
- package/lib-esm/parser/parse-mo-catalog.d.ts +2 -0
- package/lib-esm/parser/parse-mo-catalog.js +82 -0
- package/lib-esm/parser/parse-mo-catalog.js.map +1 -0
- package/lib-esm/parser/parse-mo-catalog.spec.d.ts +1 -0
- package/lib-esm/parser/parse-mo-catalog.spec.js +113 -0
- package/lib-esm/parser/parse-mo-catalog.spec.js.map +1 -0
- package/lib-esm/transport/fs.d.ts +4 -0
- package/lib-esm/transport/fs.js +15 -0
- package/lib-esm/transport/fs.js.map +1 -0
- package/lib-esm/transport/http.d.ts +4 -0
- package/lib-esm/transport/http.js +24 -0
- package/lib-esm/transport/http.js.map +1 -0
- package/lib-esm/transport/http.spec.d.ts +1 -0
- package/lib-esm/transport/http.spec.js +114 -0
- package/lib-esm/transport/http.spec.js.map +1 -0
- package/lib-esm/transport/index.d.ts +3 -0
- package/lib-esm/transport/index.js +4 -0
- package/lib-esm/transport/index.js.map +1 -0
- package/lib-esm/transport/transport.interface.d.ts +3 -0
- package/lib-esm/transport/transport.interface.js +2 -0
- package/lib-esm/transport/transport.interface.js.map +1 -0
- package/package.json +72 -0
- package/webpack.common.js +38 -0
- package/webpack.dev.js +9 -0
- package/webpack.prod.js +8 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
This software is Copyright (C) 2020 by Guido Flohr.
|
|
2
|
+
|
|
3
|
+
This is free software, licensed under:
|
|
4
|
+
|
|
5
|
+
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE, Version 2, December 2004
|
|
6
|
+
|
|
7
|
+
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
|
8
|
+
Version 2, December 2004
|
|
9
|
+
|
|
10
|
+
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
|
|
11
|
+
|
|
12
|
+
Everyone is permitted to copy and distribute verbatim or modified
|
|
13
|
+
copies of this license document, and changing it is allowed as long
|
|
14
|
+
as the name is changed.
|
|
15
|
+
|
|
16
|
+
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
|
17
|
+
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
|
18
|
+
|
|
19
|
+
0. You just DO WHAT THE FUCK YOU WANT TO.
|
package/README.md
ADDED
|
@@ -0,0 +1,411 @@
|
|
|
1
|
+
# @esgettext/runtime <!-- omit in toc -->
|
|
2
|
+
|
|
3
|
+
GNU gettext-alike translation runtime library.
|
|
4
|
+
|
|
5
|
+
## Table of Contents <!-- omit in toc -->
|
|
6
|
+
|
|
7
|
+
- [API Documentation](#api-documentation)
|
|
8
|
+
- [Internationalizing Hello World](#internationalizing-hello-world)
|
|
9
|
+
- [Choosing a Textdomain](#choosing-a-textdomain)
|
|
10
|
+
- [Install the Library](#install-the-library)
|
|
11
|
+
- [Import the Library](#import-the-library)
|
|
12
|
+
- [Prepare Your Sources](#prepare-your-sources)
|
|
13
|
+
- [Translation Methods](#translation-methods)
|
|
14
|
+
- [Simple Translations With `_()`](#simple-translations-with-_)
|
|
15
|
+
- [Variable Interpolation With `_x()`](#variable-interpolation-with-_x)
|
|
16
|
+
- [Plural Forms With `_nx()`](#plural-forms-with-_nx)
|
|
17
|
+
- [Message Context With `_p()`](#message-context-with-_p)
|
|
18
|
+
- [Specific Locale with `_l`](#specific-locale-with-_l)
|
|
19
|
+
- [TODO: Gender-Specific Translations](#todo-gender-specific-translations)
|
|
20
|
+
- [Selecting the Preferred Language with `selectLocale()`](#selecting-the-preferred-language-with-selectlocale)
|
|
21
|
+
- [Internationalizing a Library](#internationalizing-a-library)
|
|
22
|
+
- [Frequently-Asked Questions](#frequently-asked-questions)
|
|
23
|
+
- [Why do Template Strings not Work?](#why-do-template-strings-not-work)
|
|
24
|
+
- [What Does the Error "template literals with embedded expressions are not allowed as arguments to gettext functions because they are not constant" Mean?](#what-does-the-error-template-literals-with-embedded-expressions-are-not-allowed-as-arguments-to-gettext-functions-because-they-are-not-constant-mean)
|
|
25
|
+
- [Copyright](#copyright)
|
|
26
|
+
|
|
27
|
+
## API Documentation
|
|
28
|
+
|
|
29
|
+
If you are already familiar with the concepts of the esgettext runtime library,
|
|
30
|
+
you can go straight to the [API documentation](https://gflohr.github.io/esgettext/packages/runtime/api-docs/globals.html).
|
|
31
|
+
|
|
32
|
+
## Internationalizing Hello World
|
|
33
|
+
|
|
34
|
+
You have written this little piece of JavaScript:
|
|
35
|
+
|
|
36
|
+
```javascript
|
|
37
|
+
console.log('Hello, world!');
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
What are the steps needed to internationalize it with this library?
|
|
41
|
+
|
|
42
|
+
### Choosing a Textdomain
|
|
43
|
+
|
|
44
|
+
First, you have to choose a unique identifier for your project so that the
|
|
45
|
+
translation catalogs will have a unique name. You are almost free
|
|
46
|
+
in what you are choosing but you have to keep in mind that the textdomain
|
|
47
|
+
will be part of a URI or filename and therefore a couple of rules apply:
|
|
48
|
+
|
|
49
|
+
- A textdomain _must not_ contain a slash ("/").
|
|
50
|
+
- A textdomain _should not_ contain a colon (":"), because of Windows.
|
|
51
|
+
- A textdomain _should not_ contain a backslash ("\"), because of Windows.
|
|
52
|
+
- A textdomain _should not_ contain binary characters, because of common sense.
|
|
53
|
+
|
|
54
|
+
In general, you should only use lowercase characters that are valid inside
|
|
55
|
+
hostnames, namely "a-z", "0-9", the hyphen "-", and the dot ".".
|
|
56
|
+
|
|
57
|
+
If possible, follow this advice:
|
|
58
|
+
|
|
59
|
+
1. If your organization has a domain, use the reverse(!) domain name followed by the name of your product for example "com.example.hello"
|
|
60
|
+
2. Otherwise, if your project sources are publicly hosted use the reverse domain name of your hoster followed by an identifier of your project. For example, the textdomain for `https://github.com/gflohr/esgettext` would then be "com.github.gflohr.esgettext".
|
|
61
|
+
3. Otherwise, use common sense.
|
|
62
|
+
|
|
63
|
+
We will use the the third rule and pick the textdomain "hello".
|
|
64
|
+
|
|
65
|
+
### Install the Library
|
|
66
|
+
|
|
67
|
+
You normally install the library with `npm` or `yarn`.
|
|
68
|
+
|
|
69
|
+
With `npm`:
|
|
70
|
+
|
|
71
|
+
```shell
|
|
72
|
+
$ npm install --save esgettext
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Or with `yarn`:
|
|
76
|
+
|
|
77
|
+
```shell
|
|
78
|
+
$ yarn add esgettext
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Import the Library
|
|
82
|
+
|
|
83
|
+
How to import the library, depends on your environment.
|
|
84
|
+
|
|
85
|
+
If you have the `import` keyword:
|
|
86
|
+
|
|
87
|
+
```javascript
|
|
88
|
+
import Textdomain from '@esgettext/runtime';
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
If you can use `require`:
|
|
92
|
+
|
|
93
|
+
```javascript
|
|
94
|
+
const esgettext = require('@esgettext/runtime');
|
|
95
|
+
const Textdomain = esgettext.Textdomain;
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
_FIXME! Is this correct?_
|
|
99
|
+
|
|
100
|
+
If you are writing javascript loaded by a browser:
|
|
101
|
+
|
|
102
|
+
```html
|
|
103
|
+
<script src="https://cdn.jsdelivr.net/npm/@esgettext/runtime/_bundles/runtime.min.js"></script>
|
|
104
|
+
<script>
|
|
105
|
+
var Textdomain = esgettext.Textdomain;
|
|
106
|
+
// ... your code follows.
|
|
107
|
+
</script>
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
If you want a specific version, you can do like this:
|
|
111
|
+
|
|
112
|
+
```html
|
|
113
|
+
<script src="https://cdn.jsdelivr.net/npm/@esgettext/runtime@0.1.0/_bundles/runtime.min.js"></script>
|
|
114
|
+
<script>
|
|
115
|
+
var Textdomain = esgettext.Textdomain;
|
|
116
|
+
// ... your code follows.
|
|
117
|
+
</script>
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Prepare Your Sources
|
|
121
|
+
|
|
122
|
+
Change your `hello.js` to read like this:
|
|
123
|
+
|
|
124
|
+
```javascript
|
|
125
|
+
import { Textdomain } from '@esgettext/runtime';
|
|
126
|
+
|
|
127
|
+
Textdomain.locale = 'fr';
|
|
128
|
+
const gtx = Textdomain.getInstance('hello');
|
|
129
|
+
gtx.bindtextdomain('/assets/locale');
|
|
130
|
+
gtx.resolve().then(function () {
|
|
131
|
+
console.log(gtx._('Hello, world!'));
|
|
132
|
+
});
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
_Hint:_ If you cannot use `import`, use one of the other techniques shown
|
|
136
|
+
above to make the `Textdomain` class available in your source!
|
|
137
|
+
|
|
138
|
+
What is happening here?
|
|
139
|
+
|
|
140
|
+
First, you set the locale (resp. language) to the desired value. Here we
|
|
141
|
+
choose "fr" for French. See the section [Selecting the Preferred Language with `selectLocale()`](#selecting-the-preferred-language-with-selectlocale)
|
|
142
|
+
for a more flexible way to select the user's locale.
|
|
143
|
+
|
|
144
|
+
You then get an instance of a `Textdomain` object. You cannot use the regular
|
|
145
|
+
constructor because it is private! The argument to the
|
|
146
|
+
[`getInstance()`](https://gflohr.github.io/esgettext/packages/runtime/api-docs/classes/textdomain.html#getinstance) class
|
|
147
|
+
method is the textdomain you have chosen.
|
|
148
|
+
|
|
149
|
+
You then have to tell the library where to find translations for the "hello"
|
|
150
|
+
textdomain. You do that with the instance method
|
|
151
|
+
[`bindtextdomain()`](https://gflohr.github.io/esgettext/packages/runtime/api-docs/classes/textdomain.html#bindtextdomain) that
|
|
152
|
+
receives a (base) directory as its argument. The actual translation catalog
|
|
153
|
+
would then be searched at `/assets/locale/fr/LC_MESSAGES/hello.json` (or
|
|
154
|
+
`hello.mo` depending on your environment).
|
|
155
|
+
|
|
156
|
+
Don't worry that there are no translations at the moment. Failure is handled
|
|
157
|
+
gracefully by the library falling back to using the original, untranslated
|
|
158
|
+
strings. See the [docs for tools](../tools/README.md) for
|
|
159
|
+
instructions on how to create translation catalogs.
|
|
160
|
+
|
|
161
|
+
You then have to [`resolve()`](https://gflohr.github.io/esgettext/packages/runtime/api-docs/classes/textdomain.html#resolve) the translations. The method returns a promise,
|
|
162
|
+
and your actual code should be moved into the promise's `then()` method.
|
|
163
|
+
|
|
164
|
+
Now that everything is loaded you can translate all messages by replacing
|
|
165
|
+
`'some string'` with `gtx._('some string')`. That's it!
|
|
166
|
+
|
|
167
|
+
### Translation Methods
|
|
168
|
+
|
|
169
|
+
The method [`_()`](https://gflohr.github.io/esgettext/packages/runtime/api-docs/classes/textdomain.html#_) is the simplest but by far not the only translation method
|
|
170
|
+
that esgettext has to offer.
|
|
171
|
+
|
|
172
|
+
#### Simple Translations With [`_()`](https://gflohr.github.io/esgettext/packages/runtime/api-docs/classes/textdomain.html#_)
|
|
173
|
+
|
|
174
|
+
The method [`_()`](https://gflohr.github.io/esgettext/packages/runtime/api-docs/classes/textdomain.html#_) has already been introduced:
|
|
175
|
+
|
|
176
|
+
```javascript
|
|
177
|
+
console.log(gtx._('Hello, world!'));
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
It returns the translation of its argument or just the argument if no
|
|
181
|
+
translation can be found.
|
|
182
|
+
|
|
183
|
+
#### Variable Interpolation With [`_x()`](https://gflohr.github.io/esgettext/packages/runtime/api-docs/classes/textdomain.html#_x)
|
|
184
|
+
|
|
185
|
+
Imagine you want to express RGB colors in human-readable form. The esgettext
|
|
186
|
+
way to do that goes like this:
|
|
187
|
+
|
|
188
|
+
```javascript
|
|
189
|
+
console.log(gtx._x(
|
|
190
|
+
'red: {r}, green: {g}, blue: {b}', {
|
|
191
|
+
r: red,
|
|
192
|
+
g: green,
|
|
193
|
+
b: blue
|
|
194
|
+
}
|
|
195
|
+
);
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
You use placeholders surrounded by curly braces (`{}`), and provide an object
|
|
199
|
+
as an additional argument where the keys are the placeholder names and the
|
|
200
|
+
values, the respective values to be interpolated.
|
|
201
|
+
|
|
202
|
+
Placeholder names must be valid C identifiers: They must begin with a
|
|
203
|
+
lower- or uppercase letter ("a" to "z", "A" to "Z") or an underscore ("\_")
|
|
204
|
+
followed by an arbitrary number of characters from the same set or decimal
|
|
205
|
+
digits ("0" to "9"). In regular espression syntax: `/^[_a-zA-Z][_a-zA-Z0-9]*$/`.
|
|
206
|
+
|
|
207
|
+
#### Plural Forms With [`_nx()`](https://gflohr.github.io/esgettext/packages/runtime/api-docs/classes/textdomain.html#_nx)
|
|
208
|
+
|
|
209
|
+
Translating a string with plural expressions is unfortunately somewhat
|
|
210
|
+
convoluted:
|
|
211
|
+
|
|
212
|
+
```javascript
|
|
213
|
+
console.log(
|
|
214
|
+
gtx._nx('One file copied', '{count} files copied.', count, {
|
|
215
|
+
count: count,
|
|
216
|
+
}),
|
|
217
|
+
);
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
Count, count, count, count.
|
|
221
|
+
|
|
222
|
+
If the variable `count` has the value 42, the above would yield in English:
|
|
223
|
+
"42 files copied.". If `count` had the value 1, it would yield: "One file
|
|
224
|
+
copied.".
|
|
225
|
+
|
|
226
|
+
The method [`_nx()`](https://gflohr.github.io/esgettext/packages/runtime/api-docs/classes/textdomain.html#_) has this signature:
|
|
227
|
+
|
|
228
|
+
```javascript
|
|
229
|
+
_nx(
|
|
230
|
+
(msgid: string),
|
|
231
|
+
(msgidPlural: string),
|
|
232
|
+
(numberOfItems: number),
|
|
233
|
+
(placeholders: Object),
|
|
234
|
+
);
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
Many times, the placeholder name will equal the variable name, so that you see
|
|
238
|
+
that name once inside the plural string as the placeholder, then as the
|
|
239
|
+
argument `numberOfItems`, then as the key in the placeholder hash, and again
|
|
240
|
+
as the value for that key.
|
|
241
|
+
|
|
242
|
+
Note that there is also a method [`_n()`](https://gflohr.github.io/esgettext/packages/runtime/api-docs/classes/textdomain.html#_n) that does the same as [`_nx()`](https://gflohr.github.io/esgettext/packages/runtime/api-docs/classes/textdomain.html#_nx) but
|
|
243
|
+
without inpterpolation but it only exists for completeness and is useless for
|
|
244
|
+
practical purposes.
|
|
245
|
+
|
|
246
|
+
#### Message Context With [`_p()`](https://gflohr.github.io/esgettext/packages/runtime/api-docs/classes/textdomain.html#_p)
|
|
247
|
+
|
|
248
|
+
It is sometimes possible that one English sentence can have multiple, different
|
|
249
|
+
meanings in another language. For example "Sun" can mean our planet's star or
|
|
250
|
+
the abbreviation of "Sunday". In order to allow translators to provide
|
|
251
|
+
accurate translations for each meaning, you can distinguish them by message
|
|
252
|
+
context:
|
|
253
|
+
|
|
254
|
+
```javascript
|
|
255
|
+
weekday = gtx._p('wday', 'Sun');
|
|
256
|
+
star = gtx._p('star', 'Sun');
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
The first argument is the context (a free-form string), the second is the
|
|
260
|
+
string to translate.
|
|
261
|
+
|
|
262
|
+
It is actually sufficient to use a context just for one of the two cases.
|
|
263
|
+
|
|
264
|
+
There are also methods [`_px()`](https://gflohr.github.io/esgettext/packages/runtime/api-docs/classes/textdomain.html#_px), when you need placeholders or [`_npx()`](https://gflohr.github.io/esgettext/packages/runtime/api-docs/classes/textdomain.html#_npx), when
|
|
265
|
+
you need placeholders and plural forms in addition to a message context.
|
|
266
|
+
|
|
267
|
+
#### Specific Locale with [`_l`](https://gflohr.github.io/esgettext/packages/runtime/api-docs/classes/textdomain.html#_l)
|
|
268
|
+
|
|
269
|
+
Most of the time, the locale resp. language is set just once by setting the
|
|
270
|
+
static property `locale`:
|
|
271
|
+
|
|
272
|
+
```javascript
|
|
273
|
+
Textdomain.locale = 'fr';
|
|
274
|
+
console.log(gtx._('Hello, world!'));
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
Alternatively, you can pass the locale with every call to a translation
|
|
278
|
+
method:
|
|
279
|
+
|
|
280
|
+
```javascript
|
|
281
|
+
console.log(gtx._l('fr', 'Hello, world!'));
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
There is not just [`_l()`](https://gflohr.github.io/esgettext/packages/runtime/api-docs/classes/textdomain.html#_l), but actually all of the above mentioned methods have
|
|
285
|
+
versions with a leading `_l`, like
|
|
286
|
+
[`_lx()`](https://gflohr.github.io/esgettext/packages/runtime/api-docs/classes/textdomain.html#_lx)
|
|
287
|
+
or as complicated as
|
|
288
|
+
[`_lnpx()`](https://gflohr.github.io/esgettext/packages/runtime/api-docs/classes/textdomain.html#_lnpx).
|
|
289
|
+
|
|
290
|
+
One use-case for the
|
|
291
|
+
[`_l()`](https://gflohr.github.io/esgettext/packages/runtime/api-docs/classes/textdomain.html#_l)
|
|
292
|
+
family of methods
|
|
293
|
+
would be a web server. A web server handles requests asynchronously, and a
|
|
294
|
+
global locale doesn't make sense. Instead, the language is typically bound
|
|
295
|
+
to the request or response and should be taken from there.
|
|
296
|
+
|
|
297
|
+
#### TODO: Gender-Specific Translations
|
|
298
|
+
|
|
299
|
+
This is on the todo list for a future version. You will be able to do something
|
|
300
|
+
like:
|
|
301
|
+
|
|
302
|
+
```javascript
|
|
303
|
+
msg = gtx._g(
|
|
304
|
+
user.gender,
|
|
305
|
+
'They have liked your photo.',
|
|
306
|
+
'She has liked your photo.',
|
|
307
|
+
);
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
### Selecting the Preferred Language with [`selectLocale()`](https://gflohr.github.io/esgettext/packages/runtime/api-docs/classes/textdomain.html#selectLocale)
|
|
311
|
+
|
|
312
|
+
Negotiating the preferred locale can be performed with the help of esgettext.
|
|
313
|
+
If your application supports the locales "en-US", "en-GB", "fr-FR", and
|
|
314
|
+
"de-DE", you can select a suitable locale for the current user by calling
|
|
315
|
+
[`Textdomain.selectlocale`](https://gflohr.github.io/esgettext/packages/runtime/api-docs/classes/textdomain.html#selectLocale)
|
|
316
|
+
|
|
317
|
+
```javascript
|
|
318
|
+
Textdomain.locale = Textdomain.selectLocale(['en-US', 'en-GB', 'fr-FR']);
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
[`Textdomain.selectLocale()`](https://gflohr.github.io/esgettext/packages/runtime/api-docs/classes/textdomain.html#selectLocale)
|
|
322
|
+
will return the most suitable locale for the current user. For browser code,
|
|
323
|
+
the browser will be queried for the user language preferences, for server
|
|
324
|
+
code the environment variables `LANGUAGE`, `LC_ALL`, `LANG`, and `LC_MESSAGES`
|
|
325
|
+
will be queried in that order.
|
|
326
|
+
|
|
327
|
+
You can also explicitly specify, which locales the user has requested by
|
|
328
|
+
passing a second argument:
|
|
329
|
+
|
|
330
|
+
```javascript
|
|
331
|
+
Textdomain.locale = Textdomain.selectLocale(
|
|
332
|
+
['en-US', 'en-GB', 'fr-FR'], // Supported by the application.
|
|
333
|
+
['de-DE', 'fr-FR'],
|
|
334
|
+
); // Requested by the user.
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
## Internationalizing a Library
|
|
338
|
+
|
|
339
|
+
Internationalizing a library is very simple. Take this sample library:
|
|
340
|
+
|
|
341
|
+
```javascript
|
|
342
|
+
function greet(name) {
|
|
343
|
+
return `Hello, ${name}`;
|
|
344
|
+
}
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
Internationalized, it would look like this:
|
|
348
|
+
|
|
349
|
+
```javascript
|
|
350
|
+
import { Textdomain } from '@esgettext/runtime';
|
|
351
|
+
|
|
352
|
+
const gtx = Textdomain.getInstance('hello-library');
|
|
353
|
+
gtx.bindtextdomain('/assets/locale');
|
|
354
|
+
|
|
355
|
+
function greet(name) {
|
|
356
|
+
return gtx._x('Hello, {name}', { name: name });
|
|
357
|
+
}
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
The main differences to an internationalized application are:
|
|
361
|
+
|
|
362
|
+
- You do not set [Textdomain.locale](https://gflohr.github.io/esgettext/packages/runtime/api-docs/classes/textdomain.html#locale) because the main application (the application that loads your library) does it.
|
|
363
|
+
- You do not call [resolve()](https://gflohr.github.io/esgettext/packages/runtime/api-docs/classes/textdomain.html#resolve) because whenever the main application calls `resolve()`, the catalogs for your library will also be loaded.
|
|
364
|
+
|
|
365
|
+
## Frequently-Asked Questions
|
|
366
|
+
|
|
367
|
+
### Why do Template Strings not Work?
|
|
368
|
+
|
|
369
|
+
A common error is to use template strings with interpolations as arguments to
|
|
370
|
+
the translation functions, for example:
|
|
371
|
+
|
|
372
|
+
```javascript
|
|
373
|
+
console.log(gtx._(`red: ${red}, green: ${green}, blue: ${blue}`);
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
That seems to work for English but the string never gets translated.
|
|
377
|
+
|
|
378
|
+
The reason is that the argument to
|
|
379
|
+
[`_()`](https://gflohr.github.io/esgettext/packages/runtime/api-docs/classes/textdomain.html#_)
|
|
380
|
+
is the lookup key into the translation database but that key has to be constant.
|
|
381
|
+
The method receives an argument like "red: 127, green: 63, blue: 31" because
|
|
382
|
+
the JavaScript engine has already interpolated the variables into the string.
|
|
383
|
+
But that string does not exist in the database.
|
|
384
|
+
|
|
385
|
+
You have to use
|
|
386
|
+
[`_x()`](https://gflohr.github.io/esgettext/packages/runtime/api-docs/classes/textdomain.html#_x)
|
|
387
|
+
instead:
|
|
388
|
+
|
|
389
|
+
```javascript
|
|
390
|
+
console.log(gtx._x(
|
|
391
|
+
'red: {r}, green: {g}, blue: {b}', {
|
|
392
|
+
r: red,
|
|
393
|
+
g: green,
|
|
394
|
+
b: blue
|
|
395
|
+
}
|
|
396
|
+
);
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
### What Does the Error "template literals with embedded expressions are not allowed as arguments to gettext functions because they are not constant" Mean?
|
|
400
|
+
|
|
401
|
+
See [Why do Template Strings not Work?](#why-do-template-strings-not-work)
|
|
402
|
+
above! The extractor `esgettext-xgettext` complains that you are using a
|
|
403
|
+
template string with interpolated expressions.
|
|
404
|
+
|
|
405
|
+
## Copyright
|
|
406
|
+
|
|
407
|
+
Copyright (C) 2020 Guido Flohr <guido.flohr@cantanea.com>, all
|
|
408
|
+
rights reserved.
|
|
409
|
+
|
|
410
|
+
This software is available under the terms and conditions of the
|
|
411
|
+
[WTFPL](http://www.wtfpl.net/about).
|