Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: Handling plural translations #30645

Merged
merged 15 commits into from
Jan 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/grumpy-trainers-hope.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@rocket.chat/meteor': patch
---

Apply plural translations at a few places.
2 changes: 1 addition & 1 deletion apps/meteor/.scripts/translation-check.ts
Original file line number Diff line number Diff line change
Expand Up @@ -237,8 +237,8 @@ const checkFiles = async (sourceDirPath: string, sourceLng: string, fix = false)

for await (const { path, json, lng } of translations) {
await checkPlaceholdersFormat({ json, path, fix });
await checkMissingPlurals({ json, path, lng, fix });
await checkExceedingKeys({ json, path, lng, sourceJson, sourceLng, fix });
await checkMissingPlurals({ json, path, lng, fix });
}
};

Expand Down
8 changes: 6 additions & 2 deletions apps/meteor/app/utils/lib/i18n.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,13 @@ import { isObject } from '../../../lib/utils/isObject';

export const i18n = i18next.use(sprintf);

export const addSprinfToI18n = function (t: (key: string, ...replaces: any) => string) {
export const addSprinfToI18n = function (t: (typeof i18n)['t']) {
return function (key: string, ...replaces: any): string {
if (replaces[0] === undefined || (isObject(replaces[0]) && !Array.isArray(replaces[0]))) {
if (replaces[0] === undefined) {
return t(key, ...replaces);
}

if (isObject(replaces[0]) && !Array.isArray(replaces[0])) {
return t(key, ...replaces);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Icon } from '@rocket.chat/fuselage';
import { useConnectionStatus, useTranslation } from '@rocket.chat/ui-contexts';
import type { MouseEventHandler, FC } from 'react';
import type { MouseEventHandler } from 'react';
import React, { useEffect, useRef, useState } from 'react';

import './ConnectionStatusBar.styles.css';
Expand Down Expand Up @@ -45,7 +45,7 @@ const useReconnectCountdown = (
return reconnectCountdown;
};

const ConnectionStatusBar: FC = function ConnectionStatusBar() {
function ConnectionStatusBar() {
const { connected, retryTime, status, reconnect } = useConnectionStatus();
const reconnectCountdown = useReconnectCountdown(retryTime, status);
const t = useTranslation();
Expand Down Expand Up @@ -77,6 +77,6 @@ const ConnectionStatusBar: FC = function ConnectionStatusBar() {
)}
</div>
);
};
}

export default ConnectionStatusBar;
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ const DiscussionMetrics = ({ lm, count, rid, drid }: DiscussionMetricsProps): Re
<MessageBlock>
<MessageMetrics>
<MessageMetricsReply data-rid={rid} data-drid={drid} onClick={() => goToRoom(drid)}>
{count ? t('message_counter', { counter: count, count }) : t('Reply')}
{count ? t('message_counter', { count }) : t('Reply')}
</MessageMetricsReply>
<MessageMetricsItem title={lm?.toLocaleString()}>
<MessageMetricsItem.Icon name='clock' />
Expand Down
16 changes: 2 additions & 14 deletions apps/meteor/client/sidebar/footer/voip/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { VoIpCallerInfo } from '@rocket.chat/core-typings';
import { useEndpoint, useTranslation } from '@rocket.chat/ui-contexts';
import type { ReactElement } from 'react';
import React, { useCallback, useMemo, useState } from 'react';
import React, { useCallback, useState } from 'react';

import { useVoipFooterMenu } from '../../../../ee/client/hooks/useVoipFooterMenu';
import {
Expand Down Expand Up @@ -62,18 +62,6 @@ export const VoipFooter = (): ReactElement | null => {
return subtitles[state] || '';
};

const getCallsInQueueText = useMemo((): string => {
if (queueCounter === 0) {
return t('Calls_in_queue_empty');
}

if (queueCounter === 1) {
return t('Calls_in_queue', { calls: queueCounter });
}

return t('Calls_in_queue_plural', { calls: queueCounter });
}, [queueCounter, t]);

if (!('caller' in callerInfo)) {
return <SidebarFooterDefault />;
}
Expand All @@ -91,7 +79,7 @@ export const VoipFooter = (): ReactElement | null => {
togglePause={togglePause}
createRoom={createRoom}
openRoom={openRoom}
callsInQueue={getCallsInQueueText}
callsInQueue={t('Calls_in_queue', { count: queueCounter })}
dispatchEvent={dispatchEvent}
openedRoomInfo={openedRoomInfo}
isEnterprise={isEnterprise}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { Pagination, Field, FieldLabel, FieldRow } from '@rocket.chat/fuselage';
import { useDebouncedValue, useMediaQuery, useMutableCallback } from '@rocket.chat/fuselage-hooks';
import { useEndpoint, useToastMessageDispatch, useRoute, useTranslation } from '@rocket.chat/ui-contexts';
import { useEndpoint, useToastMessageDispatch, useRoute } from '@rocket.chat/ui-contexts';
import { useQuery } from '@tanstack/react-query';
import type { FC } from 'react';
import React, { useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';

import FilterByText from '../../../components/FilterByText';
import GenericNoResults from '../../../components/GenericNoResults';
Expand All @@ -23,7 +24,7 @@ import DateRangePicker from './helpers/DateRangePicker';
const ModerationConsoleTable: FC = () => {
const [text, setText] = useState('');
const moderationRoute = useRoute('moderation-console');
const t = useTranslation();
const { t } = useTranslation();
const isDesktopOrLarger = useMediaQuery('(min-width: 1024px)');

const { sortBy, sortDirection, setSort } = useSort<'reports.ts' | 'reports.message.u.username' | 'reports.description' | 'count'>(
Expand Down Expand Up @@ -110,7 +111,7 @@ const ModerationConsoleTable: FC = () => {
{t('Moderation_Report_date')}
</GenericTableHeaderCell>,
<GenericTableHeaderCell key='reports' direction={sortDirection} active={sortBy === 'count'} onClick={setSort} sort='count'>
{t('Moderation_Report_plural')}
{t('Moderation_Report_reports')}
</GenericTableHeaderCell>,
<GenericTableHeaderCell key='actions' width='x48' />,
],
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { useEndpoint, useRouter, useSetModal, useToastMessageDispatch, useTranslation } from '@rocket.chat/ui-contexts';
import { useEndpoint, useRouter, useSetModal, useToastMessageDispatch } from '@rocket.chat/ui-contexts';
import { useMutation, useQueryClient } from '@tanstack/react-query';
import React from 'react';
import { useTranslation } from 'react-i18next';

import type { GenericMenuItemProps } from '../../../../components/GenericMenu/GenericMenuItem';
import GenericModal from '../../../../components/GenericModal';

const useDismissUserAction = (userId: string): GenericMenuItemProps => {
const t = useTranslation();
const { t } = useTranslation();
const setModal = useSetModal();
const dispatchToastMessage = useToastMessageDispatch();
const moderationRoute = useRouter();
Expand All @@ -20,7 +21,7 @@ const useDismissUserAction = (userId: string): GenericMenuItemProps => {
dispatchToastMessage({ type: 'error', message: error });
},
onSuccess: () => {
dispatchToastMessage({ type: 'success', message: t('Moderation_Reports_dismissed_plural') });
dispatchToastMessage({ type: 'success', message: t('Moderation_Reports_all_dismissed') });
},
});

Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { Field } from '@rocket.chat/fuselage';
import type { ServerMethods } from '@rocket.chat/ui-contexts';
import type { ServerMethods, TranslationKey } from '@rocket.chat/ui-contexts';
import type { ComponentMeta, ComponentStory } from '@storybook/react';
import React from 'react';

import type keys from '../../../../../packages/rocketchat-i18n/i18n/en.i18n.json';
import ActionSettingInput from './ActionSettingInput';

export default {
Expand All @@ -17,22 +16,22 @@ const Template: ComponentStory<typeof ActionSettingInput> = (args) => <ActionSet
export const Default = Template.bind({});
Default.args = {
_id: 'setting_id',
actionText: 'Action text' as keyof typeof keys,
actionText: 'Action text' as TranslationKey,
value: 'methodName' as keyof ServerMethods,
};

export const Disabled = Template.bind({});
Disabled.args = {
_id: 'setting_id',
actionText: 'Action text' as keyof typeof keys,
actionText: 'Action text' as TranslationKey,
value: 'methodName' as keyof ServerMethods,
disabled: true,
};

export const WithinChangedSection = Template.bind({});
WithinChangedSection.args = {
_id: 'setting_id',
actionText: 'Action text' as keyof typeof keys,
actionText: 'Action text' as TranslationKey,
value: 'methodName' as keyof ServerMethods,
sectionChanged: true,
};
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Field } from '@rocket.chat/fuselage';
import type { TranslationKey } from '@rocket.chat/ui-contexts';
import type { ComponentMeta, ComponentStory } from '@storybook/react';
import React from 'react';

import type keys from '../../../../../packages/rocketchat-i18n/i18n/en.i18n.json';
import type { valuesOption } from './MultiSelectSettingInput';
import MultiSelectSettingInput from './MultiSelectSettingInput';

Expand All @@ -20,9 +20,9 @@ export default {
const Template: ComponentStory<typeof MultiSelectSettingInput> = (args) => <MultiSelectSettingInput {...args} />;

const options: valuesOption[] = [
{ key: '1', i18nLabel: '1' as keyof typeof keys },
{ key: '2', i18nLabel: '2' as keyof typeof keys },
{ key: '3', i18nLabel: '3' as keyof typeof keys },
{ key: '1', i18nLabel: '1' as TranslationKey },
{ key: '2', i18nLabel: '2' as TranslationKey },
{ key: '3', i18nLabel: '3' as TranslationKey },
];

export const Default = Template.bind({});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Field } from '@rocket.chat/fuselage';
import type { TranslationKey } from '@rocket.chat/ui-contexts';
import type { ComponentMeta, ComponentStory } from '@storybook/react';
import React from 'react';

import type keys from '../../../../../packages/rocketchat-i18n/i18n/en.i18n.json';
import SelectSettingInput from './SelectSettingInput';

export default {
Expand All @@ -24,9 +24,9 @@ Default.args = {
label: 'Label',
placeholder: 'Placeholder',
values: [
{ key: '1', i18nLabel: '1' as keyof typeof keys },
{ key: '2', i18nLabel: '2' as keyof typeof keys },
{ key: '3', i18nLabel: '3' as keyof typeof keys },
{ key: '1', i18nLabel: '1' as TranslationKey },
{ key: '2', i18nLabel: '2' as TranslationKey },
{ key: '3', i18nLabel: '3' as TranslationKey },
],
};

Expand All @@ -36,9 +36,9 @@ Disabled.args = {
label: 'Label',
placeholder: 'Placeholder',
values: [
{ key: '1', i18nLabel: '1' as keyof typeof keys },
{ key: '2', i18nLabel: '2' as keyof typeof keys },
{ key: '3', i18nLabel: '3' as keyof typeof keys },
{ key: '1', i18nLabel: '1' as TranslationKey },
{ key: '2', i18nLabel: '2' as TranslationKey },
{ key: '3', i18nLabel: '3' as TranslationKey },
],
disabled: true,
};
Expand All @@ -50,9 +50,9 @@ WithValue.args = {
placeholder: 'Placeholder',
value: '2',
values: [
{ key: '1', i18nLabel: '1' as keyof typeof keys },
{ key: '2', i18nLabel: '2' as keyof typeof keys },
{ key: '3', i18nLabel: '3' as keyof typeof keys },
{ key: '1', i18nLabel: '1' as TranslationKey },
{ key: '2', i18nLabel: '2' as TranslationKey },
{ key: '3', i18nLabel: '3' as TranslationKey },
],
};

Expand All @@ -62,9 +62,9 @@ WithResetButton.args = {
label: 'Label',
placeholder: 'Placeholder',
values: [
{ key: '1', i18nLabel: '1' as keyof typeof keys },
{ key: '2', i18nLabel: '2' as keyof typeof keys },
{ key: '3', i18nLabel: '3' as keyof typeof keys },
{ key: '1', i18nLabel: '1' as TranslationKey },
{ key: '2', i18nLabel: '2' as TranslationKey },
{ key: '3', i18nLabel: '3' as TranslationKey },
],
hasResetButton: true,
};
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,9 @@ const EnabledAppsCount = ({
}): ReactElement | null => {
const t = useTranslation();

const privateAppsCountText: string = t('Private_Apps_Count_Enabled', { count: enabled });
const marketplaceAppsCountText: string = t('Apps_Count_Enabled', { count: enabled });

return (
<GenericResourceUsage
title={context === 'private' ? privateAppsCountText : marketplaceAppsCountText}
title={context === 'private' ? t('Private_Apps_Count_Enabled', { count: enabled }) : t('Apps_Count_Enabled', { count: enabled })}
value={enabled}
max={limit}
percentage={percentage}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ const VideoConfListItem = ({
</Avatar.Stack>
<Box mis={4}>
{joinedUsers.length > VIDEOCONF_STACK_MAX_USERS
? t('__usersCount__member_joined', { usersCount: joinedUsers.length - VIDEOCONF_STACK_MAX_USERS })
? t('__usersCount__member_joined', { count: joinedUsers.length - VIDEOCONF_STACK_MAX_USERS })
: t('joined')}
</Box>
</Box>
Expand Down
29 changes: 19 additions & 10 deletions apps/meteor/packages/rocketchat-i18n/i18n/ar.i18n.json
Original file line number Diff line number Diff line change
Expand Up @@ -706,9 +706,12 @@
"Call": "مكالمة",
"Calling": "يتم الآن الاتصال",
"Call_Center": "مركز الاتصال",
"Calls_in_queue": "{{calls}} من المكالمات الانتظار",
"Calls_in_queue_plural": "{{calls}} من المكالمات الانتظار",
"Calls_in_queue_empty": "قائمة الانتظار فارغة",
"Calls_in_queue_zero": "قائمة الانتظار فارغة",
"Calls_in_queue_one": "{{count}} من المكالمات الانتظار",
"Calls_in_queue_two": "{{count}} من المكالمات الانتظار",
"Calls_in_queue_few": "{{count}} من المكالمات الانتظار",
"Calls_in_queue_many": "{{count}} من المكالمات الانتظار",
"Calls_in_queue_other": "{{count}} من المكالمات الانتظار",
"Call_declined": "تم رفض المكالمة!",
"Call_Information": "معلومات المكالمة",
"Call_provider": "مزود المكالمة",
Expand Down Expand Up @@ -2847,8 +2850,12 @@
"Message_Characther_Limit": "حد أحرف الرسالة",
"Message_Code_highlight": "رمز تمييز قائمة اللغات",
"Message_Code_highlight_Description": "قائمة اللغات المفصولة بفواصل (كل اللغات المدعومة على [highlight.js](https://github.com/highlightjs/highlight.js/tree/11.6.0#supported-languages)) التي سيتم استخدامها لتمييز الكتل البرمجية للتعليمات البرمجية",
"message_counter": "{{counter}} رسالة",
"message_counter_plural": "{{counter}} رسائل",
"message_counter_zero": "{{count}} رسائل",
"message_counter_one": "{{count}} رسالة",
"message_counter_two": "{{count}} رسائل",
"message_counter_few": "{{count}} رسائل",
"message_counter_many": "{{count}} رسائل",
"message_counter_other": "{{count}} رسائل",
"Message_DateFormat": "تنسيق التاريخ",
"Message_DateFormat_Description": "انظر أيضًا: [Moment.js](http://momentjs.com/docs/#/displaying/format/)",
"Message_deleting_blocked": "لا يمكن حذف هذه الرسالة بعد الآن",
Expand Down Expand Up @@ -2941,8 +2948,12 @@
"meteor_status_connecting": "يتم الاتصال الآن...",
"meteor_status_failed": "فشل الاتصال بالخادم",
"meteor_status_offline": "وضع عدم الاتصال.",
"meteor_status_reconnect_in": "المحاولة مرة أخرى خلال ثانية واحدة...",
"meteor_status_reconnect_in_plural": "المحاولة مرة أخرى خلال {{count}} من الثواني...",
"meteor_status_reconnect_in_zero": "المحاولة مرة أخرى خلال {{count}} من الثواني...",
"meteor_status_reconnect_in_one": "المحاولة مرة أخرى خلال ثانية واحدة...",
"meteor_status_reconnect_in_two": "المحاولة مرة أخرى خلال {{count}} من الثواني...",
"meteor_status_reconnect_in_few": "المحاولة مرة أخرى خلال {{count}} من الثواني...",
"meteor_status_reconnect_in_many": "المحاولة مرة أخرى خلال {{count}} من الثواني...",
"meteor_status_reconnect_in_other": "المحاولة مرة أخرى خلال {{count}} من الثواني...",
"meteor_status_try_now_offline": "الاتصال مرة أخرى",
"meteor_status_try_now_waiting": "المحاولة الآن",
"meteor_status_waiting": "في انتظار اتصال الخادم،",
Expand Down Expand Up @@ -3494,8 +3505,6 @@
"Replied_on": "تم الرد على",
"Replies": "الردود",
"Reply": "رد",
"reply_counter": "{{counter}} رد",
"reply_counter_plural": "{{counter}} ردود",
"Reply_in_direct_message": "الرد في رسالة مباشرة",
"Reply_in_thread": "الرد في موضوع",
"Reply_via_Email": "الرد عبر البريد الإلكتروني",
Expand Down Expand Up @@ -4886,4 +4895,4 @@
"Enterprise": "مؤسسة",
"UpgradeToGetMore_engagement-dashboard_Title": "التحليلات",
"UpgradeToGetMore_auditing_Title": "تدقيق الرسائل"
}
}
Loading
Loading