languages.js 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. /**
  2. * Language configuration for i18n and SEO
  3. *
  4. * This configuration is used for:
  5. * - hreflang tags
  6. * - Language detection
  7. * - URL path generation
  8. * - Locale imports
  9. */
  10. export const LANGUAGES = {
  11. en: {
  12. code: 'en', // ISO 639-1 language code (used in hreflang)
  13. urlPath: '', // URL path prefix (empty for default language)
  14. name: 'English',
  15. nativeName: 'English',
  16. isDefault: true,
  17. },
  18. ja: {
  19. code: 'ja', // ISO 639-1 language code
  20. urlPath: '/ja', // URL path prefix
  21. name: 'Japanese',
  22. nativeName: '日本語',
  23. isDefault: false,
  24. },
  25. ko: {
  26. code: 'ko', // ISO 639-1 language code
  27. urlPath: '/ko', // URL path prefix
  28. name: 'Korean',
  29. nativeName: '한국어',
  30. isDefault: false,
  31. },
  32. }
  33. // Helper to get language config by URL path
  34. export function getLanguageByPath(pathname) {
  35. // Check if pathname starts with any language prefix
  36. for (const [key, lang] of Object.entries(LANGUAGES)) {
  37. if (lang.urlPath && pathname.startsWith(lang.urlPath)) {
  38. return lang
  39. }
  40. }
  41. // Default to English
  42. return LANGUAGES.en
  43. }
  44. // Helper to get language config by locale code
  45. export function getLanguageByCode(code) {
  46. return LANGUAGES[code] || LANGUAGES.en
  47. }
  48. // Helper to generate alternate URLs for hreflang
  49. export function generateAlternateUrls(pathname) {
  50. const alternates = []
  51. // Normalize pathname (remove any existing language prefix)
  52. let normalizedPath = pathname
  53. for (const lang of Object.values(LANGUAGES)) {
  54. if (lang.urlPath && pathname.startsWith(lang.urlPath)) {
  55. normalizedPath = pathname.slice(lang.urlPath.length) || '/'
  56. break
  57. }
  58. }
  59. // Generate alternate URLs for each language
  60. for (const lang of Object.values(LANGUAGES)) {
  61. const url = lang.urlPath ? `${lang.urlPath}${normalizedPath}` : normalizedPath
  62. alternates.push({
  63. hreflang: lang.code,
  64. url: url,
  65. })
  66. }
  67. return alternates
  68. }
  69. // Get all supported language codes
  70. export const SUPPORTED_LANGUAGES = Object.keys(LANGUAGES)
  71. // Get default language
  72. export const DEFAULT_LANGUAGE = Object.values(LANGUAGES).find(lang => lang.isDefault)
  73. /**
  74. * Get localized href for a given path and locale
  75. *
  76. * @param {string} path - The path to localize (can be internal or external URL)
  77. * @param {string} locale - The locale code (e.g., 'en', 'ja', 'ko')
  78. * @returns {string} The localized path
  79. *
  80. * @example
  81. * getLocalizedHref('/docs', 'en') // '/docs'
  82. * getLocalizedHref('/docs', 'ja') // '/ja/docs'
  83. * getLocalizedHref('docs', 'ko') // '/ko/docs' (normalized with leading slash)
  84. * getLocalizedHref('https://example.com', 'ja') // 'https://example.com' (external URLs unchanged)
  85. */
  86. export function getLocalizedHref(path, locale) {
  87. // Handle external URLs - don't add locale prefix
  88. if (path.startsWith('http://') || path.startsWith('https://') || path.startsWith('//')) {
  89. return path
  90. }
  91. // Normalize internal paths to ensure leading slash
  92. const normalizedPath = path.startsWith('/') ? path : `/${path}`
  93. // For English (default locale), return normalized path without locale prefix
  94. if (locale === 'en') {
  95. return normalizedPath
  96. }
  97. // For other locales, prefix with /{locale}
  98. return `/${locale}${normalizedPath}`
  99. }