mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-14 05:14:54 +00:00
refactor(i18n): i18n utils tools (#7251)
This commit is contained in:
@@ -1,112 +0,0 @@
|
||||
import { getI18n } from '@affine/i18n';
|
||||
import { describe, expect, test } from 'vitest';
|
||||
|
||||
import type { CalendarTranslation } from '../intl-formatter';
|
||||
import { timestampToCalendarDate } from '../intl-formatter';
|
||||
|
||||
const translation: CalendarTranslation = {
|
||||
yesterday: () => 'Yesterday',
|
||||
today: () => 'Today',
|
||||
tomorrow: () => 'Tomorrow',
|
||||
nextWeek: () => 'Next Week',
|
||||
};
|
||||
|
||||
const ONE_DAY = 24 * 60 * 60 * 1000;
|
||||
|
||||
describe('intl calendar date formatter', () => {
|
||||
const week = new Intl.DateTimeFormat(getI18n()?.language, {
|
||||
weekday: 'long',
|
||||
});
|
||||
|
||||
test('someday before last week', async () => {
|
||||
const timestamp = '2000-01-01 10:00';
|
||||
expect(timestampToCalendarDate(timestamp, translation)).toBe('Jan 1, 2000');
|
||||
});
|
||||
|
||||
test('someday in last week', async () => {
|
||||
const timestamp = Date.now() - 6 * ONE_DAY;
|
||||
expect(timestampToCalendarDate(timestamp, translation)).toBe(
|
||||
week.format(timestamp)
|
||||
);
|
||||
});
|
||||
|
||||
test('someday is yesterday', async () => {
|
||||
const timestamp = Date.now() - ONE_DAY;
|
||||
expect(timestampToCalendarDate(timestamp, translation)).toBe('Yesterday');
|
||||
});
|
||||
|
||||
test('someday is today', async () => {
|
||||
const timestamp = Date.now();
|
||||
expect(timestampToCalendarDate(timestamp, translation)).toBe('Today');
|
||||
});
|
||||
|
||||
test('someday is tomorrow', async () => {
|
||||
const timestamp = Date.now() + ONE_DAY;
|
||||
expect(timestampToCalendarDate(timestamp, translation)).toBe('Tomorrow');
|
||||
});
|
||||
|
||||
test('someday in next week', async () => {
|
||||
const timestamp = Date.now() + 6 * ONE_DAY;
|
||||
expect(timestampToCalendarDate(timestamp, translation)).toBe(
|
||||
`Next Week ${week.format(timestamp)}`
|
||||
);
|
||||
});
|
||||
|
||||
test('someday after next week', async () => {
|
||||
const timestamp = '3000-01-01 10:00';
|
||||
expect(timestampToCalendarDate(timestamp, translation)).toBe('Jan 1, 3000');
|
||||
});
|
||||
});
|
||||
|
||||
describe('intl calendar date formatter with specific reference time', () => {
|
||||
const referenceTime = '2024-05-10 14:00';
|
||||
|
||||
test('someday before last week', async () => {
|
||||
const timestamp = '2024-04-27 10:00';
|
||||
expect(timestampToCalendarDate(timestamp, translation, referenceTime)).toBe(
|
||||
'Apr 27, 2024'
|
||||
);
|
||||
});
|
||||
|
||||
test('someday in last week', async () => {
|
||||
const timestamp = '2024-05-6 10:00';
|
||||
expect(timestampToCalendarDate(timestamp, translation, referenceTime)).toBe(
|
||||
'Monday'
|
||||
);
|
||||
});
|
||||
|
||||
test('someday is yesterday', async () => {
|
||||
const timestamp = '2024-05-9 10:00';
|
||||
expect(timestampToCalendarDate(timestamp, translation, referenceTime)).toBe(
|
||||
'Yesterday'
|
||||
);
|
||||
});
|
||||
|
||||
test('someday is today', async () => {
|
||||
const timestamp = '2024-05-10 10:00';
|
||||
expect(timestampToCalendarDate(timestamp, translation, referenceTime)).toBe(
|
||||
'Today'
|
||||
);
|
||||
});
|
||||
|
||||
test('someday is tomorrow', async () => {
|
||||
const timestamp = '2024-05-11 10:00';
|
||||
expect(timestampToCalendarDate(timestamp, translation, referenceTime)).toBe(
|
||||
'Tomorrow'
|
||||
);
|
||||
});
|
||||
|
||||
test('someday in next week', async () => {
|
||||
const timestamp = '2024-05-15 10:00';
|
||||
expect(timestampToCalendarDate(timestamp, translation, referenceTime)).toBe(
|
||||
'Next Week Wednesday'
|
||||
);
|
||||
});
|
||||
|
||||
test('someday after next week', async () => {
|
||||
const timestamp = '2024-05-30 10:00';
|
||||
expect(timestampToCalendarDate(timestamp, translation, referenceTime)).toBe(
|
||||
'May 30, 2024'
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -1,6 +1,5 @@
|
||||
export * from './create-emotion-cache';
|
||||
export * from './fractional-indexing';
|
||||
export * from './intl-formatter';
|
||||
export * from './mixpanel';
|
||||
export * from './popup';
|
||||
export * from './string2color';
|
||||
|
||||
@@ -1,105 +0,0 @@
|
||||
import { getI18n } from '@affine/i18n';
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
function createTimeFormatter() {
|
||||
return new Intl.DateTimeFormat(getI18n()?.language, {
|
||||
timeStyle: 'short',
|
||||
});
|
||||
}
|
||||
|
||||
function createDateTimeFormatter() {
|
||||
return new Intl.DateTimeFormat(getI18n()?.language, {
|
||||
timeStyle: 'medium',
|
||||
dateStyle: 'medium',
|
||||
});
|
||||
}
|
||||
|
||||
function createDateFormatter() {
|
||||
return new Intl.DateTimeFormat(getI18n()?.language, {
|
||||
year: 'numeric',
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
});
|
||||
}
|
||||
|
||||
function createWeekFormatter() {
|
||||
return new Intl.DateTimeFormat(getI18n()?.language, {
|
||||
weekday: 'long',
|
||||
});
|
||||
}
|
||||
|
||||
export const timestampToLocalTime = (ts: string | number) => {
|
||||
const formatter = createTimeFormatter();
|
||||
return formatter.format(dayjs(ts).toDate());
|
||||
};
|
||||
|
||||
export const timestampToLocalDate = (ts: string | number) => {
|
||||
const formatter = createDateFormatter();
|
||||
return formatter.format(dayjs(ts).toDate());
|
||||
};
|
||||
|
||||
export const timestampToLocalDateTime = (ts: string | number) => {
|
||||
const formatter = createDateTimeFormatter();
|
||||
return formatter.format(dayjs(ts).toDate());
|
||||
};
|
||||
|
||||
export const createRelativeTimeFormatter = () => {
|
||||
return new Intl.RelativeTimeFormat(getI18n()?.language, {
|
||||
style: 'narrow',
|
||||
});
|
||||
};
|
||||
|
||||
export interface CalendarTranslation {
|
||||
yesterday: () => string;
|
||||
today: () => string;
|
||||
tomorrow: () => string;
|
||||
nextWeek: () => string;
|
||||
}
|
||||
|
||||
export const timestampToCalendarDate = (
|
||||
ts: string | number,
|
||||
translation: CalendarTranslation,
|
||||
referenceTime?: string | number
|
||||
) => {
|
||||
const startOfDay = dayjs(referenceTime).startOf('d');
|
||||
const diff = dayjs(ts).diff(startOfDay, 'd', true);
|
||||
const sameElse = timestampToLocalDate(ts);
|
||||
|
||||
const formatter = createWeekFormatter();
|
||||
const week = formatter.format(dayjs(ts).toDate());
|
||||
|
||||
return diff < -6
|
||||
? sameElse
|
||||
: diff < -1
|
||||
? week
|
||||
: diff < 0
|
||||
? translation.yesterday()
|
||||
: diff < 1
|
||||
? translation.today()
|
||||
: diff < 2
|
||||
? translation.tomorrow()
|
||||
: diff < 7
|
||||
? `${translation.nextWeek()} ${week}`
|
||||
: sameElse;
|
||||
};
|
||||
|
||||
// TODO: refactor this to @affine/i18n
|
||||
export const timestampToHumanTime = (ts: number) => {
|
||||
const diff = Math.abs(dayjs(ts).diff(dayjs()));
|
||||
|
||||
if (diff < 1000 * 60) {
|
||||
return getI18n().t('com.affine.just-now');
|
||||
} else if (diff < 1000 * 60 * 60) {
|
||||
return createRelativeTimeFormatter().format(
|
||||
-Math.floor(diff / 1000 / 60),
|
||||
'minutes'
|
||||
);
|
||||
} else if (diff < 1000 * 60 * 60 * 24) {
|
||||
return createRelativeTimeFormatter().format(
|
||||
-Math.floor(diff / 1000 / 60 / 60),
|
||||
'hours'
|
||||
);
|
||||
} else {
|
||||
return timestampToLocalDate(ts);
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user