feat: intl support for emoji picker (#1910)
* feat: intl support for emoji picker Fixes #1908 * fix: update emoji-picker-element * fix: fix typo
This commit is contained in:
parent
2de875795b
commit
a028a7e880
|
@ -8,7 +8,7 @@
|
|||
/static/icons.svg
|
||||
/static/robots.txt
|
||||
/static/inline-script.js.map
|
||||
/static/emoji-all-en.json
|
||||
/static/emoji-*.json
|
||||
/src/inline-script/checksum.js
|
||||
yarn-error.log
|
||||
|
||||
|
|
|
@ -1,17 +1,48 @@
|
|||
import path from 'path'
|
||||
import fs from 'fs'
|
||||
import { promisify } from 'util'
|
||||
import { LOCALE } from '../src/routes/_static/intl'
|
||||
|
||||
const readFile = promisify(fs.readFile)
|
||||
const writeFile = promisify(fs.writeFile)
|
||||
|
||||
// Try 'en-US' first, then 'en' if that doesn't exist
|
||||
const PREFERRED_LOCALES = [LOCALE, LOCALE.split('-')[0]]
|
||||
|
||||
// emojibase seems like the most "neutral" shortcodes, but cldr is available in every language
|
||||
const PREFERRED_SHORTCODES = ['emojibase', 'cldr']
|
||||
|
||||
async function getEmojiI18nFile (locale, shortcode) {
|
||||
const filename = path.resolve(__dirname,
|
||||
'../node_modules/emoji-picker-element-data',
|
||||
locale,
|
||||
shortcode,
|
||||
'data.json')
|
||||
try {
|
||||
return JSON.parse(await readFile(filename, 'utf8'))
|
||||
} catch (err) { /* ignore */ }
|
||||
}
|
||||
|
||||
async function getFirstExistingEmojiI18nFile () {
|
||||
for (const locale of PREFERRED_LOCALES) {
|
||||
for (const shortcode of PREFERRED_SHORTCODES) {
|
||||
const json = await getEmojiI18nFile(locale, shortcode)
|
||||
if (json) {
|
||||
return json
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function main () {
|
||||
const json = JSON.parse(await readFile(
|
||||
path.resolve(__dirname, '../node_modules/emoji-picker-element-data/en/emojibase-legacy/data.json'),
|
||||
'utf8')
|
||||
)
|
||||
const json = await getFirstExistingEmojiI18nFile()
|
||||
|
||||
if (!json) {
|
||||
throw new Error(`Couldn't find i18n data for locale ${LOCALE}. Is it supported in emoji-picker-element-data?`)
|
||||
}
|
||||
|
||||
await writeFile(
|
||||
path.resolve(__dirname, '../static/emoji-all-en.json'),
|
||||
path.resolve(__dirname, `../static/emoji-${LOCALE}.json`),
|
||||
JSON.stringify(json),
|
||||
'utf8'
|
||||
)
|
||||
|
|
|
@ -49,7 +49,7 @@
|
|||
"compression": "^1.7.4",
|
||||
"cross-env": "^7.0.2",
|
||||
"css-dedoupe": "^0.1.1",
|
||||
"emoji-picker-element": "^1.3.0",
|
||||
"emoji-picker-element": "^1.3.1",
|
||||
"emoji-picker-element-data": "^1.0.0",
|
||||
"emoji-regex": "^9.0.0",
|
||||
"encoding": "^0.1.13",
|
||||
|
|
|
@ -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'
|
||||
}
|
||||
}
|
|
@ -8,7 +8,8 @@
|
|||
<div class="emoji-container">
|
||||
<emoji-picker
|
||||
ref:picker
|
||||
data-source="/emoji-all-en.json"
|
||||
locale={emojiPickerLocale}
|
||||
data-source={emojiPickerDataSource}
|
||||
class={darkMode ? 'dark' : 'light'}
|
||||
on:emoji-click="onEmojiSelected(event)"
|
||||
on:keydown="onPickerKeydown(event)"
|
||||
|
@ -67,6 +68,7 @@
|
|||
import { convertCustomEmojiToEmojiPickerFormat } from '../../../_utils/convertCustomEmojiToEmojiPickerFormat'
|
||||
import { supportsFocusVisible } from '../../../_utils/supportsFocusVisible'
|
||||
import { importFocusVisible } from '../../../_utils/asyncPolyfills'
|
||||
import { emojiPickerI18n, emojiPickerDataSource, emojiPickerLocale } from '../../../_static/emojiPickerIntl'
|
||||
|
||||
export default {
|
||||
async oncreate () {
|
||||
|
@ -75,6 +77,9 @@
|
|||
const { enableGrayscale, isUserTouching } = this.store.get()
|
||||
const { picker } = this.refs
|
||||
picker.customEmoji = customEmoji
|
||||
if (emojiPickerI18n) {
|
||||
picker.i18n = emojiPickerI18n
|
||||
}
|
||||
// break into shadow DOM to fix grayscale in Wellness grayscale mode
|
||||
if (enableGrayscale) {
|
||||
const style = document.createElement('style')
|
||||
|
@ -100,6 +105,10 @@
|
|||
ModalDialog
|
||||
},
|
||||
store: () => store,
|
||||
data: () => ({
|
||||
emojiPickerLocale,
|
||||
emojiPickerDataSource
|
||||
}),
|
||||
computed: {
|
||||
darkMode: ({ $currentTheme }) => isDarkTheme($currentTheme),
|
||||
customEmoji: ({ $currentCustomEmoji, $autoplayGifs }) => (
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
import { LOCALE } from './intl'
|
||||
|
||||
export const emojiPickerDataSource = `/emoji-${LOCALE}.json`
|
||||
|
||||
// this should be undefined for English; it's already bundled with emoji-picker-element
|
||||
export const emojiPickerI18n = process.env.EMOJI_PICKER_I18N
|
||||
|
||||
// To avoid creating a new IDB database named emoji-picker-en-US, just
|
||||
// reuse the existing default "en" one (otherwise people will end up with
|
||||
// a stale database taking up useless space)
|
||||
export const emojiPickerLocale = LOCALE === 'en-US' ? 'en' : LOCALE
|
|
@ -1,5 +1,6 @@
|
|||
import Database from 'emoji-picker-element/database'
|
||||
import { lifecycle } from './lifecycle'
|
||||
import { emojiPickerLocale, emojiPickerDataSource } from '../_static/emojiPickerIntl'
|
||||
|
||||
let database
|
||||
|
||||
|
@ -23,7 +24,8 @@ function applySkinToneToEmoji (emoji, skinTone) {
|
|||
export function init () {
|
||||
if (!database) {
|
||||
database = new Database({
|
||||
dataSource: '/emoji-all-en.json'
|
||||
locale: emojiPickerLocale,
|
||||
dataSource: emojiPickerDataSource
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ const assets = __assets__
|
|||
.filter(filename => filename !== '/robots.txt')
|
||||
.filter(filename => !filename.includes('traineddata.gz')) // cache on-demand
|
||||
.filter(filename => !filename.endsWith('.webapp')) // KaiOS manifest
|
||||
.filter(filename => !filename.includes('emoji-all-en.json')) // useless to cache; it already goes in IndexedDB
|
||||
.filter(filename => !/emoji-.*?\.json$/.test(filename)) // useless to cache; it already goes in IndexedDB
|
||||
|
||||
// `shell` is an array of all the files generated by webpack
|
||||
// also contains '/index.html' for some reason
|
||||
|
|
|
@ -100,6 +100,16 @@ test('autosuggest handles works with regular emoji - clicking', async t => {
|
|||
.expect(composeInput.value).eql('\ud83c\udf4d @quux ')
|
||||
})
|
||||
|
||||
test('autosuggest can suggest native emoji', async t => {
|
||||
await loginAsFoobar(t)
|
||||
await t
|
||||
.hover(composeInput)
|
||||
.typeText(composeInput, ':slight')
|
||||
.expect(getNthAutosuggestionResult(1).innerText).contains(':slightly_smiling_face:', { timeout })
|
||||
.click(getNthAutosuggestionResult(1))
|
||||
.expect(composeInput.value).eql('\ud83d\ude42 ')
|
||||
})
|
||||
|
||||
test('autosuggest only shows for one input', async t => {
|
||||
await loginAsFoobar(t)
|
||||
await t
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { LOCALE } from '../src/routes/_static/intl'
|
||||
import { DEFAULT_LOCALE, LOCALE } from '../src/routes/_static/intl'
|
||||
|
||||
const path = require('path')
|
||||
const webpack = require('webpack')
|
||||
|
@ -19,6 +19,9 @@ const output = Object.assign(config.client.output(), {
|
|||
chunkFilename: dev ? '[hash]/[id].js' : '[id].[contenthash].js'
|
||||
})
|
||||
|
||||
const emojiPickerI18n = LOCALE !== DEFAULT_LOCALE &&
|
||||
require(path.join(__dirname, '../src/intl/emoji-picker/', `${LOCALE}.js`)).default
|
||||
|
||||
module.exports = {
|
||||
entry: config.client.entry(),
|
||||
output,
|
||||
|
@ -101,7 +104,8 @@ module.exports = {
|
|||
'process.env.INLINE_SVGS': JSON.stringify(inlineSvgs),
|
||||
'process.env.ALL_SVGS': JSON.stringify(allSvgs),
|
||||
'process.env.URL_REGEX': urlRegex.toString(),
|
||||
'process.env.LOCALE': JSON.stringify(LOCALE)
|
||||
'process.env.LOCALE': JSON.stringify(LOCALE),
|
||||
'process.env.EMOJI_PICKER_I18N': emojiPickerI18n ? JSON.stringify(emojiPickerI18n) : 'undefined'
|
||||
}),
|
||||
new webpack.NormalModuleReplacementPlugin(
|
||||
/\/_database\/database\.js$/, // this version plays nicer with IDEs
|
||||
|
|
|
@ -2904,10 +2904,10 @@ emoji-picker-element-data@^1.0.0:
|
|||
resolved "https://registry.yarnpkg.com/emoji-picker-element-data/-/emoji-picker-element-data-1.0.0.tgz#1e9c4b399ce6e1858514df4c25b65284d981f92f"
|
||||
integrity sha512-Ch6Ibuc2DJAh9MMyaH0hxsfkCoGAkYVWf9i1JC30PsaC4L9rmS7LMvu1iR396NHecdMYToJEQEOneatPVGe/IQ==
|
||||
|
||||
emoji-picker-element@^1.3.0:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/emoji-picker-element/-/emoji-picker-element-1.3.0.tgz#d78deba0ebc4b87731bb2c16f7be00ec458d7647"
|
||||
integrity sha512-Zg+8rtr3vXKuAgBXWpSBghHq+I6o7+35N+25MN3P07pUyk07GXJ6B+gKr8ttUo2LZrLDZVoqKOVMzowkNwwZIg==
|
||||
emoji-picker-element@^1.3.1:
|
||||
version "1.3.1"
|
||||
resolved "https://registry.yarnpkg.com/emoji-picker-element/-/emoji-picker-element-1.3.1.tgz#844e1ed261b6cda431423a1652da977202cb2090"
|
||||
integrity sha512-+WtNPw28snGd5ZXVS5mAAKsAJ1+hJVRdXNQ9ZCdWSLVCK1mtJjcHl2dMxtB1LxSpX6m79DAAHMmDJRjqbRA+5w==
|
||||
|
||||
emoji-regex@^7.0.1:
|
||||
version "7.0.3"
|
||||
|
|
Loading…
Reference in New Issue