From a028a7e880b9bb98ecabb0dd3ece2fc6a38e58f7 Mon Sep 17 00:00:00 2001 From: Nolan Lawson Date: Fri, 18 Dec 2020 20:02:36 -0800 Subject: [PATCH] feat: intl support for emoji picker (#1910) * feat: intl support for emoji picker Fixes #1908 * fix: update emoji-picker-element * fix: fix typo --- .gitignore | 2 +- bin/build-assets.js | 41 ++++++++++++++++--- package.json | 2 +- src/intl/emoji-picker/fr.js | 34 +++++++++++++++ .../dialog/components/EmojiDialog.html | 11 ++++- src/routes/_static/emojiPickerIntl.js | 11 +++++ src/routes/_utils/emojiDatabase.js | 4 +- src/service-worker.js | 2 +- tests/spec/018-compose-autosuggest.js | 10 +++++ webpack/client.config.js | 8 +++- yarn.lock | 8 ++-- 11 files changed, 117 insertions(+), 16 deletions(-) create mode 100644 src/intl/emoji-picker/fr.js create mode 100644 src/routes/_static/emojiPickerIntl.js diff --git a/.gitignore b/.gitignore index 7bf0fa18..fdf14967 100644 --- a/.gitignore +++ b/.gitignore @@ -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 diff --git a/bin/build-assets.js b/bin/build-assets.js index 14a908e1..5dc271e0 100644 --- a/bin/build-assets.js +++ b/bin/build-assets.js @@ -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' ) diff --git a/package.json b/package.json index 0b65ff9b..e546a616 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/src/intl/emoji-picker/fr.js b/src/intl/emoji-picker/fr.js new file mode 100644 index 00000000..f2df4db7 --- /dev/null +++ b/src/intl/emoji-picker/fr.js @@ -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' + } +} diff --git a/src/routes/_components/dialog/components/EmojiDialog.html b/src/routes/_components/dialog/components/EmojiDialog.html index 3cf94b60..c2b8aa7f 100644 --- a/src/routes/_components/dialog/components/EmojiDialog.html +++ b/src/routes/_components/dialog/components/EmojiDialog.html @@ -8,7 +8,8 @@
store, + data: () => ({ + emojiPickerLocale, + emojiPickerDataSource + }), computed: { darkMode: ({ $currentTheme }) => isDarkTheme($currentTheme), customEmoji: ({ $currentCustomEmoji, $autoplayGifs }) => ( diff --git a/src/routes/_static/emojiPickerIntl.js b/src/routes/_static/emojiPickerIntl.js new file mode 100644 index 00000000..56407273 --- /dev/null +++ b/src/routes/_static/emojiPickerIntl.js @@ -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 diff --git a/src/routes/_utils/emojiDatabase.js b/src/routes/_utils/emojiDatabase.js index 18ab738a..5f3b386c 100644 --- a/src/routes/_utils/emojiDatabase.js +++ b/src/routes/_utils/emojiDatabase.js @@ -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 }) } } diff --git a/src/service-worker.js b/src/service-worker.js index 722c3748..e992f184 100644 --- a/src/service-worker.js +++ b/src/service-worker.js @@ -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 diff --git a/tests/spec/018-compose-autosuggest.js b/tests/spec/018-compose-autosuggest.js index 4a337a08..d6afb27f 100644 --- a/tests/spec/018-compose-autosuggest.js +++ b/tests/spec/018-compose-autosuggest.js @@ -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 diff --git a/webpack/client.config.js b/webpack/client.config.js index 5dd46c51..238ef547 100644 --- a/webpack/client.config.js +++ b/webpack/client.config.js @@ -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 diff --git a/yarn.lock b/yarn.lock index b68344cc..316116d5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -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"