From f18363ee3605a22c269a64234c1e1bdc17302c07 Mon Sep 17 00:00:00 2001 From: dangered wolf Date: Tue, 30 Apr 2024 01:27:53 -0400 Subject: [PATCH] Use intl for formats --- src/embed/status.ts | 3 ++- src/render/instantview.ts | 49 +++++++++++++++++++++------------------ src/types/types.d.ts | 1 + 3 files changed, 30 insertions(+), 23 deletions(-) diff --git a/src/embed/status.ts b/src/embed/status.ts index 3a6b921..e8bcc55 100644 --- a/src/embed/status.ts +++ b/src/embed/status.ts @@ -209,7 +209,8 @@ export const handleStatus = async ( status: status, thread: thread, text: newText, - flags: flags + flags: flags, + targetLanguage: language ?? status.lang ?? 'en' }); headers.push(...instructions.addHeaders); if (instructions.authorText) { diff --git a/src/render/instantview.ts b/src/render/instantview.ts index 8224a9c..74aecf8 100644 --- a/src/render/instantview.ts +++ b/src/render/instantview.ts @@ -56,11 +56,16 @@ const generateStatusMedia = (status: APIStatus): string => { // return `${hh}:${min} - ${yyyy}/${mm}/${dd}`; // } -const formatDate = (date: Date): string => { - const yyyy = date.getFullYear(); - const mm = String(date.getMonth() + 1).padStart(2, '0'); // Months are 0-indexed - const dd = String(date.getDate()).padStart(2, '0'); - return `${yyyy}/${mm}/${dd}`; +const formatDate = (date: Date, language: string): string => { + if (language.startsWith('en')) { + language = 'en-CA'; // Use ISO dates for English to avoid problems with mm/dd vs. dd/mm + } + const formatter = new Intl.DateTimeFormat(language, { + year: 'numeric', + month: '2-digit', + day: '2-digit' + }); + return formatter.format(date); }; const htmlifyLinks = (input: string): string => { @@ -108,15 +113,14 @@ function getTranslatedText(status: APITwitterStatus, isQuote = false): string | const notApplicableComment = ''; -// 1100 -> 1.1K, 1100000 -> 1.1M -const truncateSocialCount = (count: number): string => { - if (count >= 1000000) { - return `${(count / 1000000).toFixed(1)}M`; - } else if (count >= 1000) { - return `${(count / 1000).toFixed(1)}K`; - } else { - return String(count); - } +const truncateSocialCount = (count: number, locale = 'en-US') => { + const formatter = new Intl.NumberFormat(locale, { + notation: "compact", + compactDisplay: "short", + maximumFractionDigits: 1 + }); + + return formatter.format(count); }; const generateInlineAuthorHeader = ( @@ -166,7 +170,7 @@ const wrapForeignLinks = (url: string) => { : url; }; -const generateStatusFooter = (status: APIStatus, isQuote = false, author: APIUser): string => { +const generateStatusFooter = (status: APIStatus, isQuote = false, author: APIUser, language: string): string => { let description = author.description; description = htmlifyLinks(description); description = htmlifyHashtags(description); @@ -200,10 +204,10 @@ const generateStatusFooter = (status: APIStatus, isQuote = false, author: APIUse website: author.website ? `🔗 ${author.website.display_url}` : '', - joined: author.joined ? `📆 ${formatDate(new Date(author.joined))}` : '', - following: truncateSocialCount(author.following), - followers: truncateSocialCount(author.followers), - statuses: truncateSocialCount(author.statuses) + joined: author.joined ? `📆 ${formatDate(new Date(author.joined), language)}` : '', + following: truncateSocialCount(author.following, language), + followers: truncateSocialCount(author.followers, language), + statuses: truncateSocialCount(author.statuses, language) }) }); }; @@ -270,6 +274,7 @@ const generateCommunityNote = (status: APITwitterStatus): string => { const generateStatus = ( status: APIStatus, author: APIUser, + language: string, isQuote = false, authorActionType: AuthorActionType | null ): string => { @@ -295,7 +300,7 @@ const generateStatus = ( ${status.poll ? generatePoll(status.poll, status.lang ?? 'en') : notApplicableComment} - ${!isQuote && status.quote ? generateStatus(status.quote, author, true, null) : notApplicableComment} + ${!isQuote && status.quote ? generateStatus(status.quote, author, language, true, null) : notApplicableComment}
${!isQuote ? `${i18next.t('ivViewOriginal')}` : notApplicableComment} `.format({ quoteHeader: isQuote @@ -391,10 +396,10 @@ export const renderInstantView = (properties: RenderProperties): ResponseInstruc previousThreadPieceAuthor = status.author?.id; - return generateStatus(status, status.author ?? thread?.author, false, authorAction); + return generateStatus(status, status.author ?? thread?.author, properties?.targetLanguage ?? 'en', false, authorAction,); }) .join('')} - ${generateStatusFooter(status, false, thread?.author ?? status.author)} + ${generateStatusFooter(status, false, thread?.author ?? status.author, properties?.targetLanguage ?? 'en')}
${`${i18next.t('ivViewOriginal')}`} `; diff --git a/src/types/types.d.ts b/src/types/types.d.ts index 3b5b947..ae8964e 100644 --- a/src/types/types.d.ts +++ b/src/types/types.d.ts @@ -38,6 +38,7 @@ interface RenderProperties { userAgent?: string; text?: string; flags?: InputFlags; + targetLanguage?: string; } interface TweetAPIResponse {