feat: add built-in translations (#200)

* feat: add built-in translations

* docs: fix docs

* docs: fix docs
This commit is contained in:
Nolan Lawson 2021-08-06 10:05:58 -07:00 committed by GitHub
parent 9f124f808e
commit 96d0d1d171
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 149 additions and 8 deletions

1
.gitignore vendored
View File

@ -131,3 +131,4 @@ dist
/bundle.js
/test/benchmark/node_modules
/test/benchmark/data.json
/i18n

View File

@ -33,7 +33,8 @@ A lightweight emoji picker, distributed as a web component.
+ [Custom styling](#custom-styling)
* [JavaScript API](#javascript-api)
+ [Picker](#picker)
- [i18n structure](#i18n-structure)
- [Internationalization](#internationalization)
* [Built-in translations](#built-in-translations)
- [Custom category order](#custom-category-order)
+ [Database](#database)
- [Constructors](#constructors)
@ -287,9 +288,9 @@ Some values can also be set as declarative attributes:
Note that complex properties like `i18n` or `customEmoji` are not supported as attributes, because the DOM only
supports string attributes, not complex objects.
#### i18n structure
#### Internationalization
Here is the default English `i18n` object (`"en"` locale):
The `i18n` parameter specifies translations for the picker interface. Here is the default English `i18n` object:
<!-- i18n options start -->
@ -332,8 +333,36 @@ Here is the default English `i18n` object (`"en"` locale):
<!-- i18n options end -->
Note that some of these strings are only visible to users of screen readers.
But you should still support them if you internationalize your app!
Note that some of these strings are only visible to users of screen readers. They are still important for accessibility!
##### Built-in translations
Community-provided translations for some languages [are available](https://github.com/nolanlawson/emoji-picker-element/tree/master/src/i18n). You can use them like so:
```js
import fr from 'emoji-picker-element/i18n/fr';
import de from 'emoji-picker-element/i18n/de';
// French
picker.i18n = fr;
// German
picker.i18n = de;
```
Note that translations for the interface (`i18n`) are not the same as translations for the emoji data (`dataSource` and `locale`). To support both, you should do something like:
```js
import fr from 'emoji-picker-element/i18n/fr';
const picker = new Picker({
i18n: fr,
locale: 'fr',
dataSource: 'https://cdn.jsdelivr.net/npm/emoji-picker-element-data@^1/fr/emojibase/data.json',
});
```
If a built-in translation for your target language is not available, you can also write your own translation and pass it in as `i18n`. Please feel free to contribute your translation [here](https://github.com/nolanlawson/emoji-picker-element/tree/master/src/i18n).
#### Custom category order
@ -740,12 +769,20 @@ While this option can reduce your bundle size, note that it only works if your S
### Data source and JSON format
If you'd like to host the emoji JSON yourself, you can do:
If you'd like to host the emoji data (`dataSource`) yourself, you can do:
npm install emoji-picker-element-data@^1
Then host `node_modules/emoji-picker-element-data/en/emojibase/data.json` (or other JSON files) on your web server.
```js
const picker = new Picker({
dataSource: '/path/to/my/webserver/data.json'
});
```
See [`emoji-picker-element-data`](https://www.npmjs.com/package/emoji-picker-element-data) for details.
### Shortcodes
There is no standard for shortcodes, so unlike other emoji data, there is some disagreement as to what a "shortcode" actually is.

34
bin/buildI18n.js Normal file
View File

@ -0,0 +1,34 @@
import path from 'path'
import { copyFile, readdir, writeFile } from './fs.js'
import mkdirp from 'mkdirp'
import rimraf from 'rimraf'
import { promisify } from 'util'
const __dirname = path.dirname(new URL(import.meta.url).pathname)
async function main () {
const targetDir = path.join(__dirname, '../i18n')
await promisify(rimraf)(targetDir)
await mkdirp(targetDir)
const sourceDir = path.join(__dirname, '../src/picker/i18n')
const sourceFiles = await readdir(sourceDir)
await Promise.all(sourceFiles.map(async sourceFile => {
await Promise.all([
copyFile(path.join(sourceDir, sourceFile), path.join(targetDir, sourceFile)),
writeFile(path.join(targetDir, sourceFile.replace('.js', '.d.ts')), `
import { I18n } from "../shared";
declare const _default: I18n;
export default _default;
`.trim())
])
}))
}
main().catch(err => {
console.error(err)
process.exit(1)
})

View File

@ -18,11 +18,12 @@
],
"scripts": {
"prepare": "run-s build",
"build": "run-s build:rollup build:css-docs build:i18n-docs build:toc",
"build": "run-s build:rollup build:i18n build:css-docs build:i18n-docs build:toc",
"build:rollup": "cross-env NODE_ENV=production rollup -c",
"build:css-docs": "node ./bin/generateCssDocs",
"build:i18n-docs": "node ./bin/generateI18nDocs",
"build:toc": "node ./bin/generateTOC",
"build:i18n": "node ./bin/buildI18n",
"benchmark:runtime": "cross-env PERF=1 run-s build:rollup && ./bin/run-benchmark.sh",
"benchmark:bundlesize": "run-s build:rollup benchmark:bundle benchmark:run-bundlesize",
"benchmark:bundle": "rollup -c ./test/bundlesize/rollup.config.js",

View File

@ -1,7 +1,7 @@
import SveltePicker from './components/Picker/Picker.svelte'
import { DEFAULT_DATA_SOURCE, DEFAULT_LOCALE } from '../database/constants'
import { DEFAULT_CATEGORY_SORTING, DEFAULT_SKIN_TONE_EMOJI } from './constants'
import enI18n from '../picker/i18n/en.js'
import enI18n from './i18n/en.js'
import styles from 'emoji-picker-element-styles'
import Database from './ImportedDatabase'

34
src/picker/i18n/de.js Normal file
View File

@ -0,0 +1,34 @@
export default {
categoriesLabel: 'Kategorien',
emojiUnsupportedMessage: 'Dein Browser unterstützt keine farbigen Emojis.',
favoritesLabel: 'Favoriten',
loadingMessage: 'Wird geladen…',
networkErrorMessage: 'Konnte Emoji nicht laden. Versuche, die Seite neu zu laden.',
regionLabel: 'Emoji auswählen',
searchDescription: 'Wenn Suchergebnisse verfügbar sind, wähle sie mit Pfeil rauf und runter, dann Eingabetaste, aus.',
searchLabel: 'Suchen',
searchResultsLabel: 'Suchergebnisse',
skinToneDescription: 'Wenn angezeigt, nutze Pfeiltasten rauf und runter zum Auswählen, Eingabe zum Akzeptieren.',
skinToneLabel: 'Wähle einen Hautton (aktuell {skinTone})',
skinTonesLabel: 'Hauttöne',
skinTones: [
'Standard',
'Hell',
'Mittel-hell',
'Mittel',
'Mittel-dunkel',
'Dunkel'
],
categories: {
custom: 'Benutzerdefiniert',
'smileys-emotion': 'Smileys und Emoticons',
'people-body': 'Menschen und Körper',
'animals-nature': 'Tiere und Natur',
'food-drink': 'Essen und Trinken',
'travel-places': 'Reisen und Orte',
activities: 'Aktivitäten',
objects: 'Objekte',
symbols: 'Symbole',
flags: 'Flaggen'
}
}

34
src/picker/i18n/fr.js Normal file
View File

@ -0,0 +1,34 @@
export default {
categoriesLabel: 'Catégories',
emojiUnsupportedMessage: 'Votre navigateur ne soutient pas les emojis en couleur.',
favoritesLabel: 'Favoris',
loadingMessage: 'Chargement en cours…',
networkErrorMessage: 'Impossible de charger les emojis. Veuillez essayer de recharger.',
regionLabel: 'Choisir un emoji',
searchDescription: 'Quand les résultats sont disponisbles, appuyez la fleche vers le haut ou le bas et la touche entrée pour choisir.',
searchLabel: 'Rechercher',
searchResultsLabel: 'Résultats',
skinToneDescription: 'Quand disponible, appuyez la fleche vers le haut ou le bas et la touch entrée pour choisir.',
skinToneLabel: 'Choisir une couleur de peau (actuellement {skinTone})',
skinTonesLabel: 'Couleurs de peau',
skinTones: [
'Défaut',
'Clair',
'Moyennement clair',
'Moyen',
'Moyennement sombre',
'Sombre'
],
categories: {
custom: 'Customisé',
'smileys-emotion': 'Les smileyes et les émoticônes',
'people-body': 'Les gens et le corps',
'animals-nature': 'Les animaux et la nature',
'food-drink': 'La nourriture et les boissons',
'travel-places': 'Les voyages et les endroits',
activities: 'Les activités',
objects: 'Les objets',
symbols: 'Les symbols',
flags: 'Les drapeaux'
}
}