Skip to content
Docs
i18n 문서로 돌아가기

Translation Loaders

설정
@hua-labs/i18n-loaders

번역 로딩 전략 가이드: API, 정적, 커스텀 로더의 사용 사례와 SSR 지원 여부.

설치

Terminalbash
npm install @hua-labs/i18n-loaders
Importtsx
import { Translation Loaders } from '@hua-labs/i18n-loaders';

개요

Translation Loaders는 API 엔드포인트, 정적 파일 또는 커스텀 소스에서 번역 파일을 로드하는 유연한 전략을 제공합니다.

로더 유형

API 로더
SSR
API 엔드포인트에서 번역을 로드, 서버 렌더링 앱에 적합
정적 로더
Client
정적 JSON 파일에서 번역을 로드, 클라이언트 사이드 앱에 적합
커스텀 로더
Flexible
CMS 또는 데이터베이스 기반 번역을 위한 커스텀 로딩 전략 구현

API 레퍼런스

옵션

이름타입기본값설명
translationApiPathstring"/api/translations"docs:i18n.translation-loaders.options.translationApiPath
baseUrlstring-docs:i18n.translation-loaders.options.baseUrl
cacheTtlMsnumber300000docs:i18n.translation-loaders.options.cacheTtlMs
disableCachebooleanfalsedocs:i18n.translation-loaders.options.disableCache
retryCountnumber0docs:i18n.translation-loaders.options.retryCount
retryDelaynumber1000docs:i18n.translation-loaders.options.retryDelay
autoInvalidateInDevbooleantruedocs:i18n.translation-loaders.options.autoInvalidateInDev
fetcher(url: RequestInfo | URL, init?: RequestInit) => Promise<Response>fetchdocs:i18n.translation-loaders.options.fetcher
localFallbackBaseUrlstring"http://localhost:3000"docs:i18n.translation-loaders.options.localFallbackBaseUrl
requestInitRequestInit | ((lang: string, ns: string) => RequestInit)-docs:i18n.translation-loaders.options.requestInit
loggerPick<Console, 'log' | 'warn' | 'error'>consoledocs:i18n.translation-loaders.options.logger

반환값

이름타입설명
loader(language: string, namespace: string) => Promise<TranslationRecord>docs:i18n.translation-loaders.returns.loader
invalidate(language?: string, namespace?: string) => voiddocs:i18n.translation-loaders.returns.invalidate
clear() => voiddocs:i18n.translation-loaders.returns.clear

코드 예시

docs:i18n.translation-loaders.examples.i18nexamplesproductionloader

tsx
import { createApiTranslationLoader } from '@hua-labs/i18n-loaders';
import { createCoreI18n } from '@hua-labs/i18n-core';

// Production-ready loader with caching, retry, and dev auto-invalidation
// Returns TranslationLoader function with .invalidate() and .clear() methods
const loader = createApiTranslationLoader({
  translationApiPath: '/api/translations',
  baseUrl: process.env.NEXT_PUBLIC_BASE_URL,
  retryCount: 2,
  retryDelay: 1000,
  cacheTtlMs: 5 * 60 * 1000, // 5 minutes
  autoInvalidateInDev: true,
});

// Pass to createCoreI18n
const I18nProvider = createCoreI18n({
  defaultLanguage: 'ko',
  supportedLanguages: [
    { code: 'ko', name: 'Korean', nativeName: '한국어' },
    { code: 'en', name: 'English', nativeName: 'English' },
  ],
  namespaces: ['common', 'navigation'],
  translationLoader: 'custom',
  loadTranslations: loader,
});

// Cache management via attached methods
loader.invalidate('ko', 'common'); // Invalidate specific
loader.invalidate('ko');            // Invalidate all for language
loader.clear();                     // Clear all cache

docs:i18n.translation-loaders.examples.i18nexamplespreloadandwarm

tsx
import { preloadNamespaces, warmFallbackLanguages } from '@hua-labs/i18n-loaders';

