Bluesky app fork with some witchin' additions 💫

Dynamically load `date-fns` locale data (#9535)

authored by samuel.fm and committed by

GitHub 41b37423 512ce3d5

+315 -214
+7 -93
src/components/hooks/dates.ts
··· 7 7 * {@link https://github.com/date-fns/date-fns/blob/main/docs/i18n.md} 8 8 */ 9 9 10 - import React from 'react' 11 - import {formatDistance, type Locale} from 'date-fns' 12 - import { 13 - ca, 14 - cy, 15 - da, 16 - de, 17 - el, 18 - enGB, 19 - eo, 20 - es, 21 - eu, 22 - fi, 23 - fr, 24 - fy, 25 - gd, 26 - gl, 27 - hi, 28 - hu, 29 - id, 30 - it, 31 - ja, 32 - km, 33 - ko, 34 - nl, 35 - pl, 36 - pt, 37 - ptBR, 38 - ro, 39 - ru, 40 - sv, 41 - th, 42 - tr, 43 - uk, 44 - vi, 45 - zhCN, 46 - zhHK, 47 - zhTW, 48 - } from 'date-fns/locale' 10 + import {useCallback} from 'react' 11 + import {formatDistance} from 'date-fns' 49 12 50 - import {type AppLanguage} from '#/locale/languages' 51 - import {useLanguagePrefs} from '#/state/preferences' 52 - 53 - /** 54 - * {@link AppLanguage} 55 - */ 56 - const locales: Record<AppLanguage, Locale | undefined> = { 57 - en: undefined, 58 - an: undefined, 59 - ast: undefined, 60 - ca, 61 - cy, 62 - da, 63 - de, 64 - el, 65 - ['en-GB']: enGB, 66 - eo, 67 - es, 68 - eu, 69 - fi, 70 - fr, 71 - fy, 72 - ga: undefined, 73 - gd, 74 - gl, 75 - hi, 76 - hu, 77 - ia: undefined, 78 - id, 79 - it, 80 - ja, 81 - km, 82 - ko, 83 - ne: undefined, 84 - nl, 85 - pl, 86 - ['pt-PT']: pt, 87 - ['pt-BR']: ptBR, 88 - ro, 89 - ru, 90 - sv, 91 - th, 92 - tr, 93 - uk, 94 - vi, 95 - ['zh-Hans-CN']: zhCN, 96 - ['zh-Hant-HK']: zhHK, 97 - ['zh-Hant-TW']: zhTW, 98 - } 13 + import {useDateLocale} from '#/locale/i18nProvider' 99 14 100 15 /** 101 16 * Returns a localized `formatDistance` function. 102 17 * {@link formatDistance} 103 18 */ 104 19 export function useFormatDistance() { 105 - const {appLanguage} = useLanguagePrefs() 106 - return React.useCallback<typeof formatDistance>( 20 + const locale = useDateLocale() 21 + return useCallback<typeof formatDistance>( 107 22 (date, baseDate, options) => { 108 - const locale = locales[appLanguage as AppLanguage] 109 - return formatDistance(date, baseDate, {...options, locale: locale}) 23 + return formatDistance(date, baseDate, {...options, locale}) 110 24 }, 111 - [appLanguage], 25 + [locale], 112 26 ) 113 27 }
+124 -80
src/locale/i18n.ts
··· 8 8 import '@formatjs/intl-numberformat/locale-data/en' 9 9 import '@formatjs/intl-displaynames/locale-data/en' 10 10 11 - import {useEffect} from 'react' 11 + import {useEffect, useState} from 'react' 12 12 import {i18n} from '@lingui/core' 13 + import defaultLocale from 'date-fns/locale/en-US' 13 14 14 15 import {sanitizeAppLanguageSetting} from '#/locale/helpers' 15 16 import {AppLanguage} from '#/locale/languages' ··· 63 64 switch (locale) { 64 65 case AppLanguage.an: { 65 66 i18n.loadAndActivate({locale, messages: messagesAn}) 66 - await Promise.all([ 67 + const [{default: dateLocale}] = await Promise.all([ 68 + import('date-fns/locale/es'), 67 69 import('@formatjs/intl-pluralrules/locale-data/an'), 68 70 import('@formatjs/intl-numberformat/locale-data/es'), 69 71 import('@formatjs/intl-displaynames/locale-data/es'), 70 72 ]) 71 - break 73 + return dateLocale 72 74 } 73 75 case AppLanguage.ast: { 74 76 i18n.loadAndActivate({locale, messages: messagesAst}) 75 - await Promise.all([ 77 + const [{default: dateLocale}] = await Promise.all([ 78 + import('date-fns/locale/es'), 76 79 import('@formatjs/intl-pluralrules/locale-data/ast'), 77 80 import('@formatjs/intl-numberformat/locale-data/ast'), 78 81 import('@formatjs/intl-displaynames/locale-data/ast'), 79 82 ]) 80 - break 83 + return dateLocale 81 84 } 82 85 case AppLanguage.ca: { 83 86 i18n.loadAndActivate({locale, messages: messagesCa}) 84 - await Promise.all([ 87 + const [{default: dateLocale}] = await Promise.all([ 88 + import('date-fns/locale/ca'), 85 89 import('@formatjs/intl-pluralrules/locale-data/ca'), 86 90 import('@formatjs/intl-numberformat/locale-data/ca'), 87 91 import('@formatjs/intl-displaynames/locale-data/ca'), 88 92 ]) 89 - break 93 + return dateLocale 90 94 } 91 95 case AppLanguage.cy: { 92 96 i18n.loadAndActivate({locale, messages: messagesCy}) 93 - await Promise.all([ 97 + const [{default: dateLocale}] = await Promise.all([ 98 + import('date-fns/locale/cy'), 94 99 import('@formatjs/intl-pluralrules/locale-data/cy'), 95 100 import('@formatjs/intl-numberformat/locale-data/cy'), 96 101 import('@formatjs/intl-displaynames/locale-data/cy'), 97 102 ]) 98 - break 103 + return dateLocale 99 104 } 100 105 case AppLanguage.da: { 101 106 i18n.loadAndActivate({locale, messages: messagesDa}) 102 - await Promise.all([ 107 + const [{default: dateLocale}] = await Promise.all([ 108 + import('date-fns/locale/da'), 103 109 import('@formatjs/intl-pluralrules/locale-data/da'), 104 110 import('@formatjs/intl-numberformat/locale-data/da'), 105 111 import('@formatjs/intl-displaynames/locale-data/da'), 106 112 ]) 107 - break 113 + return dateLocale 108 114 } 109 115 case AppLanguage.de: { 110 116 i18n.loadAndActivate({locale, messages: messagesDe}) 111 - await Promise.all([ 117 + const [{default: dateLocale}] = await Promise.all([ 118 + import('date-fns/locale/de'), 112 119 import('@formatjs/intl-pluralrules/locale-data/de'), 113 120 import('@formatjs/intl-numberformat/locale-data/de'), 114 121 import('@formatjs/intl-displaynames/locale-data/de'), 115 122 ]) 116 - break 123 + return dateLocale 117 124 } 118 125 case AppLanguage.el: { 119 126 i18n.loadAndActivate({locale, messages: messagesEl}) 120 - await Promise.all([ 127 + const [{default: dateLocale}] = await Promise.all([ 128 + import('date-fns/locale/el'), 121 129 import('@formatjs/intl-pluralrules/locale-data/el'), 122 130 import('@formatjs/intl-numberformat/locale-data/el'), 123 131 import('@formatjs/intl-displaynames/locale-data/el'), 124 132 ]) 125 - break 133 + return dateLocale 126 134 } 127 135 case AppLanguage.en_GB: { 128 136 i18n.loadAndActivate({locale, messages: messagesEn_GB}) 129 - await Promise.all([ 137 + const [{default: dateLocale}] = await Promise.all([ 138 + import('date-fns/locale/en-GB'), 130 139 import('@formatjs/intl-pluralrules/locale-data/en'), 131 140 import('@formatjs/intl-numberformat/locale-data/en-GB'), 132 141 import('@formatjs/intl-displaynames/locale-data/en-GB'), 133 142 ]) 134 - break 143 + return dateLocale 135 144 } 136 145 case AppLanguage.eo: { 137 146 i18n.loadAndActivate({locale, messages: messagesEo}) 138 - await Promise.all([ 147 + const [{default: dateLocale}] = await Promise.all([ 148 + import('date-fns/locale/eo'), 139 149 import('@formatjs/intl-pluralrules/locale-data/eo'), 140 150 import('@formatjs/intl-numberformat/locale-data/eo'), 141 151 // borked, see https://github.com/bluesky-social/social-app/pull/9574 142 152 // import('@formatjs/intl-displaynames/locale-data/eo'), 143 153 ]) 144 - break 154 + return dateLocale 145 155 } 146 156 case AppLanguage.es: { 147 157 i18n.loadAndActivate({locale, messages: messagesEs}) 148 - await Promise.all([ 158 + const [{default: dateLocale}] = await Promise.all([ 159 + import('date-fns/locale/es'), 149 160 import('@formatjs/intl-pluralrules/locale-data/es'), 150 161 import('@formatjs/intl-numberformat/locale-data/es'), 151 162 import('@formatjs/intl-displaynames/locale-data/es'), 152 163 ]) 153 - break 164 + return dateLocale 154 165 } 155 166 case AppLanguage.eu: { 156 167 i18n.loadAndActivate({locale, messages: messagesEu}) 157 - await Promise.all([ 168 + const [{default: dateLocale}] = await Promise.all([ 169 + import('date-fns/locale/eu'), 158 170 import('@formatjs/intl-pluralrules/locale-data/eu'), 159 171 import('@formatjs/intl-numberformat/locale-data/eu'), 160 172 import('@formatjs/intl-displaynames/locale-data/eu'), 161 173 ]) 162 - break 174 + return dateLocale 163 175 } 164 176 case AppLanguage.fi: { 165 177 i18n.loadAndActivate({locale, messages: messagesFi}) 166 - await Promise.all([ 178 + const [{default: dateLocale}] = await Promise.all([ 179 + import('date-fns/locale/fi'), 167 180 import('@formatjs/intl-pluralrules/locale-data/fi'), 168 181 import('@formatjs/intl-numberformat/locale-data/fi'), 169 182 import('@formatjs/intl-displaynames/locale-data/fi'), 170 183 ]) 171 - break 184 + return dateLocale 172 185 } 173 186 case AppLanguage.fr: { 174 187 i18n.loadAndActivate({locale, messages: messagesFr}) 175 - await Promise.all([ 188 + const [{default: dateLocale}] = await Promise.all([ 189 + import('date-fns/locale/fr'), 176 190 import('@formatjs/intl-pluralrules/locale-data/fr'), 177 191 import('@formatjs/intl-numberformat/locale-data/fr'), 178 192 import('@formatjs/intl-displaynames/locale-data/fr'), 179 193 ]) 180 - break 194 + return dateLocale 181 195 } 182 196 case AppLanguage.fy: { 183 197 i18n.loadAndActivate({locale, messages: messagesFy}) 184 - await Promise.all([ 198 + const [{default: dateLocale}] = await Promise.all([ 199 + import('date-fns/locale/fy'), 185 200 import('@formatjs/intl-pluralrules/locale-data/fy'), 186 201 import('@formatjs/intl-numberformat/locale-data/fy'), 187 202 import('@formatjs/intl-displaynames/locale-data/fy'), 188 203 ]) 189 - break 204 + return dateLocale 190 205 } 191 206 case AppLanguage.ga: { 192 207 i18n.loadAndActivate({locale, messages: messagesGa}) ··· 195 210 import('@formatjs/intl-numberformat/locale-data/ga'), 196 211 import('@formatjs/intl-displaynames/locale-data/ga'), 197 212 ]) 198 - break 213 + return undefined 199 214 } 200 215 case AppLanguage.gd: { 201 216 i18n.loadAndActivate({locale, messages: messagesGd}) 202 - await Promise.all([ 217 + const [{default: dateLocale}] = await Promise.all([ 218 + import('date-fns/locale/gd'), 203 219 import('@formatjs/intl-pluralrules/locale-data/gd'), 204 220 import('@formatjs/intl-numberformat/locale-data/gd'), 205 221 import('@formatjs/intl-displaynames/locale-data/gd'), 206 222 ]) 207 - break 223 + return dateLocale 208 224 } 209 225 case AppLanguage.gl: { 210 226 i18n.loadAndActivate({locale, messages: messagesGl}) 211 - await Promise.all([ 227 + const [{default: dateLocale}] = await Promise.all([ 228 + import('date-fns/locale/gl'), 212 229 import('@formatjs/intl-pluralrules/locale-data/gl'), 213 230 import('@formatjs/intl-numberformat/locale-data/gl'), 214 231 import('@formatjs/intl-displaynames/locale-data/gl'), 215 232 ]) 216 - break 233 + return dateLocale 217 234 } 218 235 case AppLanguage.hi: { 219 236 i18n.loadAndActivate({locale, messages: messagesHi}) 220 - await Promise.all([ 237 + const [{default: dateLocale}] = await Promise.all([ 238 + import('date-fns/locale/hi'), 221 239 import('@formatjs/intl-pluralrules/locale-data/hi'), 222 240 import('@formatjs/intl-numberformat/locale-data/hi'), 223 241 import('@formatjs/intl-displaynames/locale-data/hi'), 224 242 ]) 225 - break 243 + return dateLocale 226 244 } 227 245 case AppLanguage.hu: { 228 246 i18n.loadAndActivate({locale, messages: messagesHu}) 229 - await Promise.all([ 247 + const [{default: dateLocale}] = await Promise.all([ 248 + import('date-fns/locale/hu'), 230 249 import('@formatjs/intl-pluralrules/locale-data/hu'), 231 250 import('@formatjs/intl-numberformat/locale-data/hu'), 232 251 import('@formatjs/intl-displaynames/locale-data/hu'), 233 252 ]) 234 - break 253 + return dateLocale 235 254 } 236 255 case AppLanguage.ia: { 237 256 i18n.loadAndActivate({locale, messages: messagesIa}) ··· 240 259 import('@formatjs/intl-numberformat/locale-data/ia'), 241 260 import('@formatjs/intl-displaynames/locale-data/ia'), 242 261 ]) 243 - break 262 + return undefined 244 263 } 245 264 case AppLanguage.id: { 246 265 i18n.loadAndActivate({locale, messages: messagesId}) 247 - await Promise.all([ 266 + const [{default: dateLocale}] = await Promise.all([ 267 + import('date-fns/locale/id'), 248 268 import('@formatjs/intl-pluralrules/locale-data/id'), 249 269 import('@formatjs/intl-numberformat/locale-data/id'), 250 270 import('@formatjs/intl-displaynames/locale-data/id'), 251 271 ]) 252 - break 272 + return dateLocale 253 273 } 254 274 case AppLanguage.it: { 255 275 i18n.loadAndActivate({locale, messages: messagesIt}) 256 - await Promise.all([ 276 + const [{default: dateLocale}] = await Promise.all([ 277 + import('date-fns/locale/it'), 257 278 import('@formatjs/intl-pluralrules/locale-data/it'), 258 279 import('@formatjs/intl-numberformat/locale-data/it'), 259 280 import('@formatjs/intl-displaynames/locale-data/it'), 260 281 ]) 261 - break 282 + return dateLocale 262 283 } 263 284 case AppLanguage.ja: { 264 285 i18n.loadAndActivate({locale, messages: messagesJa}) 265 - await Promise.all([ 286 + const [{default: dateLocale}] = await Promise.all([ 287 + import('date-fns/locale/ja'), 266 288 import('@formatjs/intl-pluralrules/locale-data/ja'), 267 289 import('@formatjs/intl-numberformat/locale-data/ja'), 268 290 import('@formatjs/intl-displaynames/locale-data/ja'), 269 291 ]) 270 - break 292 + return dateLocale 271 293 } 272 294 case AppLanguage.km: { 273 295 i18n.loadAndActivate({locale, messages: messagesKm}) 274 - await Promise.all([ 296 + const [{default: dateLocale}] = await Promise.all([ 297 + import('date-fns/locale/km'), 275 298 import('@formatjs/intl-pluralrules/locale-data/km'), 276 299 import('@formatjs/intl-numberformat/locale-data/km'), 277 300 import('@formatjs/intl-displaynames/locale-data/km'), 278 301 ]) 279 - break 302 + return dateLocale 280 303 } 281 304 case AppLanguage.ko: { 282 305 i18n.loadAndActivate({locale, messages: messagesKo}) 283 - await Promise.all([ 306 + const [{default: dateLocale}] = await Promise.all([ 307 + import('date-fns/locale/ko'), 284 308 import('@formatjs/intl-pluralrules/locale-data/ko'), 285 309 import('@formatjs/intl-numberformat/locale-data/ko'), 286 310 import('@formatjs/intl-displaynames/locale-data/ko'), 287 311 ]) 288 - break 312 + return dateLocale 289 313 } 290 314 case AppLanguage.ne: { 291 315 i18n.loadAndActivate({locale, messages: messagesNe}) ··· 294 318 import('@formatjs/intl-numberformat/locale-data/ne'), 295 319 import('@formatjs/intl-displaynames/locale-data/ne'), 296 320 ]) 297 - break 321 + return undefined 298 322 } 299 323 case AppLanguage.nl: { 300 324 i18n.loadAndActivate({locale, messages: messagesNl}) 301 - await Promise.all([ 325 + const [{default: dateLocale}] = await Promise.all([ 326 + import('date-fns/locale/nl'), 302 327 import('@formatjs/intl-pluralrules/locale-data/nl'), 303 328 import('@formatjs/intl-numberformat/locale-data/nl'), 304 329 import('@formatjs/intl-displaynames/locale-data/nl'), 305 330 ]) 306 - break 331 + return dateLocale 307 332 } 308 333 case AppLanguage.pl: { 309 334 i18n.loadAndActivate({locale, messages: messagesPl}) 310 - await Promise.all([ 335 + const [{default: dateLocale}] = await Promise.all([ 336 + import('date-fns/locale/pl'), 311 337 import('@formatjs/intl-pluralrules/locale-data/pl'), 312 338 import('@formatjs/intl-numberformat/locale-data/pl'), 313 339 import('@formatjs/intl-displaynames/locale-data/pl'), 314 340 ]) 315 - break 341 + return dateLocale 316 342 } 317 343 case AppLanguage.pt_BR: { 318 344 i18n.loadAndActivate({locale, messages: messagesPt_BR}) 319 - await Promise.all([ 345 + const [{default: dateLocale}] = await Promise.all([ 346 + import('date-fns/locale/pt-BR'), 320 347 import('@formatjs/intl-pluralrules/locale-data/pt'), 321 348 import('@formatjs/intl-numberformat/locale-data/pt'), 322 349 import('@formatjs/intl-displaynames/locale-data/pt'), 323 350 ]) 324 - break 351 + return dateLocale 325 352 } 326 353 case AppLanguage.pt_PT: { 327 354 i18n.loadAndActivate({locale, messages: messagesPt_PT}) 328 - await Promise.all([ 355 + const [{default: dateLocale}] = await Promise.all([ 356 + import('date-fns/locale/pt'), 329 357 import('@formatjs/intl-pluralrules/locale-data/pt-PT'), 330 358 import('@formatjs/intl-numberformat/locale-data/pt-PT'), 331 359 import('@formatjs/intl-displaynames/locale-data/pt-PT'), 332 360 ]) 333 - break 361 + return dateLocale 334 362 } 335 363 case AppLanguage.ro: { 336 364 i18n.loadAndActivate({locale, messages: messagesRo}) 337 - await Promise.all([ 365 + const [{default: dateLocale}] = await Promise.all([ 366 + import('date-fns/locale/ro'), 338 367 import('@formatjs/intl-pluralrules/locale-data/ro'), 339 368 import('@formatjs/intl-numberformat/locale-data/ro'), 340 369 import('@formatjs/intl-displaynames/locale-data/ro'), 341 370 ]) 342 - break 371 + return dateLocale 343 372 } 344 373 case AppLanguage.ru: { 345 374 i18n.loadAndActivate({locale, messages: messagesRu}) 346 - await Promise.all([ 375 + const [{default: dateLocale}] = await Promise.all([ 376 + import('date-fns/locale/ru'), 347 377 import('@formatjs/intl-pluralrules/locale-data/ru'), 348 378 import('@formatjs/intl-numberformat/locale-data/ru'), 349 379 import('@formatjs/intl-displaynames/locale-data/ru'), 350 380 ]) 351 - break 381 + return dateLocale 352 382 } 353 383 case AppLanguage.sv: { 354 384 i18n.loadAndActivate({locale, messages: messagesSv}) 355 - await Promise.all([ 385 + const [{default: dateLocale}] = await Promise.all([ 386 + import('date-fns/locale/sv'), 356 387 import('@formatjs/intl-pluralrules/locale-data/sv'), 357 388 import('@formatjs/intl-numberformat/locale-data/sv'), 358 389 import('@formatjs/intl-displaynames/locale-data/sv'), 359 390 ]) 360 - break 391 + return dateLocale 361 392 } 362 393 case AppLanguage.th: { 363 394 i18n.loadAndActivate({locale, messages: messagesTh}) 364 - await Promise.all([ 395 + const [{default: dateLocale}] = await Promise.all([ 396 + import('date-fns/locale/th'), 365 397 import('@formatjs/intl-pluralrules/locale-data/th'), 366 398 import('@formatjs/intl-numberformat/locale-data/th'), 367 399 import('@formatjs/intl-displaynames/locale-data/th'), 368 400 ]) 369 - break 401 + return dateLocale 370 402 } 371 403 case AppLanguage.tr: { 372 404 i18n.loadAndActivate({locale, messages: messagesTr}) 373 - await Promise.all([ 405 + const [{default: dateLocale}] = await Promise.all([ 406 + import('date-fns/locale/tr'), 374 407 import('@formatjs/intl-pluralrules/locale-data/tr'), 375 408 import('@formatjs/intl-numberformat/locale-data/tr'), 376 409 import('@formatjs/intl-displaynames/locale-data/tr'), 377 410 ]) 378 - break 411 + return dateLocale 379 412 } 380 413 case AppLanguage.uk: { 381 414 i18n.loadAndActivate({locale, messages: messagesUk}) 382 - await Promise.all([ 415 + const [{default: dateLocale}] = await Promise.all([ 416 + import('date-fns/locale/uk'), 383 417 import('@formatjs/intl-pluralrules/locale-data/uk'), 384 418 import('@formatjs/intl-numberformat/locale-data/uk'), 385 419 import('@formatjs/intl-displaynames/locale-data/uk'), 386 420 ]) 387 - break 421 + return dateLocale 388 422 } 389 423 case AppLanguage.vi: { 390 424 i18n.loadAndActivate({locale, messages: messagesVi}) 391 - await Promise.all([ 425 + const [{default: dateLocale}] = await Promise.all([ 426 + import('date-fns/locale/vi'), 392 427 import('@formatjs/intl-pluralrules/locale-data/vi'), 393 428 import('@formatjs/intl-numberformat/locale-data/vi'), 394 429 import('@formatjs/intl-displaynames/locale-data/vi'), 395 430 ]) 396 - break 431 + return dateLocale 397 432 } 398 433 case AppLanguage.zh_CN: { 399 434 i18n.loadAndActivate({locale, messages: messagesZh_CN}) 400 - await Promise.all([ 435 + const [{default: dateLocale}] = await Promise.all([ 436 + import('date-fns/locale/zh-CN'), 401 437 import('@formatjs/intl-pluralrules/locale-data/zh'), 402 438 import('@formatjs/intl-numberformat/locale-data/zh'), 403 439 import('@formatjs/intl-displaynames/locale-data/zh'), 404 440 ]) 405 - break 441 + return dateLocale 406 442 } 407 443 case AppLanguage.zh_HK: { 408 444 i18n.loadAndActivate({locale, messages: messagesZh_HK}) 409 - await Promise.all([ 445 + const [{default: dateLocale}] = await Promise.all([ 446 + import('date-fns/locale/zh-HK'), 410 447 import('@formatjs/intl-pluralrules/locale-data/zh'), 411 448 import('@formatjs/intl-numberformat/locale-data/zh'), 412 449 import('@formatjs/intl-displaynames/locale-data/zh'), 413 450 ]) 414 - break 451 + return dateLocale 415 452 } 416 453 case AppLanguage.zh_TW: { 417 454 i18n.loadAndActivate({locale, messages: messagesZh_TW}) 418 - await Promise.all([ 455 + const [{default: dateLocale}] = await Promise.all([ 456 + import('date-fns/locale/zh-TW'), 419 457 import('@formatjs/intl-pluralrules/locale-data/zh'), 420 458 import('@formatjs/intl-numberformat/locale-data/zh'), 421 459 import('@formatjs/intl-displaynames/locale-data/zh'), 422 460 ]) 423 - break 461 + return dateLocale 424 462 } 425 463 default: { 426 464 i18n.loadAndActivate({locale, messages: messagesEn}) 427 - break 465 + return defaultLocale 428 466 } 429 467 } 430 468 } 431 469 432 470 export function useLocaleLanguage() { 433 471 const {appLanguage} = useLanguagePrefs() 472 + const [dateLocale, setDateLocale] = useState(defaultLocale) 473 + 434 474 useEffect(() => { 435 - dynamicActivate(sanitizeAppLanguageSetting(appLanguage)) 475 + dynamicActivate(sanitizeAppLanguageSetting(appLanguage)).then(locale => { 476 + setDateLocale(locale ?? defaultLocale) 477 + }) 436 478 }, [appLanguage]) 479 + 480 + return dateLocale 437 481 }
+160 -39
src/locale/i18n.web.ts
··· 1 - import {useEffect} from 'react' 1 + import {useEffect, useState} from 'react' 2 2 import {i18n} from '@lingui/core' 3 + import defaultLocale from 'date-fns/locale/en-US' 3 4 4 5 import {sanitizeAppLanguageSetting} from '#/locale/helpers' 5 6 import {AppLanguage} from '#/locale/languages' ··· 10 11 */ 11 12 export async function dynamicActivate(locale: AppLanguage) { 12 13 let mod: any 14 + let dateLocale: Locale = defaultLocale 13 15 14 16 switch (locale) { 15 17 case AppLanguage.an: { 16 - mod = await import(`./locales/an/messages`) 18 + ;[mod, {default: dateLocale}] = await Promise.all([ 19 + import(`./locales/an/messages`), 20 + import('date-fns/locale/es'), 21 + ]) 17 22 break 18 23 } 19 24 case AppLanguage.ast: { 20 - mod = await import(`./locales/ast/messages`) 25 + ;[mod, {default: dateLocale}] = await Promise.all([ 26 + import(`./locales/ast/messages`), 27 + import('date-fns/locale/es'), 28 + ]) 21 29 break 22 30 } 23 31 case AppLanguage.ca: { 24 - mod = await import(`./locales/ca/messages`) 32 + ;[mod, {default: dateLocale}] = await Promise.all([ 33 + import(`./locales/ca/messages`), 34 + import('date-fns/locale/ca'), 35 + ]) 25 36 break 26 37 } 27 38 case AppLanguage.cy: { 28 - mod = await import(`./locales/cy/messages`) 39 + ;[mod, {default: dateLocale}] = await Promise.all([ 40 + import(`./locales/cy/messages`), 41 + import('date-fns/locale/cy'), 42 + ]) 29 43 break 30 44 } 31 45 case AppLanguage.da: { 32 - mod = await import(`./locales/da/messages`) 46 + ;[mod, {default: dateLocale}] = await Promise.all([ 47 + import(`./locales/da/messages`), 48 + import('date-fns/locale/da'), 49 + ]) 33 50 break 34 51 } 35 52 case AppLanguage.de: { 36 - mod = await import(`./locales/de/messages`) 53 + ;[mod, {default: dateLocale}] = await Promise.all([ 54 + import(`./locales/de/messages`), 55 + import('date-fns/locale/de'), 56 + ]) 37 57 break 38 58 } 39 59 case AppLanguage.el: { 40 - mod = await import(`./locales/el/messages`) 60 + ;[mod, {default: dateLocale}] = await Promise.all([ 61 + import(`./locales/el/messages`), 62 + import('date-fns/locale/el'), 63 + ]) 41 64 break 42 65 } 43 66 case AppLanguage.en_GB: { 44 - mod = await import(`./locales/en-GB/messages`) 67 + ;[mod, {default: dateLocale}] = await Promise.all([ 68 + import(`./locales/en-GB/messages`), 69 + import('date-fns/locale/en-GB'), 70 + ]) 45 71 break 46 72 } 47 73 case AppLanguage.eo: { 48 - mod = await import(`./locales/eo/messages`) 74 + ;[mod, {default: dateLocale}] = await Promise.all([ 75 + import(`./locales/eo/messages`), 76 + import('date-fns/locale/eo'), 77 + ]) 49 78 break 50 79 } 51 80 case AppLanguage.es: { 52 - mod = await import(`./locales/es/messages`) 81 + ;[mod, {default: dateLocale}] = await Promise.all([ 82 + import(`./locales/es/messages`), 83 + import('date-fns/locale/es'), 84 + ]) 53 85 break 54 86 } 55 87 case AppLanguage.eu: { 56 - mod = await import(`./locales/eu/messages`) 88 + ;[mod, {default: dateLocale}] = await Promise.all([ 89 + import(`./locales/eu/messages`), 90 + import('date-fns/locale/eu'), 91 + ]) 57 92 break 58 93 } 59 94 case AppLanguage.fi: { 60 - mod = await import(`./locales/fi/messages`) 95 + ;[mod, {default: dateLocale}] = await Promise.all([ 96 + import(`./locales/fi/messages`), 97 + import('date-fns/locale/fi'), 98 + ]) 61 99 break 62 100 } 63 101 case AppLanguage.fr: { 64 - mod = await import(`./locales/fr/messages`) 102 + ;[mod, {default: dateLocale}] = await Promise.all([ 103 + import(`./locales/fr/messages`), 104 + import('date-fns/locale/fr'), 105 + ]) 65 106 break 66 107 } 67 108 case AppLanguage.fy: { 68 - mod = await import(`./locales/fy/messages`) 109 + ;[mod, {default: dateLocale}] = await Promise.all([ 110 + import(`./locales/fy/messages`), 111 + import('date-fns/locale/fy'), 112 + ]) 69 113 break 70 114 } 71 115 case AppLanguage.ga: { ··· 73 117 break 74 118 } 75 119 case AppLanguage.gd: { 76 - mod = await import(`./locales/gd/messages`) 120 + ;[mod, {default: dateLocale}] = await Promise.all([ 121 + import(`./locales/gd/messages`), 122 + import('date-fns/locale/gd'), 123 + ]) 77 124 break 78 125 } 79 126 case AppLanguage.gl: { 80 - mod = await import(`./locales/gl/messages`) 127 + ;[mod, {default: dateLocale}] = await Promise.all([ 128 + import(`./locales/gl/messages`), 129 + import('date-fns/locale/gl'), 130 + ]) 81 131 break 82 132 } 83 133 case AppLanguage.hi: { 84 - mod = await import(`./locales/hi/messages`) 134 + ;[mod, {default: dateLocale}] = await Promise.all([ 135 + import(`./locales/hi/messages`), 136 + import('date-fns/locale/hi'), 137 + ]) 85 138 break 86 139 } 87 140 case AppLanguage.hu: { 88 - mod = await import(`./locales/hu/messages`) 141 + ;[mod, {default: dateLocale}] = await Promise.all([ 142 + import(`./locales/hu/messages`), 143 + import('date-fns/locale/hu'), 144 + ]) 89 145 break 90 146 } 91 147 case AppLanguage.ia: { ··· 93 149 break 94 150 } 95 151 case AppLanguage.id: { 96 - mod = await import(`./locales/id/messages`) 152 + ;[mod, {default: dateLocale}] = await Promise.all([ 153 + import(`./locales/id/messages`), 154 + import('date-fns/locale/id'), 155 + ]) 97 156 break 98 157 } 99 158 case AppLanguage.it: { 100 - mod = await import(`./locales/it/messages`) 159 + ;[mod, {default: dateLocale}] = await Promise.all([ 160 + import(`./locales/it/messages`), 161 + import('date-fns/locale/it'), 162 + ]) 101 163 break 102 164 } 103 165 case AppLanguage.ja: { 104 - mod = await import(`./locales/ja/messages`) 166 + ;[mod, {default: dateLocale}] = await Promise.all([ 167 + import(`./locales/ja/messages`), 168 + import('date-fns/locale/ja'), 169 + ]) 105 170 break 106 171 } 107 172 case AppLanguage.km: { 108 - mod = await import(`./locales/km/messages`) 173 + ;[mod, {default: dateLocale}] = await Promise.all([ 174 + import(`./locales/km/messages`), 175 + import('date-fns/locale/km'), 176 + ]) 109 177 break 110 178 } 111 179 case AppLanguage.ko: { 112 - mod = await import(`./locales/ko/messages`) 180 + ;[mod, {default: dateLocale}] = await Promise.all([ 181 + import(`./locales/ko/messages`), 182 + import('date-fns/locale/ko'), 183 + ]) 113 184 break 114 185 } 115 186 case AppLanguage.ne: { ··· 117 188 break 118 189 } 119 190 case AppLanguage.nl: { 120 - mod = await import(`./locales/nl/messages`) 191 + ;[mod, {default: dateLocale}] = await Promise.all([ 192 + import(`./locales/nl/messages`), 193 + import('date-fns/locale/nl'), 194 + ]) 121 195 break 122 196 } 123 197 case AppLanguage.pl: { 124 - mod = await import(`./locales/pl/messages`) 198 + ;[mod, {default: dateLocale}] = await Promise.all([ 199 + import(`./locales/pl/messages`), 200 + import('date-fns/locale/pl'), 201 + ]) 125 202 break 126 203 } 127 204 case AppLanguage.pt_BR: { 128 - mod = await import(`./locales/pt-BR/messages`) 205 + ;[mod, {default: dateLocale}] = await Promise.all([ 206 + import(`./locales/pt-BR/messages`), 207 + import('date-fns/locale/pt-BR'), 208 + ]) 129 209 break 130 210 } 131 211 case AppLanguage.pt_PT: { 132 - mod = await import(`./locales/pt-PT/messages`) 212 + ;[mod, {default: dateLocale}] = await Promise.all([ 213 + import(`./locales/pt-PT/messages`), 214 + import('date-fns/locale/pt'), 215 + ]) 133 216 break 134 217 } 135 218 case AppLanguage.ro: { 136 - mod = await import(`./locales/ro/messages`) 219 + ;[mod, {default: dateLocale}] = await Promise.all([ 220 + import(`./locales/ro/messages`), 221 + import('date-fns/locale/ro'), 222 + ]) 137 223 break 138 224 } 139 225 case AppLanguage.ru: { 140 - mod = await import(`./locales/ru/messages`) 226 + ;[mod, {default: dateLocale}] = await Promise.all([ 227 + import(`./locales/ru/messages`), 228 + import('date-fns/locale/ru'), 229 + ]) 141 230 break 142 231 } 143 232 case AppLanguage.sv: { 144 - mod = await import(`./locales/sv/messages`) 233 + ;[mod, {default: dateLocale}] = await Promise.all([ 234 + import(`./locales/sv/messages`), 235 + import('date-fns/locale/sv'), 236 + ]) 145 237 break 146 238 } 147 239 case AppLanguage.th: { 148 - mod = await import(`./locales/th/messages`) 240 + ;[mod, {default: dateLocale}] = await Promise.all([ 241 + import(`./locales/th/messages`), 242 + import('date-fns/locale/th'), 243 + ]) 149 244 break 150 245 } 151 246 case AppLanguage.tr: { 152 - mod = await import(`./locales/tr/messages`) 247 + ;[mod, {default: dateLocale}] = await Promise.all([ 248 + import(`./locales/tr/messages`), 249 + import('date-fns/locale/tr'), 250 + ]) 153 251 break 154 252 } 155 253 case AppLanguage.uk: { 156 - mod = await import(`./locales/uk/messages`) 254 + ;[mod, {default: dateLocale}] = await Promise.all([ 255 + import(`./locales/uk/messages`), 256 + import('date-fns/locale/uk'), 257 + ]) 157 258 break 158 259 } 159 260 case AppLanguage.vi: { 160 - mod = await import(`./locales/vi/messages`) 261 + ;[mod, {default: dateLocale}] = await Promise.all([ 262 + import(`./locales/vi/messages`), 263 + import('date-fns/locale/vi'), 264 + ]) 161 265 break 162 266 } 163 267 case AppLanguage.zh_CN: { 164 - mod = await import(`./locales/zh-CN/messages`) 268 + ;[mod, {default: dateLocale}] = await Promise.all([ 269 + import(`./locales/zh-CN/messages`), 270 + import('date-fns/locale/zh-CN'), 271 + ]) 165 272 break 166 273 } 167 274 case AppLanguage.zh_HK: { 168 - mod = await import(`./locales/zh-HK/messages`) 275 + ;[mod, {default: dateLocale}] = await Promise.all([ 276 + import(`./locales/zh-HK/messages`), 277 + import('date-fns/locale/zh-HK'), 278 + ]) 169 279 break 170 280 } 171 281 case AppLanguage.zh_TW: { 172 - mod = await import(`./locales/zh-TW/messages`) 282 + ;[mod, {default: dateLocale}] = await Promise.all([ 283 + import(`./locales/zh-TW/messages`), 284 + import('date-fns/locale/zh-TW'), 285 + ]) 173 286 break 174 287 } 175 288 default: { ··· 180 293 181 294 i18n.load(locale, mod.messages) 182 295 i18n.activate(locale) 296 + 297 + return dateLocale 183 298 } 184 299 185 300 export function useLocaleLanguage() { 186 301 const {appLanguage} = useLanguagePrefs() 302 + const [dateLocale, setDateLocale] = useState(defaultLocale) 303 + 187 304 useEffect(() => { 188 305 const sanitizedLanguage = sanitizeAppLanguageSetting(appLanguage) 189 306 190 307 document.documentElement.lang = sanitizedLanguage 191 - dynamicActivate(sanitizedLanguage) 308 + dynamicActivate(sanitizedLanguage).then(locale => { 309 + setDateLocale(locale) 310 + }) 192 311 }, [appLanguage]) 312 + 313 + return dateLocale 193 314 }
+24 -2
src/locale/i18nProvider.tsx
··· 1 + import {createContext, useContext} from 'react' 1 2 import {i18n} from '@lingui/core' 2 3 import {I18nProvider as DefaultI18nProvider} from '@lingui/react' 4 + import {type Locale} from 'date-fns' 3 5 import type React from 'react' 4 6 5 7 import {useLocaleLanguage} from './i18n' 6 8 9 + const DateLocaleContext = createContext<Locale | undefined>(undefined) 10 + DateLocaleContext.displayName = 'DateLocaleContext' 11 + 7 12 export default function I18nProvider({children}: {children: React.ReactNode}) { 8 - useLocaleLanguage() 9 - return <DefaultI18nProvider i18n={i18n}>{children}</DefaultI18nProvider> 13 + const dateLocale = useLocaleLanguage() 14 + return ( 15 + <DateLocaleContext value={dateLocale}> 16 + <DefaultI18nProvider i18n={i18n}>{children}</DefaultI18nProvider> 17 + </DateLocaleContext> 18 + ) 19 + } 20 + 21 + /** 22 + * Returns a `date-fns` locale corresponding to the current app language 23 + */ 24 + export function useDateLocale() { 25 + const ctx = useContext(DateLocaleContext) 26 + 27 + if (!ctx) { 28 + throw new Error('useDateLocale must be used within an I18nProvider') 29 + } 30 + 31 + return ctx 10 32 }