- Home »

Интернационализация в Angular: как локализовать приложение
Если ты разрабатываешь приложения на Angular и тебе нужно поддерживать несколько языков, то без интернационализации (i18n) не обойтись. Это не просто перевод текста — это полноценная локализация, которая включает форматирование дат, чисел, валют и даже направление текста. Сегодня разберём, как правильно настроить i18n в Angular, какие подводные камни ждут и как развернуть многоязычное приложение на своём сервере.
Как работает интернационализация в Angular
Angular i18n работает на этапе компиляции. Это значит, что для каждого языка генерируется отдельный бандл приложения. Никаких рантайм-переключений языков — всё статично и быстро.
Основные компоненты системы:
- @angular/localize — основная библиотека для локализации
- Angular CLI — инструменты для извлечения и сборки переводов
- XLIFF, XMB, JSON — форматы файлов переводов
- ICU expressions — для сложных случаев (множественные формы, условия)
Пошаговая настройка локализации
Начнём с чистого проекта. Если у тебя уже есть приложение, просто пропусти создание нового.
ng new my-i18n-app
cd my-i18n-app
ng add @angular/localize
Теперь настраиваем angular.json для поддержки нескольких языков:
{
"projects": {
"my-i18n-app": {
"i18n": {
"sourceLocale": "en",
"locales": {
"ru": "src/locale/messages.ru.xlf",
"de": "src/locale/messages.de.xlf"
}
},
"architect": {
"build": {
"configurations": {
"ru": {
"aot": true,
"outputPath": "dist/ru/",
"i18nFile": "src/locale/messages.ru.xlf",
"i18nFormat": "xlf",
"i18nLocale": "ru"
},
"de": {
"aot": true,
"outputPath": "dist/de/",
"i18nFile": "src/locale/messages.de.xlf",
"i18nFormat": "xlf",
"i18nLocale": "de"
}
}
}
}
}
}
}
Добавляем переводы в компонент:
// app.component.html
<h1 i18n="@@welcome">Welcome to our app!</h1>
<p i18n="@@description">This is a multilingual application</p>
<div i18n="@@user-count">
{users, plural, =0 {No users} =1 {One user} other {{{users}} users}}
</div>
Извлекаем строки для перевода:
ng extract-i18n
ng extract-i18n --output-path src/locale
Практические примеры и кейсы
Вот несколько реальных сценариев, с которыми столкнётся каждый разработчик:
Работа с датами и числами
// В компоненте
export class AppComponent {
today = new Date();
price = 1234.56;
users = 42;
}
<!-- В шаблоне -->
<p>{{ today | date:'medium' }}</p>
<p>{{ price | currency:'USD':'symbol':'1.2-2' }}</p>
<p>{{ users | number:'1.0-0' }}</p>
Условные переводы с ICU expressions
<span i18n="@@user-greeting">
{gender, select,
male {Welcome, sir!}
female {Welcome, madam!}
other {Welcome!}
}
</span>
Атрибуты и плейсхолдеры
<input
type="text"
i18n-placeholder="@@search-placeholder"
placeholder="Search..."
i18n-title="@@search-title"
title="Enter search term"
/>
Сравнение подходов к интернационализации
Подход | Производительность | Гибкость | Сложность настройки | Размер бандла |
---|---|---|---|---|
Angular i18n | Отличная | Средняя | Высокая | Оптимальный |
ngx-translate | Хорошая | Высокая | Низкая | Больше на 20-30% |
Transloco | Хорошая | Высокая | Средняя | Средний |
Автоматизация и скрипты
Создаём скрипты для автоматической сборки всех языков:
# build-i18n.sh
#!/bin/bash
languages=("en" "ru" "de")
for lang in "${languages[@]}"
do
echo "Building $lang..."
if [ "$lang" == "en" ]; then
ng build --configuration=production
else
ng build --configuration=production,$lang
fi
done
echo "All languages built successfully!"
Для автоматического развёртывания на сервере:
# deploy-i18n.sh
#!/bin/bash
# Собираем все языки
./build-i18n.sh
# Создаём структуру папок на сервере
ssh user@your-server "mkdir -p /var/www/myapp/{en,ru,de}"
# Загружаем файлы
scp -r dist/en/* user@your-server:/var/www/myapp/en/
scp -r dist/ru/* user@your-server:/var/www/myapp/ru/
scp -r dist/de/* user@your-server:/var/www/myapp/de/
echo "Deployment completed!"
Настройка веб-сервера для многоязычности
Для корректной работы нужно настроить перенаправления. Пример конфигурации Nginx:
server {
listen 80;
server_name myapp.com;
root /var/www/myapp;
index index.html;
# Определяем язык по Accept-Language
location / {
set $lang "en";
if ($http_accept_language ~* "^ru") {
set $lang "ru";
}
if ($http_accept_language ~* "^de") {
set $lang "de";
}
# Перенаправляем на соответствующую папку
try_files $uri $uri/ /$lang/index.html;
}
# Прямые пути к языковым версиям
location /en/ {
try_files $uri $uri/ /en/index.html;
}
location /ru/ {
try_files $uri $uri/ /ru/index.html;
}
location /de/ {
try_files $uri $uri/ /de/index.html;
}
}
Подводные камни и решения
Проблема: Размер проекта растёт с каждым языком
Решение: Используй lazy loading для языковых модулей или рассмотри ngx-translate для рантайм-переключения
Проблема: Сложность CI/CD для множественных сборок
Решение: Автоматизируй через Docker и GitHub Actions
# Dockerfile
FROM node:16-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build:i18n
FROM nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/nginx.conf
Интеграция с системами переводов
Для больших проектов стоит интегрироваться с профессиональными системами переводов:
- Crowdin — поддерживает XLIFF из коробки
- Lokalise — хорошая интеграция с Angular CLI
- Transifex — мощные API для автоматизации
Пример интеграции с Crowdin CLI:
npm install -g @crowdin/cli
# crowdin.yml
project_id: "your-project-id"
api_token: "your-api-token"
base_path: "."
files:
- source: "src/locale/messages.xlf"
translation: "src/locale/messages.%locale%.xlf"
Нестандартные способы использования
Вот несколько хаков, которые могут пригодиться:
Условная загрузка модулей по локали
// locale.service.ts
@Injectable()
export class LocaleService {
loadLocaleData(locale: string) {
return import(`@angular/common/locales/${locale}`)
.then(module => {
registerLocaleData(module.default);
});
}
}
Кастомные пайпы для специфичных форматов
@Pipe({name: 'phoneNumber'})
export class PhoneNumberPipe implements PipeTransform {
transform(value: string, locale: string): string {
switch(locale) {
case 'ru':
return value.replace(/(\d{1})(\d{3})(\d{3})(\d{2})(\d{2})/, '+$1 ($2) $3-$4-$5');
case 'de':
return value.replace(/(\d{2})(\d{3})(\d{3})(\d{4})/, '+$1 $2 $3 $4');
default:
return value;
}
}
}
Мониторинг и аналитика
Не забывай отслеживать, какие языки используются:
// analytics.service.ts
@Injectable()
export class AnalyticsService {
trackLanguageUsage() {
const locale = document.documentElement.lang;
// Отправляем в Google Analytics
gtag('event', 'language_selected', {
'language': locale,
'user_agent': navigator.userAgent
});
}
}
Тестирование многоязычных приложений
Автоматизируй тестирование всех языковых версий:
// e2e/i18n.spec.ts
describe('i18n App', () => {
const languages = ['en', 'ru', 'de'];
languages.forEach(lang => {
it(`should display welcome message in ${lang}`, () => {
cy.visit(`/${lang}`);
cy.get('[data-cy=welcome]').should('be.visible');
});
});
});
Развёртывание на VPS
Для размещения многоязычного приложения тебе понадобится надёжный VPS или выделенный сервер. Особенно это важно, если планируешь автоматические сборки и развёртывания через CI/CD.
Заключение и рекомендации
Angular i18n — мощный инструмент для создания многоязычных приложений, но он требует продуманной архитектуры. Используй его, если:
- У тебя статичный контент, который не меняется часто
- Производительность критична
- Готов настроить сложную систему сборки
Для быстрого прототипирования или частых изменений переводов лучше взять ngx-translate или Transloco.
Главное — не забывай про SEO: каждая языковая версия должна быть доступна по уникальному URL, иметь правильные мета-теги и hreflang атрибуты. И обязательно тестируй на реальных пользователях — автоматические переводы могут быть неточными.
Удачи в создании международных приложений!
В этой статье собрана информация и материалы из различных интернет-источников. Мы признаем и ценим работу всех оригинальных авторов, издателей и веб-сайтов. Несмотря на то, что были приложены все усилия для надлежащего указания исходного материала, любая непреднамеренная оплошность или упущение не являются нарушением авторских прав. Все упомянутые товарные знаки, логотипы и изображения являются собственностью соответствующих владельцев. Если вы считаете, что какой-либо контент, использованный в этой статье, нарушает ваши авторские права, немедленно свяжитесь с нами для рассмотрения и принятия оперативных мер.
Данная статья предназначена исключительно для ознакомительных и образовательных целей и не ущемляет права правообладателей. Если какой-либо материал, защищенный авторским правом, был использован без должного упоминания или с нарушением законов об авторском праве, это непреднамеренно, и мы исправим это незамедлительно после уведомления. Обратите внимание, что переиздание, распространение или воспроизведение части или всего содержимого в любой форме запрещено без письменного разрешения автора и владельца веб-сайта. Для получения разрешений или дополнительных запросов, пожалуйста, свяжитесь с нами.