// Preload critical namespaces at app startup
// preloadNamespaces(language, namespaces, loader, options?)
await preloadNamespaces('ko', ['common', 'navigation'], loader, { suppressErrors: true });
await preloadNamespaces('en', ['common', 'navigation'], loader);

// Warm fallback language cache for instant switching
// warmFallbackLanguages(currentLanguage, languages, namespaces, loader, options?)
await warmFallbackLanguages('ko', ['ko', 'en', 'ja'], ['common'], loader);

docs:i18n.translation-loaders.examples.i18nexamplesloadercomparison

tsx
/**
 * Translation Loader Comparison
 * 번역 로더 비교
 *
 * | Loader   | Location            | SSR Support | Use Case                    |
 * |----------|---------------------|-------------|-----------------------------|
 * | api      | lib/translations/   | ✅ Yes      | Production apps, SSR        |
 * | static   | public/translations/| ❌ No       | Simple apps, prototypes     |
 * | custom   | Any                 | ✅ Possible | CMS, external APIs          |
 */

docs:i18n.translation-loaders.examples.i18nexamplesapiloader

tsx
// hua.config.ts - API Loader (Recommended for SSR)
import { defineConfig } from '@hua-labs/hua/framework';

export default defineConfig({
  i18n: {
    defaultLanguage: 'ko',
    supportedLanguages: ['ko', 'en', 'ja'],
    namespaces: ['common', 'navigation'],
    translationLoader: 'api',  // Load from lib/translations/
    translationApiPath: '/api/translations',
  },
});

// File structure:
// your-app/
// ├── lib/
// │   └── translations/
// │       ├── ko/
// │       │   ├── common.json
// │       │   └── navigation.json
// │       └── en/
// │           ├── common.json
// │           └── navigation.json

docs:i18n.translation-loaders.examples.i18nexamplesstaticloader

tsx
// hua.config.ts - Static Loader (No SSR)
import { defineConfig } from '@hua-labs/hua/framework';

export default defineConfig({
  i18n: {
    defaultLanguage: 'ko',
    supportedLanguages: ['ko', 'en'],
    namespaces: ['common'],
    translationLoader: 'static',  // Load from public/translations/
  },
});

// File structure:
// your-app/
// └── public/
//     └── translations/
//         ├── ko/
//         │   └── common.json
//         └── en/
//             └── common.json

// ⚠️ Warning: Static loader causes language flickering on SSR
// because translations are fetched client-side after hydration.

docs:i18n.translation-loaders.examples.i18nexamplescustomloader

tsx
// hua.config.ts - Custom Loader
import { defineConfig } from '@hua-labs/hua/framework';

export default defineConfig({
  i18n: {
    defaultLanguage: 'ko',
    supportedLanguages: ['ko', 'en'],
    namespaces: ['common'],
    translationLoader: 'custom',
    customLoader: async (language: string, namespace: string) => {
      // Load from CMS, external API, or any source
      const response = await fetch(
        `https://cms.example.com/translations/${language}/${namespace}`
      );
      return response.json();
    },
  },
});

docs:i18n.translation-loaders.examples.i18nexamplesapiroute

tsx
// app/api/translations/[language]/[namespace]/route.ts
import { NextResponse } from "next/server";
import fs from "fs";
import path from "path";

export async function GET(
  request: Request,
  { params }: { params: Promise<{ language: string; namespace: string }> }
) {
  const { language, namespace } = await params;

  // API loader reads from lib/translations/ (not public/)
  const filePath = path.join(
    process.cwd(),
    "lib/translations",  // ← Server-side only, supports SSR
    language,
    `${namespace}.json`
  );

  try {
    const content = fs.readFileSync(filePath, "utf-8");
    return NextResponse.json(JSON.parse(content));
  } catch {
    return NextResponse.json({}, { status: 404 });
  }
}

사용 사례

SSR 앱

올바른 언어로 서버사이드 렌더링이 필요한 프로덕션 앱

정적 사이트

SSR이 필요 없는 간단한 사이트

CMS 연동

외부 CMS 또는 API에서 번역 로드