Руководство по миграции

Переходите со старого компилятора (lingo.dev/compiler) на новый @lingo.dev/compiler.

Зачем переходить?

Новый компилятор предлагает:

  • Лучший DX — Всё автоматом по умолчанию (без 'use i18n')
  • Лучшая производительность — Быстрее сборка, круче HMR
  • Режимы сборки — Разделение dev/CI/prod
  • Ручные override'ы — Атрибут data-lingo-override
  • Кастомные locale-резолверы — Гибкое определение локали
  • Dev-инструменты — Псевдопереводчик, dev-виджет (скоро)
  • Чище архитектура — Логичное разделение ответственности

Важные изменения

1. Имя пакета

Было:

npm install lingo.dev

Стало:

npm install @lingo.dev/compiler

2. Пути импорта

Было:

import lingoCompiler from "lingo.dev/compiler";
import { LingoProvider } from "lingo.dev/react/rsc";

Стало:

import { withLingo } from "@lingo.dev/compiler/next";
import { LingoProvider } from "@lingo.dev/compiler/react";

3. API конфигурации

Next.js

Было:

// next.config.js
import lingoCompiler from "lingo.dev/compiler";

export default lingoCompiler.next({
  sourceLocale: "en",
  targetLocales: ["es", "de"],
  models: "lingo.dev",
})(nextConfig);

Стало:

// next.config.ts
import { withLingo } from "@lingo.dev/compiler/next";

export default async function (): Promise<NextConfig> {
  return await withLingo(nextConfig, {
    sourceRoot: "./app", // New: specify source directory
    sourceLocale: "en",
    targetLocales: ["es", "de"],
    models: "lingo.dev",
  });
}

Что поменялось:

  • Конфиг теперь должен быть async-функцией
  • Новый параметр sourceRoot
  • Обёртка withLingo вместо lingoCompiler.next

Vite

Было:

import lingoCompiler from "lingo.dev/compiler";

export default defineConfig(() =>
  lingoCompiler.vite({
    sourceRoot: "src",
    targetLocales: ["es", "de"],
    models: "lingo.dev",
  })(viteConfig)
);

Новое:

import { lingoCompilerPlugin } from "@lingo.dev/compiler/vite";

export default defineConfig({
  plugins: [
    lingoCompilerPlugin({
      sourceRoot: "src",
      sourceLocale: "en", // New: required
      targetLocales: ["es", "de"],
      models: "lingo.dev",
    }),
    react(),
  ],
});

Изменения:

  • Теперь используется плагин вместо обёртки конфига
  • Теперь обязательно указывать sourceLocale
  • Разместите перед плагином react()

4. Настройка провайдера

Старое:

import { LingoProvider, loadDictionary } from "lingo.dev/react/rsc";

export default function Layout({ children }) {
  return (
    <LingoProvider loadDictionary={(locale) => loadDictionary(locale)}>
      {children}
    </LingoProvider>
  );
}

Новое:

import { LingoProvider } from "@lingo.dev/compiler/react";

export default function Layout({ children }) {
  return (
    <LingoProvider>
      {children}
    </LingoProvider>
  );
}

Изменения:

  • Нет пропса loadDictionary — теперь всё внутри
  • Более простой API

5. Структура файлов

Старое:

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

Новое:

.lingo/
└── metadata.json

Изменения:

  • Папка переименована (.lingo против lingo)
  • Один файл метаданных вместо нескольких
  • Другая структура JSON

6. Директива "use i18n"

Старое: Требуется по умолчанию. Добавляйте во все файлы, которые хотите перевести:

'use i18n';

export function Component() { ... }

Новое: Необязательно. По умолчанию все файлы переводятся автоматически. Чтобы включить вручную:

{
  useDirective: true, // Enable opt-in behavior
}

Потом добавьте директиву:

'use i18n';

export function Component() { ... }

Шаги миграции

Шаг 1: Обновите пакет

# Uninstall old package
npm uninstall lingo.dev

# Install new package
npm install @lingo.dev/compiler

Шаг 2: Обновите конфигурацию

Next.js

До:

// next.config.js
import lingoCompiler from "lingo.dev/compiler";

export default lingoCompiler.next({
  sourceLocale: "en",
  targetLocales: ["es", "de"],
  models: "lingo.dev",
})(nextConfig);

После:

// next.config.ts
import type { NextConfig } from "next";
import { withLingo } from "@lingo.dev/compiler/next";

const nextConfig: NextConfig = {};

export default async function (): Promise<NextConfig> {
  return await withLingo(nextConfig, {
    sourceRoot: "./app",
    sourceLocale: "en",
    targetLocales: ["es", "de"],
    models: "lingo.dev",
    dev: {
      usePseudotranslator: true, // Recommended for development
    },
  });
}

Vite

До:

import lingoCompiler from "lingo.dev/compiler";

export default defineConfig(() =>
  lingoCompiler.vite({
    sourceRoot: "src",
    targetLocales: ["es", "de"],
    models: "lingo.dev",
  })(viteConfig)
);

После:

import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import { lingoCompilerPlugin } from "@lingo.dev/compiler/vite";

export default defineConfig({
  plugins: [
    lingoCompilerPlugin({
      sourceRoot: "src",
      sourceLocale: "en",
      targetLocales: ["es", "de"],
      models: "lingo.dev",
      dev: {
        usePseudotranslator: true,
      },
    }),
    react(),
  ],
});

