feat(i18n): localize the emoji and sticker picker into English and Russian
This commit is contained in:
parent
cd050c309b
commit
8989c0d7f7
8 changed files with 105 additions and 33 deletions
|
|
@ -1,4 +1,28 @@
|
|||
{
|
||||
"EmojiBoard": {
|
||||
"sticker": "Sticker",
|
||||
"emoji": "Emoji",
|
||||
"search": "Search",
|
||||
"search_or_react": "Search or Text Reaction",
|
||||
"react": "React",
|
||||
"no_sticker_packs": "No Sticker Packs!",
|
||||
"add_stickers_hint": "Add stickers from user, room or space settings.",
|
||||
"recent": "Recent",
|
||||
"personal_pack": "Personal Pack",
|
||||
"unknown": "Unknown",
|
||||
"unknown_pack": "Unknown Pack",
|
||||
"search_results": "Search Results",
|
||||
"no_results": "No Results found",
|
||||
"aria_emoji": "{{name}} emoji",
|
||||
"cat_people": "Smileys & People",
|
||||
"cat_nature": "Animals & Nature",
|
||||
"cat_food": "Food & Drinks",
|
||||
"cat_activity": "Activity",
|
||||
"cat_travel": "Travel & Places",
|
||||
"cat_object": "Objects",
|
||||
"cat_symbol": "Symbols",
|
||||
"cat_flag": "Flags"
|
||||
},
|
||||
"Organisms": {
|
||||
"RoomCommon": {
|
||||
"changed_room_name": " changed room name"
|
||||
|
|
|
|||
|
|
@ -1,4 +1,28 @@
|
|||
{
|
||||
"EmojiBoard": {
|
||||
"sticker": "Стикеры",
|
||||
"emoji": "Эмодзи",
|
||||
"search": "Поиск",
|
||||
"search_or_react": "Поиск или текст-реакция",
|
||||
"react": "Реакция",
|
||||
"no_sticker_packs": "Нет наборов стикеров",
|
||||
"add_stickers_hint": "Добавьте стикеры в настройках профиля, комнаты или пространства.",
|
||||
"recent": "Недавние",
|
||||
"personal_pack": "Личный набор",
|
||||
"unknown": "Без названия",
|
||||
"unknown_pack": "Набор без названия",
|
||||
"search_results": "Результаты поиска",
|
||||
"no_results": "Ничего не найдено",
|
||||
"aria_emoji": "{{name}}, эмодзи",
|
||||
"cat_people": "Смайлы и люди",
|
||||
"cat_nature": "Животные и природа",
|
||||
"cat_food": "Еда и напитки",
|
||||
"cat_activity": "Активности",
|
||||
"cat_travel": "Путешествия и места",
|
||||
"cat_object": "Предметы",
|
||||
"cat_symbol": "Символы",
|
||||
"cat_flag": "Флаги"
|
||||
},
|
||||
"Organisms": {
|
||||
"RoomCommon": {
|
||||
"changed_room_name": " изменил(а) название комнаты"
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import { isKeyHotkey } from 'is-hotkey';
|
|||
import { Room } from 'matrix-js-sdk';
|
||||
import { atom, PrimitiveAtom, useAtom, useSetAtom } from 'jotai';
|
||||
import { useVirtualizer } from '@tanstack/react-virtual';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { IEmoji } from '../../plugins/emoji';
|
||||
import { emojiGroups, emojis } from '../../plugins/emoji-data';
|
||||
import { useEmojiGroupLabels } from './useEmojiGroupLabels';
|
||||
|
|
@ -76,6 +77,7 @@ const useGroups = (
|
|||
|
||||
const recentEmojis = useRecentEmoji(mx, 21);
|
||||
const labels = useEmojiGroupLabels();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const emojiGroupItems = useMemo(() => {
|
||||
const g: EmojiGroupItem[] = [];
|
||||
|
|
@ -83,17 +85,18 @@ const useGroups = (
|
|||
|
||||
g.push({
|
||||
id: RECENT_GROUP_ID,
|
||||
name: 'Recent',
|
||||
name: t('EmojiBoard.recent'),
|
||||
items: recentEmojis,
|
||||
});
|
||||
|
||||
imagePacks.forEach((pack) => {
|
||||
let label = pack.meta.name;
|
||||
if (!label) label = isUserId(pack.id) ? 'Personal Pack' : mx.getRoom(pack.id)?.name;
|
||||
if (!label)
|
||||
label = isUserId(pack.id) ? t('EmojiBoard.personal_pack') : mx.getRoom(pack.id)?.name;
|
||||
|
||||
g.push({
|
||||
id: pack.id,
|
||||
name: label ?? 'Unknown',
|
||||
name: label ?? t('EmojiBoard.unknown'),
|
||||
items: pack
|
||||
.getImages(ImageUsage.Emoticon)
|
||||
.sort((a, b) => a.shortcode.localeCompare(b.shortcode)),
|
||||
|
|
@ -109,7 +112,7 @@ const useGroups = (
|
|||
});
|
||||
|
||||
return g;
|
||||
}, [mx, recentEmojis, labels, imagePacks, tab]);
|
||||
}, [mx, recentEmojis, labels, imagePacks, tab, t]);
|
||||
|
||||
const stickerGroupItems = useMemo(() => {
|
||||
const g: StickerGroupItem[] = [];
|
||||
|
|
@ -117,11 +120,12 @@ const useGroups = (
|
|||
|
||||
imagePacks.forEach((pack) => {
|
||||
let label = pack.meta.name;
|
||||
if (!label) label = isUserId(pack.id) ? 'Personal Pack' : mx.getRoom(pack.id)?.name;
|
||||
if (!label)
|
||||
label = isUserId(pack.id) ? t('EmojiBoard.personal_pack') : mx.getRoom(pack.id)?.name;
|
||||
|
||||
g.push({
|
||||
id: pack.id,
|
||||
name: label ?? 'Unknown',
|
||||
name: label ?? t('EmojiBoard.unknown'),
|
||||
items: pack
|
||||
.getImages(ImageUsage.Sticker)
|
||||
.sort((a, b) => a.shortcode.localeCompare(b.shortcode)),
|
||||
|
|
@ -129,7 +133,7 @@ const useGroups = (
|
|||
});
|
||||
|
||||
return g;
|
||||
}, [mx, imagePacks, tab]);
|
||||
}, [mx, imagePacks, tab, t]);
|
||||
|
||||
return [emojiGroupItems, stickerGroupItems];
|
||||
};
|
||||
|
|
@ -178,6 +182,7 @@ function EmojiSidebar({ activeGroupAtom, packs, onScrollToGroup }: EmojiSidebarP
|
|||
const usage = ImageUsage.Emoticon;
|
||||
const labels = useEmojiGroupLabels();
|
||||
const icons = useEmojiGroupIcons();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const handleScrollToGroup = (groupId: string) => {
|
||||
setActiveGroupId(groupId);
|
||||
|
|
@ -190,7 +195,7 @@ function EmojiSidebar({ activeGroupAtom, packs, onScrollToGroup }: EmojiSidebarP
|
|||
<GroupIcon
|
||||
active={activeGroupId === RECENT_GROUP_ID}
|
||||
id={RECENT_GROUP_ID}
|
||||
label="Recent"
|
||||
label={t('EmojiBoard.recent')}
|
||||
icon={Icons.RecentClock}
|
||||
onClick={handleScrollToGroup}
|
||||
/>
|
||||
|
|
@ -200,7 +205,8 @@ function EmojiSidebar({ activeGroupAtom, packs, onScrollToGroup }: EmojiSidebarP
|
|||
<SidebarDivider />
|
||||
{packs.map((pack) => {
|
||||
let label = pack.meta.name;
|
||||
if (!label) label = isUserId(pack.id) ? 'Personal Pack' : mx.getRoom(pack.id)?.name;
|
||||
if (!label)
|
||||
label = isUserId(pack.id) ? t('EmojiBoard.personal_pack') : mx.getRoom(pack.id)?.name;
|
||||
|
||||
const url =
|
||||
mxcUrlToHttp(mx, pack.getAvatarUrl(usage) ?? '', useAuthentication) ?? undefined;
|
||||
|
|
@ -210,7 +216,7 @@ function EmojiSidebar({ activeGroupAtom, packs, onScrollToGroup }: EmojiSidebarP
|
|||
key={pack.id}
|
||||
active={activeGroupId === pack.id}
|
||||
id={pack.id}
|
||||
label={label ?? 'Unknown Pack'}
|
||||
label={label ?? t('EmojiBoard.unknown_pack')}
|
||||
url={url}
|
||||
onClick={handleScrollToGroup}
|
||||
/>
|
||||
|
|
@ -252,6 +258,7 @@ function StickerSidebar({ activeGroupAtom, packs, onScrollToGroup }: StickerSide
|
|||
|
||||
const [activeGroupId, setActiveGroupId] = useAtom(activeGroupAtom);
|
||||
const usage = ImageUsage.Sticker;
|
||||
const { t } = useTranslation();
|
||||
|
||||
const handleScrollToGroup = (groupId: string) => {
|
||||
setActiveGroupId(groupId);
|
||||
|
|
@ -263,7 +270,8 @@ function StickerSidebar({ activeGroupAtom, packs, onScrollToGroup }: StickerSide
|
|||
<SidebarStack>
|
||||
{packs.map((pack) => {
|
||||
let label = pack.meta.name;
|
||||
if (!label) label = isUserId(pack.id) ? 'Personal Pack' : mx.getRoom(pack.id)?.name;
|
||||
if (!label)
|
||||
label = isUserId(pack.id) ? t('EmojiBoard.personal_pack') : mx.getRoom(pack.id)?.name;
|
||||
|
||||
const url =
|
||||
mxcUrlToHttp(mx, pack.getAvatarUrl(usage) ?? '', useAuthentication) ?? undefined;
|
||||
|
|
@ -273,7 +281,7 @@ function StickerSidebar({ activeGroupAtom, packs, onScrollToGroup }: StickerSide
|
|||
key={pack.id}
|
||||
active={activeGroupId === pack.id}
|
||||
id={pack.id}
|
||||
label={label ?? 'Unknown Pack'}
|
||||
label={label ?? t('EmojiBoard.unknown_pack')}
|
||||
url={url}
|
||||
onClick={handleScrollToGroup}
|
||||
/>
|
||||
|
|
@ -378,6 +386,7 @@ export function EmojiBoard({
|
|||
addToRecentEmoji = true,
|
||||
}: EmojiBoardProps) {
|
||||
const mx = useMatrixClient();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const emojiTab = tab === EmojiBoardTab.Emoji;
|
||||
const usage = emojiTab ? ImageUsage.Emoticon : ImageUsage.Sticker;
|
||||
|
|
@ -542,7 +551,9 @@ export function EmojiBoard({
|
|||
{searchedItems && (
|
||||
<EmojiGroup
|
||||
id={SEARCH_GROUP_ID}
|
||||
label={searchedItems.length ? 'Search Results' : 'No Results found'}
|
||||
label={
|
||||
searchedItems.length ? t('EmojiBoard.search_results') : t('EmojiBoard.no_results')
|
||||
}
|
||||
>
|
||||
{searchedItems.map(renderItem)}
|
||||
</EmojiGroup>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import React from 'react';
|
||||
import { Box } from 'folds';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { MatrixClient } from 'matrix-js-sdk';
|
||||
import { EmojiItemInfo, EmojiType } from '../types';
|
||||
import * as css from './styles.css';
|
||||
|
|
@ -27,6 +28,7 @@ type EmojiItemProps = {
|
|||
emoji: IEmoji;
|
||||
};
|
||||
export function EmojiItem({ emoji }: EmojiItemProps) {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<Box
|
||||
as="button"
|
||||
|
|
@ -35,7 +37,7 @@ export function EmojiItem({ emoji }: EmojiItemProps) {
|
|||
justifyContent="Center"
|
||||
className={css.EmojiItem}
|
||||
title={emoji.label}
|
||||
aria-label={`${emoji.label} emoji`}
|
||||
aria-label={t('EmojiBoard.aria_emoji', { name: emoji.label })}
|
||||
data-emoji-type={EmojiType.Emoji}
|
||||
data-emoji-data={emoji.unicode}
|
||||
data-emoji-shortcode={emoji.shortcode}
|
||||
|
|
@ -51,6 +53,7 @@ type CustomEmojiItemProps = {
|
|||
image: PackImageReader;
|
||||
};
|
||||
export function CustomEmojiItem({ mx, useAuthentication, image }: CustomEmojiItemProps) {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<Box
|
||||
as="button"
|
||||
|
|
@ -59,7 +62,7 @@ export function CustomEmojiItem({ mx, useAuthentication, image }: CustomEmojiIte
|
|||
justifyContent="Center"
|
||||
className={css.EmojiItem}
|
||||
title={image.body || image.shortcode}
|
||||
aria-label={`${image.body || image.shortcode} emoji`}
|
||||
aria-label={t('EmojiBoard.aria_emoji', { name: image.body || image.shortcode })}
|
||||
data-emoji-type={EmojiType.CustomEmoji}
|
||||
data-emoji-data={image.url}
|
||||
data-emoji-shortcode={image.shortcode}
|
||||
|
|
@ -81,6 +84,7 @@ type StickerItemProps = {
|
|||
};
|
||||
|
||||
export function StickerItem({ mx, useAuthentication, image }: StickerItemProps) {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<Box
|
||||
as="button"
|
||||
|
|
@ -89,7 +93,7 @@ export function StickerItem({ mx, useAuthentication, image }: StickerItemProps)
|
|||
justifyContent="Center"
|
||||
className={css.StickerItem}
|
||||
title={image.body || image.shortcode}
|
||||
aria-label={`${image.body || image.shortcode} emoji`}
|
||||
aria-label={t('EmojiBoard.aria_emoji', { name: image.body || image.shortcode })}
|
||||
data-emoji-type={EmojiType.Sticker}
|
||||
data-emoji-data={image.url}
|
||||
data-emoji-shortcode={image.shortcode}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
import React from 'react';
|
||||
import { Box, toRem, config, Icons, Icon, Text } from 'folds';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
export function NoStickerPacks() {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<Box
|
||||
style={{ padding: `${toRem(60)} ${config.space.S500}` }}
|
||||
|
|
@ -12,9 +14,9 @@ export function NoStickerPacks() {
|
|||
>
|
||||
<Icon size="600" src={Icons.Sticker} />
|
||||
<Box direction="Inherit">
|
||||
<Text align="Center">No Sticker Packs!</Text>
|
||||
<Text align="Center">{t('EmojiBoard.no_sticker_packs')}</Text>
|
||||
<Text priority="300" align="Center" size="T200">
|
||||
Add stickers from user, room or space settings.
|
||||
{t('EmojiBoard.add_stickers_hint')}
|
||||
</Text>
|
||||
</Box>
|
||||
</Box>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import React, { ChangeEventHandler, useRef } from 'react';
|
||||
import { Input, Chip, Icon, Icons, Text } from 'folds';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { mobileOrTablet } from '../../../utils/user-agent';
|
||||
|
||||
type SearchInputProps = {
|
||||
|
|
@ -15,6 +16,7 @@ export function SearchInput({
|
|||
onTextCustomEmojiSelect,
|
||||
}: SearchInputProps) {
|
||||
const inputRef = useRef<HTMLInputElement>(null);
|
||||
const { t } = useTranslation();
|
||||
|
||||
const handleReact = () => {
|
||||
const textEmoji = inputRef.current?.value.trim();
|
||||
|
|
@ -27,7 +29,7 @@ export function SearchInput({
|
|||
ref={inputRef}
|
||||
variant="SurfaceVariant"
|
||||
size="400"
|
||||
placeholder={allowTextCustomEmoji ? 'Search or Text Reaction ' : 'Search'}
|
||||
placeholder={allowTextCustomEmoji ? t('EmojiBoard.search_or_react') : t('EmojiBoard.search')}
|
||||
maxLength={50}
|
||||
after={
|
||||
allowTextCustomEmoji && query ? (
|
||||
|
|
@ -38,7 +40,7 @@ export function SearchInput({
|
|||
outlined
|
||||
onClick={handleReact}
|
||||
>
|
||||
<Text size="L400">React</Text>
|
||||
<Text size="L400">{t('EmojiBoard.react')}</Text>
|
||||
</Chip>
|
||||
) : (
|
||||
<Icon src={Icons.Search} size="50" />
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import React, { CSSProperties } from 'react';
|
||||
import { Badge, Box, Text } from 'folds';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { EmojiBoardTab } from '../types';
|
||||
|
||||
const styles: CSSProperties = {
|
||||
|
|
@ -13,6 +14,7 @@ export function EmojiBoardTabs({
|
|||
tab: EmojiBoardTab;
|
||||
onTabChange: (tab: EmojiBoardTab) => void;
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<Box gap="100">
|
||||
<Badge
|
||||
|
|
@ -24,7 +26,7 @@ export function EmojiBoardTabs({
|
|||
onClick={() => onTabChange(EmojiBoardTab.Sticker)}
|
||||
>
|
||||
<Text as="span" size="L400">
|
||||
Sticker
|
||||
{t('EmojiBoard.sticker')}
|
||||
</Text>
|
||||
</Badge>
|
||||
<Badge
|
||||
|
|
@ -36,7 +38,7 @@ export function EmojiBoardTabs({
|
|||
onClick={() => onTabChange(EmojiBoardTab.Emoji)}
|
||||
>
|
||||
<Text as="span" size="L400">
|
||||
Emoji
|
||||
{t('EmojiBoard.emoji')}
|
||||
</Text>
|
||||
</Badge>
|
||||
</Box>
|
||||
|
|
|
|||
|
|
@ -1,19 +1,22 @@
|
|||
import { useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { EmojiGroupId } from '../../plugins/emoji';
|
||||
|
||||
export type IEmojiGroupLabels = Record<EmojiGroupId, string>;
|
||||
|
||||
export const useEmojiGroupLabels = (): IEmojiGroupLabels =>
|
||||
useMemo(
|
||||
export const useEmojiGroupLabels = (): IEmojiGroupLabels => {
|
||||
const { t } = useTranslation();
|
||||
return useMemo(
|
||||
() => ({
|
||||
[EmojiGroupId.People]: 'Smileys & People',
|
||||
[EmojiGroupId.Nature]: 'Animals & Nature',
|
||||
[EmojiGroupId.Food]: 'Food & Drinks',
|
||||
[EmojiGroupId.Activity]: 'Activity',
|
||||
[EmojiGroupId.Travel]: 'Travel & Places',
|
||||
[EmojiGroupId.Object]: 'Objects',
|
||||
[EmojiGroupId.Symbol]: 'Symbols',
|
||||
[EmojiGroupId.Flag]: 'Flags',
|
||||
[EmojiGroupId.People]: t('EmojiBoard.cat_people'),
|
||||
[EmojiGroupId.Nature]: t('EmojiBoard.cat_nature'),
|
||||
[EmojiGroupId.Food]: t('EmojiBoard.cat_food'),
|
||||
[EmojiGroupId.Activity]: t('EmojiBoard.cat_activity'),
|
||||
[EmojiGroupId.Travel]: t('EmojiBoard.cat_travel'),
|
||||
[EmojiGroupId.Object]: t('EmojiBoard.cat_object'),
|
||||
[EmojiGroupId.Symbol]: t('EmojiBoard.cat_symbol'),
|
||||
[EmojiGroupId.Flag]: t('EmojiBoard.cat_flag'),
|
||||
}),
|
||||
[]
|
||||
[t]
|
||||
);
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue