Структура проекта

Понимание директории .lingo/ и её содержимого.

Обзор директорий

Когда вы впервые запускаете компилятор, он создаёт директорию .lingo/ в корне вашего проекта:

your-project/
├── .lingo/
│   ├── metadata.json
│   ├── locale-resolver.server.ts (optional)
│   └── locale-resolver.client.ts (optional)
├── src/
├── package.json
└── ...

metadata.json

Основной файл, содержащий все данные переводов.

Структура

{
  "version": "1",
  "sourceLocale": "en",
  "targetLocales": ["es", "de", "fr"],
  "translations": {
    "abc123def456": {
      "source": "Welcome to our app",
      "context": {
        "file": "app/page.tsx",
        "line": 12,
        "component": "HomePage"
      },
      "locales": {
        "es": "Bienvenido a nuestra aplicación",
        "de": "Willkommen in unserer App",
        "fr": "Bienvenue dans notre application"
      },
      "metadata": {
        "createdAt": "2024-01-15T10:30:00Z",
        "updatedAt": "2024-01-15T10:30:00Z"
      }
    }
  }
}

Ключевые поля

Version: Версия формата метаданных. Текущая: "1"

Source/Target Locales: Настроенные локали

Translations: Хеш-таблица всех переводимых строк:

  • Hash (abc123def456): Стабильный идентификатор на основе исходного текста и контекста
  • source: Оригинальный английский текст
  • context: Где этот текст используется (файл, строка, компонент)
  • locales: Переводы для каждой целевой локали
  • metadata: Когда перевод был создан или обновлён

Генерация хеша

Хеши детерминированы:

  • Основаны на исходном тексте и контексте компонента
  • Один и тот же текст в разных местах = разные хеши
  • Обеспечивает контекстно-зависимые переводы

Пример:

// app/home/page.tsx
<button>Submit</button> // Hash: abc123

// app/checkout/page.tsx
<button>Submit</button> // Hash: def456 (different context)

Кастомные резолверы локалей

Необязательные файлы для кастомизации определения и сохранения локали.

locale-resolver.server.ts

Определение локали на сервере (только для Next.js):

// .lingo/locale-resolver.server.ts
export async function getServerLocale(): Promise<string> {
  // Your custom logic
  return "en";
}

locale-resolver.client.ts

Определение и сохранение локали на клиенте:

// .lingo/locale-resolver.client.ts
export function getClientLocale(): string {
  // Detect locale
  return "en";
}

export function persistLocale(locale: string): void {
  // Save locale preference
}

Если эти файлы отсутствуют, компилятор использует стандартное поведение на основе cookie.

Подробнее см. в разделе Пользовательские резолверы локалей.

Контроль версий

Стоит ли коммитить .lingo/?

Да. Каталог .lingo/ должен находиться под контролем версий:

Коммитить:

  • metadata.json — содержит все переводы
  • Пользовательские резолверы локалей (если созданы)

Не коммитить:

  • Ничего — все файлы в .lingo/ должны быть закоммичены

Зачем коммитить переводы?

  1. Контроль версий — отслеживайте изменения переводов вместе с кодом
  2. Совместная работа — делитесь переводами с командой
  3. CI/CD — продакшн-сборки используют закоммиченные переводы
  4. История изменений — видно, когда и почему менялись переводы

Интеграция с Git

Добавьте .lingo/ в свой репозиторий:

git add .lingo/
git commit -m "chore: update translations"
git push

Компилятор автоматически обновляет .lingo/metadata.json, когда:

  • Добавляется новый переводимый текст
  • Изменяется существующий текст
  • Генерируются переводы

Регулярно коммитьте эти обновления.

Размер файла

metadata.json увеличивается вместе с вашим приложением:

  • Маленькое приложение (50 строк): ~10 КБ
  • Среднее приложение (500 строк): ~100 КБ
  • Большое приложение (5000 строк): ~1 МБ

Это нормально и допустимо для контроля версий.

Очистка

Удаление неиспользуемых переводов

Со временем могут накапливаться неиспользуемые переводы (от удалённых компонентов).

Ручная очистка:

  1. Найдите хеш в кодовой базе
  2. Если не найден — удалите из metadata.json

Автоматическая очистка (скоро появится):

npx @lingo.dev/compiler clean

Это позволит автоматически удалять неиспользуемые переводы.

Сбросить переводы

Чтобы сгенерировать все переводы заново:

# Backup current translations
cp .lingo/metadata.json .lingo/metadata.backup.json

# Delete metadata
rm .lingo/metadata.json

# Regenerate
npm run dev # or npm run build

Миграция

С старого компилятора

В старом компиляторе использовалась другая структура файлов:

Старая:

lingo/
├── dictionary.js
├── meta.json
└── [locale]/
    └── *.json

Новая:

.lingo/
└── metadata.json

Миграция не автоматизирована. Подробнее см. в руководстве по миграции.

Проверка переводов

Просмотр в редакторе

Откройте .lingo/metadata.json в редакторе:

{
  "translations": {
    "abc123": {
      "source": "Welcome",
      "locales": {
        "es": "Bienvenido"
      }
    }
  }
}

Поиск перевода

Найдите перевод по исходному тексту:

grep -r "Welcome" .lingo/metadata.json

Поиск по хэшу

grep -r "abc123" .lingo/metadata.json

Красивый вывод

cat .lingo/metadata.json | jq '.'

Частые вопросы

Можно ли вручную редактировать metadata.json? Да, но не рекомендуется. Лучше использовать data-lingo-override — так безопаснее, и изменения отслеживаются в исходном коде.

Что если я удалю metadata.json? Компилятор пересоздаст его при следующей сборке. Все переводы будут сгенерированы заново (это расходует API-кредиты).

Могу ли я переместить .lingo/ в другую папку? Да. Настройте это через опцию lingoDir:

{
  lingoDir: "translations"
}

Содержит ли metadata.json конфиденциальные данные? Нет. В нём только исходный текст и переводы — никаких API-ключей или секретов.

Можно ли объединять metadata.json из разных веток? Да. Git сам справляется с мержами. Конфликты бывают редко (хэши уникальны).

Что если две ветки добавят один и тот же перевод? Git объединит их автоматически. Если хэши разные (разный контекст), оба варианта сохранятся.

Дальше