Шаг 3: Обновите провайдер

До:

import { LingoProvider, loadDictionary } from "lingo.dev/react/rsc";

export default function Layout({ children }) {
  return (
    <LingoProvider loadDictionary={(locale) => loadDictionary(locale)}>
      {children}
    </LingoProvider>
  );
}

После:

import { LingoProvider } from "@lingo.dev/compiler/react";

export default function Layout({ children }) {
  return (
    <LingoProvider>
      {children}
    </LingoProvider>
  );
}

Шаг 4: Удалите старые файлы

# Backup old translations (optional)
mv lingo lingo.backup

# Remove old directory
rm -rf lingo

# New directory will be created automatically
# on first build

Шаг 5: Проверьте с помощью псевдопереводчика

npm run dev

С usePseudotranslator: true вы сразу увидите фейковые переводы. Проверьте:

  • Весь нужный текст переведён
  • Нет ошибок компиляции
  • Верстка справляется с разной длиной текста

Шаг 6: Сгенерируйте реальные переводы

Обновите конфиг, чтобы отключить псевдопереводчик:

{
  dev: {
    usePseudotranslator: false,
  }
}

Перезапустите dev-сервер. Компилятор сгенерирует реальные переводы для любого нового или изменённого текста.

Шаг 7: Зафиксируйте новые переводы

git add .lingo/
git commit -m "chore: migrate to @lingo.dev/compiler"
git push

Сопоставление функций

Старые функции → Новые эквиваленты

Старая функцияНовый эквивалентПримечания
dictionary.js.lingo/metadata.jsonДругой формат
meta.json.lingo/metadata.jsonОбъединено в один файл
"use i18n" (обязательно)"use i18n" (необязательно)Теперь по желанию, не обязательно
Custom promptsprompt config optionТа же функциональность
Редактирование переводовdata-lingo-overrideПереопределения на основе атрибутов
Пропуск переводовdata-lingo-override + пустоИли используйте useDirective
Переопределение переводовdata-lingo-overrideНа основе атрибутов
Переключение локалейuseLingoContext()Возвращает { locale, setLocale }
LLM-провайдерыmodels configПоддерживаются те же провайдеры

Новые функции (не было в старом компиляторе)

  • Режимы сборкиtranslate vs cache-only
  • Псевдопереводчик — Мгновенные фейковые переводы
  • Виджет для разработки — Редактирование прямо в браузере (скоро)
  • Пользовательские резолверы локалей — Гибкое определение локали
  • Автоматическое склонение по числу — Поддержка ICU MessageFormat
  • Сервер переводов — Переводы по запросу в режиме разработки

Перевод существующих переводов

Новый компилятор использует другой формат файлов. Существующие переводы не мигрируются автоматически.

Варианты:

Вариант 1: Перегенерировать все переводы

Пусть компилятор создаст новые переводы с нуля:

  1. Удалите старую директорию lingo/
  2. Запустите новый компилятор
  3. Сгенерируйте переводы с помощью AI

Плюсы: Чистый старт, свежие AI-модели Минусы: Стоимость API, возможна потеря нюансов

Вариант 2: ручной скрипт миграции

Напишите скрипт для конвертации старого формата в новый:

// migrate-translations.ts
import * as fs from "fs";

const oldDir = "./lingo";
const newFile = "./.lingo/metadata.json";

// Read old translations
const oldTranslations = {}; // Parse old files

// Convert to new format
const newMetadata = {
  version: "1",
  sourceLocale: "en",
  targetLocales: ["es", "de"],
  translations: {}, // Convert old translations
};

// Write new metadata
fs.writeFileSync(newFile, JSON.stringify(newMetadata, null, 2));

Это ручная работа и зависит от формата.

Вариант 3: гибридный подход

  1. Сгенерируйте новые переводы для большинства текстов
  2. Используйте data-lingo-override для важных переводов, где нужна точная формулировка

Частые проблемы

"Cannot find module '@lingo.dev/compiler'" Выполните npm install @lingo.dev/compiler

"Config must be async function" (Next.js) Обёрните ваш config в async function:

export default async function () {
  return await withLingo(...);
}

"sourceLocale is required" Добавьте sourceLocale: "en" в ваш config.

Переводы не отображаются Проверьте:

  1. LingoProvider находится в корневом layout
  2. .lingo/metadata.json существует
  3. Нет ошибок в консоли

FAQ

Можно ли запускать оба компилятора одновременно? Нет. Удалите старый компилятор перед установкой нового.

Я потеряю свои переводы? Нет, если перенесёте их вручную. Иначе — пересоздайте с помощью AI (тратятся API кредиты).

Что если мой фреймворк ещё не поддерживается? Новый компилятор сейчас поддерживает только Next.js и Vite. Другие фреймворки появятся позже. Пока используйте старый компилятор или добавьте поддержку самостоятельно.

Сколько времени занимает миграция?

  • Простой проект: 15–30 минут
  • Сложный проект: 1–2 часа
  • Больше всего времени уходит на тестирование и проверку переводов

Стоит ли мигрировать сейчас или подождать? Мигрируйте, если:

  • Нужны новые фичи (build-режимы, overrides, кастомные резолверы)
  • Начинаете новый проект
  • Хотите лучший DX

Подождите, если:

  • Ваш проект отлично работает со старым компилятором
  • Вам нужны фреймворки, которые пока не поддерживаются новым компилятором

Что дальше