# Get Translations Source: https://docs.unlingo.com/api-reference/translations/get-translations GET https://api.unlingo.com/v1/translations Retrieve translations for your application ## Overview This is the primary endpoint for fetching translations from Unlingo. It returns ready-to-use translation data that can be directly integrated with any i18n library. ## Authentication You can authenticate using either method: Your API key passed in the header `x-api-key: YOUR_API_KEY` Bearer token with your API key `Authorization: Bearer YOUR_API_KEY` ## Required Parameters The release tag to fetch translations from **Examples**: `1.0.0`, `staging`, `production` The namespace containing your translations **Examples**: `translation`, `auth`, `dashboard` The language code for the translations **Examples**: `en`, `es`, `fr`, `de`, `zh` ## Example Request ```bash cURL curl -X GET "https://api.unlingo.com/v1/translations?release=1.0.0&namespace=translation&lang=en" \ -H "x-api-key: YOUR_API_KEY" ``` ```bash cURL (Bearer) curl -X GET "https://api.unlingo.com/v1/translations?release=1.0.0&namespace=translation&lang=en" \ -H "Authorization: Bearer YOUR_API_KEY" ``` ```javascript JavaScript const response = await fetch('https://api.unlingo.com/v1/translations?release=1.0.0&namespace=translation&lang=en', { headers: { 'x-api-key': 'YOUR_API_KEY', }, }); const translations = await response.json(); ``` ## Response The endpoint returns translation data as a JSON object ready for use with i18n libraries. No nested objects - just your translations exactly as they should be used. ```json Response { "welcome": "Welcome to our application", "login": "Sign In", "logout": "Sign Out", "nav": { "home": "Home", "about": "About", "contact": "Contact" }, "buttons": { "save": "Save", "cancel": "Cancel", "delete": "Delete" }, "messages": { "success": "Operation completed successfully", "error": "An error occurred" } } ``` # Namespaces Source: https://docs.unlingo.com/concepts/namespaces Organize your translations with namespaces for better structure and maintainability ## What are Namespaces? **Namespaces** are logical containers within a project that group related translations together. They help organize your translation keys by feature, component, or any other logical division that makes sense for your application. Think of namespaces as folders in a file system - they provide structure and help prevent naming conflicts while making translations easier to manage. ## Why Use Namespaces? Group related translations together for better maintainability Isolate different features or components to avoid conflicts Allow different teams to work on different namespaces independently Load only the translations you need, reducing bundle size ## Namespace Structure A typical application might use this namespace structure: ``` Project: E-commerce Website ├── common/ # Shared UI elements │ ├── buttons │ ├── navigation │ └── forms ├── product-catalog/ # Product listing and details │ ├── filters │ ├── search │ └── product-card ├── checkout/ # Purchase flow │ ├── cart │ ├── payment │ └── confirmation └── user-account/ # User profile and settings ├── profile ├── orders └── preferences ``` ## Creating Namespaces ### Via Dashboard Go to your project dashboard and select the project you want to work with Click on the "Namespaces" tab in your project navigation Click "Create Namespace" and fill in the details. By default new namespaces are created with `main` version. ## Namespace Versioning Each namespace can have different versions, allowing for independent updates. ## Best Practices ### Keep Namespaces Focused Avoid creating overly broad namespaces that contain unrelated translations. This makes maintenance difficult and reduces the benefits of organization. #### Good: Focused Namespaces ``` auth/ # Only authentication-related product-search/ # Only search functionality user-preferences/ # Only user settings ``` #### Avoid: Overly Broad Namespaces ``` misc/ # Too vague frontend/ # Too broad translations/ # Doesn't provide organization ``` ## Troubleshooting **Verify that:** - The namespace name is spelled correctly - The namespace exists in your project - Your API key has access to the namespace - The namespace is included in the current release ## Next Steps Understand how to version your namespace translations Package namespaces into deployable releases # Projects Source: https://docs.unlingo.com/concepts/projects Understanding Unlingo projects and how to organize your translations ## What are Projects? A **Project** in Unlingo represents a single application or product that requires internationalization. Projects serve as the top-level container for organizing all translation-related resources including namespaces, versions, releases, and API keys. ## Project Structure Each project contains: * **Namespaces**: Logical groupings of related translations * **Releases**: Versioned collections of translations ready for deployment * **Screenshots**: Visual translation mapping for UI elements * **API Keys**: Authentication credentials scoped to the project * **Settings**: Configuration options ## Creating Projects ### Via Dashboard Sign in to your Unlingo account and go to the main dashboard Click the "Create Project" button on your dashboard Enter the required information ## Best Practices ### Project Organization **One Project per Application**: Create separate projects for different applications, even if they share some translations. This provides better isolation and access control. #### Good Project Structure ``` - My E-commerce Website (Project) ├── common (Namespace) ├── product-catalog (Namespace) ├── checkout (Namespace) └── user-account (Namespace) - My Mobile App (Project) ├── onboarding (Namespace) ├── main-navigation (Namespace) └── settings (Namespace) ``` #### Avoid This Structure ``` - All Company Products (Project) ├── website-common (Namespace) ├── website-product-catalog (Namespace) ├── mobile-onboarding (Namespace) └── mobile-navigation (Namespace) ``` ## Troubleshooting Check that you haven't reached your plan's project limit. Free accounts are limited to 1 project. Ensure that your API key is associated with the correct project ## Next Steps Organize your translations within projects using namespaces Package your translations for deployment # Releases Source: https://docs.unlingo.com/concepts/releases Learn how to create and manage releases to publish your translations for production use ## Overview Releases in Unlingo are snapshots of your translations that are published and made available for production use. They represent stable, tested versions of your content that applications can reliably consume through the API. Think of releases as Git tags - they create a reference to a specific version of your translations, that you can change on the fly without changing application code. ## Creating Releases Create a release and assign an existing versions: 1. Navigate to your project's **Releases** tab 2. Click **Create Release** 3. Select the **namespace** 4. Select the **version** from namespace 5. Repeat steps 3-4 if you have multiple namespaces 6. Enter **release name** (e.g., `1.2.0`) 7. Add **release description** (optional) 8. Click **Create Release** ### Release Numbering Releases support various numbering schemes: **Semantic Versioning (Recommended):** ``` 1.0.0 # Initial release 1.0.1 # Patch release 1.1.0 # Minor release 2.0.0 # Major release ``` **Date-based Versioning:** ``` 2024.01.15 # Release date 2024-Q1 # Quarterly release 2024-W03 # Weekly release ``` **Named Releases:** ``` winter-2024 # Seasonal release mobile-launch # Feature release hotfix-jan # Emergency release ``` ## Release Management ### Editing Releases You can modify certain aspects of published releases: 1. **Description**: Update description (it won't affect any usage) 2. **Namespaces and Versions**: You can modify selected namespaces and versions ### Deleting Releases To delete a release: 1. Go to the **Releases** tab 2. Find the release to delete 3. Click the **⋮** menu 4. Select **Delete Release** 5. Confirm the deletion Deleting a release immediately breaks any applications using that release number in their API calls. Ensure no active integrations depend on the release before deletion. ## API Integration ### Fetching Release Content Applications consume releases through the API: ```javascript // Fetch specific release const translations = await fetch('/v1/translations', { params: { namespace: 'common', release: '1.2.0', // Release name lang: 'en', }, }); ``` ## Monitoring and Analytics ### Release Usage Track how releases are being used: * **API calls per release**: Which releases are active * **Language distribution**: Most requested languages * **Namespace popularity**: Most accessed namespaces ## Troubleshooting * **Problem**: * Release missing some expected translations. * **Solutions**: * Verify release name in API call * Verify source version had complete translations * Check if languages were properly included * Ensure version wasn't modified during release creation * Set updated version ## Next Steps Understand the relationship between versions and releases Learn how to consume releases in your application # Screenshots Source: https://docs.unlingo.com/concepts/screenshots Learn how to use visual screenshots to map translations directly onto your UI elements ## Overview Screenshots in Unlingo provide a visual approach to translation management by allowing you to upload images of your application's interface and map translation keys directly to UI elements. This creates an intuitive bridge between your visual design and your translation content. This feature is particularly powerful for design teams, non-technical users, and complex interfaces where the relationship between translation keys and UI elements needs to be clearly visualized. ## Key Concepts ### Visual Translation Mapping Screenshots enable you to: * **Upload UI images**: Capture screens from your application * **Place containers**: Mark translatable areas on the interface * **Assign keys**: Connect translation keys to visual elements * **Edit content**: Update translations directly in visual context * **Collaborate**: Share visual context with team members ### Screenshot Structure Each screenshot contains: * **Image file**: The actual screenshot (PNG, JPG, JPEG) * **Containers**: Colored boxes marking translatable areas * **Key mappings**: Links between containers and translation keys * **Metadata**: Name, description, upload date, dimensions ## Working Modes Screenshots support two distinct working modes: ### Edit Mode **Purpose**: Container placement and configuration **Use case**: Setting up the visual mapping structure **Features**: * Place containers on UI elements * Resize and position containers precisely * Customize container colors for organization * Add descriptions for context * Delete or modify containers **Workflow**: 1. Switch to Edit Mode 2. Click "Add Container" 3. Click on the screenshot to place containers 4. Drag edges to resize containers 5. Add descriptions for clarity ### Translate Mode **Purpose**: Translation key assignment and content editing **Use case**: Actual translation work **Features**: * Select namespace, version, and language * Assign translation keys to containers * Edit translation values inline * Save changes back to language files **Workflow**: 1. Select translation context (namespace/version/language) 2. Click containers to select them 3. Assign translation keys from the language file 4. Edit values directly in the interface 5. Save changes to update translations ## Screenshot Management ### Uploading Screenshots 1. Navigate to the **Screenshots** tab in your project 2. Click **Add Screenshot** 3. Select an image file (PNG, JPG, JPEG up to 10MB) 4. Enter a descriptive name 5. Add an optional description 6. Click **Upload** ### Screenshot Grid The screenshot overview displays: * **Thumbnail preview**: Visual preview of each screenshot * **Name and description**: Identifying information * **Metadata**: Dimensions, file size, upload date * **Quick actions**: Edit, Translate, Delete buttons ## Container System ### Creating Containers #### In Edit Mode: 1. Select container color from color picker 2. Click **Add Container** 3. Click on the screenshot where you want to place the container 4. Container appears with default size 5. Drag handles to resize as needed #### Container Properties: * **Position**: X, Y coordinates (percentage-based) * **Size**: Width and height (percentage-based) * **Color**: Background color for visual organization * **Description**: Optional context for team members ### Container Interaction #### Resizing Containers * Drag corner handles to resize proportionally * Drag edge handles to resize width or height only * Minimum size constraints prevent overly small containers * Maximum size constraints prevent containers exceeding image bounds * Click and drag container body to reposition #### Container Colors Organize containers by color-coding: ```css /* Common color schemes */ Blue (#3b82f6) - Headers and titles Green (#10b981) - Success messages and buttons Red (#ef4444) - Error messages and warnings Purple (#8b5cf6) - Navigation and links Yellow (#f59e0b) - Input fields and forms Gray (#6b7280) - Secondary content ``` ### Container Descriptions Add context to help translators understand the purpose: ``` Examples: "Main page heading - should be concise and impactful" "Error message for invalid email format" "Call-to-action button - keep under 20 characters" "Navigation menu item for user profile section" ``` ## Translation Workflow ### Setting Up Translation Context Before assigning keys, establish the translation context: 1. **Select Namespace**: Choose the namespace containing your translations 2. **Select Version**: Pick the version you're working with 3. **Select Language**: Choose the target language for translation 4. **Lock Context**: System locks selections to prevent accidents The workflow selector provides a step-by-step process ensuring you select all required elements before enabling translation features. ### Assigning Translation Keys #### Key Assignment Process: 1. Click on a container to select it 2. Click **Assign Key** button 3. Search available translation keys 4. Select the appropriate key from the list 5. Key is automatically mapped to the container #### Key Search and Selection: * **Search functionality**: Find keys by name or content * **Type indicators**: Visual badges show data types * **Key preview**: See current values before assignment ### Value Editing #### Inline Editing: 1. Click on a mapped container 2. View assigned keys in the sidebar 3. Click on a key's value to edit 4. Make changes inline 5. Changes are tracked as "pending" 6. Save all changes when ready #### Change Management: * **Pending changes**: Yellow highlighting indicates unsaved edits * **Change counter**: Shows number of modified values ## Advanced Features ### Multi-Language Support Work with multiple languages in the same screenshot: 1. Set up containers in Edit Mode 2. Switch to Translate Mode for first language 3. Assign keys and edit values 4. Change language selection 5. Same containers, different language values ## Performance Optimization ### Image Optimization Optimize screenshots for better performance: * **File size**: Compress images without losing clarity * **Dimensions**: Use appropriate resolution for display * **Format**: Choose optimal format (PNG for UI, JPEG for photos) ### Container Efficiency Optimize container management: * **Minimize containers**: Don't over-map every element * **Strategic placement**: Focus on translatable content only ## Troubleshooting * **Problem**: * Image upload fails or hangs. * **Solutions**: * Check file size (must be under 10MB) * Verify image format (PNG, JPG, JPEG only) * Test with smaller image first * Check internet connection stability * Try different browser if issues persist * **Problem**: * Containers appear in wrong locations. * **Solutions**: * Ensure click coordinates are within image bounds * Try using a different zoom level * Refresh page and try again * **Problem**: * Expected keys don't appear in key selection. * **Solutions**: * Verify correct language is selected * Check if keys exist in the selected version * Ensure translation context is properly locked * Try refreshing the language data * Verify key naming and structure ## Next Steps Integrate with i18next Integrate with next-intl # Translations Source: https://docs.unlingo.com/concepts/translations Learn how to create, edit, and manage translations using Unlingo's powerful editor interface ## Overview Translations in Unlingo are the actual content that gets displayed to users in different languages. The translation system supports complex nested structures, various data types, and provides a powerful visual editor for managing your multilingual content. Unlingo's editor provides both tree view and JSON editing modes, making it accessible for both non-technical translators and developers who prefer working with code. ## Translation Structure ### Nested Keys Translations are organized in a hierarchical structure using dot notation: ```json { "common": { "buttons": { "save": "Save", "cancel": "Cancel", "submit": "Submit" }, "navigation": { "home": "Home", "about": "About Us", "contact": "Contact" } }, "auth": { "login": { "title": "Welcome Back", "subtitle": "Please sign in to continue", "form": { "email": "Email Address", "password": "Password", "remember": "Remember me" } } } } ``` **Accessing in code:** ```javascript t('common.buttons.save'); // "Save" t('auth.login.title'); // "Welcome Back" t('auth.login.form.email'); // "Email Address" ``` ### Data Types Unlingo supports all JSON data types for translation values: #### Strings ```json { "welcome": "Welcome to our application", "description": "This is a longer description text", "greeting": "Hello, {{name}}!" } ``` #### Numbers ```json { "maxItems": 100, "price": 29.99, "version": 2.1 } ``` #### Booleans ```json { "isEnabled": true, "showAdvanced": false, "debugMode": false } ``` #### Arrays ```json { "header": [ { "title": "Dashboard", "subtitle": "Manage your account" }, { "title": "Analytics", "subtitle": "Track your activity" } ] } ``` #### Objects ```json { "header": { "title": "Dashboard", "subtitle": "Manage your account" } } ``` ## Editor Interface ### Tree View Mode The default tree view provides a hierarchical interface: * **Expandable nodes**: Click to expand/collapse sections * **Key organization**: See the structure of your translations * **Value editing**: Click values to edit directly * **Type indicators**: Visual indicators for different data types * **Search functionality**: Find keys quickly across the tree #### Adding Keys 1. Click the **"+"** button in selected node or **"Add Key"** button at the top 2. Choose parent key if needed (optional, by default new keys are added to root level) 3. Enter key name and initial value 4. Select data type (string, number, boolean) #### Deleting Keys 1. Select the key to delete 2. Click the trash icon 3. Confirm deletion in the dialog 4. Key and all children are removed Deleting a key removes it and all nested children. This action cannot be undone. Also all languages in selected version will be affected after Save. ### JSON Edit Mode Switch to JSON mode for direct code editing: * **Error detection**: Real-time validation * **Auto-formatting**: Automatic code formatting * **Bulk editing**: Make large changes quickly #### JSON Mode Features * **Schema validation**: Ensures valid JSON structure * **Type checking**: Validates data types ### Add Key Modal The Add Key modal provides a guided interface for creating new translations: #### Key Information * **Key Name**: The identifier for the translation * **Key Path**: Full dot notation path * **Parent Key**: Context within the hierarchy #### Value Configuration * **Data Type**: String, Number, Boolean, Object, Array * **Initial Value**: Starting content ## Working with Translations ### Creating Content #### Simple Text ```json { "welcome": "Welcome to our application" } ``` #### With Variables ```json { "greeting": "Hello, {{username}}! Welcome back.", "itemCount": "You have {{count}} {{count, plural, one {item} other {items}}}" } ``` #### Nested Structure ```json { "dashboard": { "header": { "title": "Dashboard", "subtitle": "Manage your account" }, "sections": { "overview": "Overview", "analytics": "Analytics", "settings": "Settings" } } } ``` ### Editing Workflows #### In-Place Editing 1. Navigate to the key in tree view 2. Click the value to start editing 3. Make changes in the inline editor 4. Press Apply button #### Batch Editing 1. Switch to JSON edit mode 2. Make multiple changes to the JSON structure 3. Validate changes with the syntax checker 4. Save all changes at once #### Find and Replace 1. Use the search bar to find specific text 2. Use browser find (Ctrl+F) in JSON mode 3. Replace values across multiple keys 4. Filter results by key path or value content ### Validation and Quality Control #### Automatic Validation * **JSON syntax**: Ensures valid structure * **Key naming**: Validates naming conventions * **Data types**: Checks type consistency * **Required fields**: Identifies missing values #### Translation Completeness * **Empty values**: Indicated with warnings ## Troubleshooting * **Problem**: * Edits are not being persisted. * **Solutions**: * Check network connectivity * Look for validation errors * **Problem**: * Invalid JSON preventing saves. * **Solutions**: * Check for missing commas or brackets * Use tree view mode for complex edits * **Problem**: * Keys not appearing in application. * **Solutions**: * Verify key path matches code usage * Check language and version selection * Ensure release includes latest version * Validate API integration * **Problem**: * Editor slow with many keys. * **Solutions**: * Use search/filter to narrow view * Split large namespaces into smaller ones * Edit in JSON mode for bulk changes ## Next Steps Learn visual translation mapping Understand releases management # Versions Source: https://docs.unlingo.com/concepts/versions Understand how versions work in Unlingo to manage different iterations of your translations ## Overview Versions in Unlingo are containers that hold different iterations of your translations within a namespace. They allow you to organize your translations across different stages of development, maintain multiple versions of your product, and safely manage updates to your content. Think of versions as branches in version control - each version represents a specific state of your translations that can evolve independently. ## Key Concepts ### Version Structure Each version contains: * **Languages**: Multiple language translations * **Schema**: Content schema for auto syncs * **Metadata**: Creation time, update history * **Version Number**: Human-readable identifier ### Version Naming Versions support flexible naming conventions: * **Semantic Versioning**: `1.0.0`, `2.1.3`, `1.0.0-beta` * **Branch Names**: `main`, `develop`, `feature-branch` * **Environment Names**: `production`, `staging`, `dev` * **Custom Names**: `winter-release`, `mobile-v1` ## Creating Versions ### New Version Create a completely new version with no existing content: 1. Navigate to your namespace 2. Click **Create Version** 3. Enter a version number (e.g., `1.0.0`) 4. Leave copy option empty 5. Click **Create Version** ### Copy from Existing Version Create a new version by copying content from an existing version: 1. Navigate to your namespace 2. Click **Create Version** 3. Enter new version number (e.g., `1.1.0`) 4. Select **Copy from existing version** 5. Choose the source version to copy from 6. Click **Create Version** Copying from an existing version includes all languages and translations, giving you a complete starting point for your new version. ## Version Management ### Editing Versions You can update version names and metadata: 1. Click the **⋮** menu on a version card 2. Select **Edit Version** 3. Update the version name 4. Save changes Changing version names might break existing releases or API integrations that reference the old name. ### Deleting Versions To delete a version: 1. Click the **⋮** menu on a version card 2. Select **Edit Version** 3. Click **Delete Version** 4. Confirm the deletion Deleting a version permanently removes: * All languages in that version * All translation data * Version history and metadata * Version schema This action cannot be undone. ## Working with Versions ### Version Workflow A typical version workflow might look like: ```mermaid graph LR A[1.0.0] --> B[1.1.0] B --> C[1.2.0] A --> D[1.0.1] B --> E[2.0.0-beta] E --> F[2.0.0] ``` 1. **Start with base version**: `1.0.0` with core translations 2. **Create feature versions**: `1.1.0` with new features 3. **Maintain patches**: `1.0.1` for critical fixes 4. **Develop major versions**: `2.0.0-beta` for major changes Version are not connected between each other. They are independent units that can be used for different purposes. ### Version Limits Each workspace has limits on versions per namespace: * **Free Plan**: 5 versions per namespace * **Pro Plan**: 20 versions per namespace * **Enterprise**: Custom quotas Monitor your version usage in the namespace header. When approaching limits, consider cleaning up old versions or upgrading your plan. ## Troubleshooting * **Problem**: * Cannot create new versions due to workspace limits. * **Solutions**: * Delete unused old versions * Upgrade workspace plan * **Problem**: * Version name already exists. * **Solutions**: * Use different naming convention * Add suffix like `-v2` or `-new` * Delete conflicting version if no longer needed * Use semantic versioning to avoid conflicts * **Problem**: * Not all translations copied to new version. * **Solutions**: * Ensure source version has all expected languages * Check if copy operation completed successfully * Verify workspace permissions * Copy individual languages manually if needed * **Problem**: * API returns error for version. * **Solutions**: * Verify version exists in namespace * Check version name spelling * Ensure API key has access to namespace ## Next Steps Understand how to publish versions as releases Deep dive into translation management # i18next Source: https://docs.unlingo.com/integrations/i18next Integrate Unlingo with React applications using i18next for powerful internationalization ## Overview This guide shows how to integrate Unlingo with React applications using i18next, one of the most popular internationalization frameworks. You'll learn how to set up a custom backend that fetches translations from Unlingo and integrates seamlessly with i18next. ## Prerequisites * React application * Basic knowledge of React hooks * An Unlingo project with translations ## Installation Install the required dependencies: ```bash npm npm install i18next react-i18next ``` ```bash yarn yarn add i18next react-i18next ``` ```bash pnpm pnpm add i18next react-i18next ``` ## Setting Up the Unlingo Backend Create a custom i18next backend that fetches translations from Unlingo: ```javascript unlingo-backend.js class UnlingoBackend { constructor() { this.type = 'backend'; // You can add own options if needed this.init(); } init() {} async read(language, namespace, callback) { try { const url = new URL('/v1/translations', 'https://api.unlingo.com'); url.searchParams.set('release', process.env.UNLINGO_RELEASE_TAG); url.searchParams.set('namespace', namespace); url.searchParams.set('lang', language); const response = await fetch(url.toString(), { method: 'GET', headers: { 'x-api-key': process.env.UNLINGO_API_KEY, 'Content-Type': 'application/json', }, }); if (!response.ok) { const errorData = await response.json().catch(() => ({})); return callback(new Error(`HTTP ${response.status}: ${errorData.error || response.statusText}`), null); } const data = await response.json(); callback(null, data); } catch (error) { console.error('Unlingo Backend Error:', error); callback(error, null); } } } export default UnlingoBackend; ``` ```typescript unlingo-backend.ts import { BackendModule, ReadCallback } from 'i18next'; class UnlingoBackend implements BackendModule { static type = 'backend' as const; type = 'backend' as const; constructor() { // You can add own options if needed this.init(); } init() {} async read(language: string, namespace: string, callback: ReadCallback) { try { const url = new URL('/v1/translations', 'https://api.unlingo.com'); url.searchParams.set('release', process.env.UNLINGO_RELEASE_TAG); url.searchParams.set('namespace', namespace); url.searchParams.set('lang', language); const response = await fetch(url.toString(), { method: 'GET', headers: { 'x-api-key': process.env.UNLINGO_API_KEY, 'Content-Type': 'application/json', }, }); if (!response.ok) { const errorData = await response.json().catch(() => ({})); return callback(new Error(`HTTP ${response.status}: ${errorData.error || response.statusText}`), null); } const data = await response.json(); callback(null, data); } catch (error) { console.error('Unlingo Backend Error:', error); callback(error as Error, null); } } } export default UnlingoBackend; ``` ## Configuring i18next Set up i18next with the Unlingo backend: ```javascript i18n.js import i18next from 'i18next'; import { initReactI18next } from 'react-i18next'; import UnlingoBackend from './unlingo-backend'; i18next.use(UnlingoBackend).use(initReactI18next).init({ lng: 'en', fallbackLng: 'en', }); export default i18next; ``` ```typescript i18n.ts import i18next from 'i18next'; import { initReactI18next } from 'react-i18next'; import UnlingoBackend from './unlingo-backend'; i18next.use(UnlingoBackend).use(initReactI18next).init({ lng: 'en', fallbackLng: 'en', }); export default i18next; ``` ## Environment Variables Add your Unlingo credentials to your environment file: ```env .env.local UNLINGO_API_KEY=your_api_key_here UNLINGO_RELEASE_TAG=1.0.0 ``` ## Initializing in Your App Import and initialize i18next in your main App component: ```javascript App.js import React, { Suspense } from 'react'; import './i18n'; // Import i18n configuration import MainApp from './MainApp'; function App() { return ( Loading translations...}> ); } export default App; ``` ```typescript App.tsx import React, { Suspense } from 'react'; import './i18n'; import MainApp from './MainApp'; const App: React.FC = () => { return ( Loading translations...}> ); }; export default App; ``` ## Next Steps Integrate applications with next-intl Explore the API reference # next-intl Source: https://docs.unlingo.com/integrations/next-intl Integrate Unlingo with Next.js applications using next-intl ## Overview This guide shows how to integrate Unlingo with Next.js applications using next-intl. ## Prerequisites * Next.js 13+ application * Basic knowledge of Next.js * An Unlingo project with translations ## Installation Install the required dependencies: ```bash npm npm install next-intl ``` ```bash yarn yarn add next-intl ``` ```bash pnpm pnpm add next-intl ``` ## Project Structure Set up your Next.js project structure for internationalization: ``` src/ ├── app/ │ ├── [locale]/ │ │ ├── layout.tsx │ │ ├── page.tsx │ │ └── dashboard/ │ │ └── page.tsx │ └── layout.tsx ├── i18n/ │ ├── request.ts │ └── routing.ts └── middleware.ts ``` ## Routing Configuration Configure your locales and routing: ```typescript i18n/routing.ts import { defineRouting } from 'next-intl/routing'; export const routing = defineRouting({ // A list of all locales that are supported locales: ['en', 'es', 'fr', 'de'], // Used when no locale matches defaultLocale: 'en', }); ``` ```javascript i18n/routing.js import { defineRouting } from 'next-intl/routing'; export const routing = defineRouting({ // A list of all locales that are supported locales: ['en', 'es', 'fr', 'de'], // Used when no locale matches defaultLocale: 'en', }); ``` ## Request Configuration Create a request configuration that fetches translations from Unlingo: ```typescript i18n/request.ts import { getRequestConfig } from 'next-intl/server'; import { hasLocale } from 'next-intl'; import { routing } from './routing'; export default getRequestConfig(async ({ requestLocale }) => { // This typically corresponds to the `[locale]` segment const requested = await requestLocale; const locale = hasLocale(routing.locales, requested) ? requested : routing.defaultLocale; try { // Fetch translations from Unlingo const url = new URL('/v1/translations', 'https://api.unlingo.com'); url.searchParams.set('release', process.env.UNLINGO_RELEASE_TAG); url.searchParams.set('namespace', process.env.UNLINGO_NAMESPACE); url.searchParams.set('lang', locale); const response = await fetch(url.toString(), { method: 'GET', headers: { Authorization: `Bearer ${process.env.UNLINGO_API_KEY}`, 'Content-Type': 'application/json', }, // Cache for 5 minutes next: { revalidate: 300 }, }); if (!response.ok) { throw new Error(`HTTP ${response.status}: ${response.statusText}`); } const messages = await response.json(); return { locale, messages, }; } catch (error) { console.error('Failed to load translations:', error); // Fallback to empty messages or default translations return { locale, messages: {}, }; } }); ``` ```javascript i18n/request.js import { getRequestConfig } from 'next-intl/server'; import { hasLocale } from 'next-intl'; import { routing } from './routing'; export default getRequestConfig(async ({ requestLocale }) => { const requested = await requestLocale; const locale = hasLocale(routing.locales, requested) ? requested : routing.defaultLocale; try { // Fetch translations from Unlingo const url = new URL('/v1/translations', 'https://api.unlingo.com'); url.searchParams.set('release', process.env.UNLINGO_RELEASE_TAG); url.searchParams.set('namespace', process.env.UNLINGO_NAMESPACE); url.searchParams.set('lang', locale); const response = await fetch(url.toString(), { method: 'GET', headers: { Authorization: `Bearer ${process.env.UNLINGO_API_KEY}`, 'Content-Type': 'application/json', }, // Cache for 5 minutes next: { revalidate: 300 }, }); if (!response.ok) { throw new Error(`HTTP ${response.status}: ${response.statusText}`); } const messages = await response.json(); return { locale, messages, }; } catch (error) { console.error('Failed to load translations:', error); return { locale, messages: {}, }; } }); ``` ## Environment Variables Add your Unlingo credentials to your environment file: ```env .env.local UNLINGO_API_KEY=your_api_key_here UNLINGO_RELEASE_TAG=1.0.0 UNLINGO_NAMESPACE=translation ``` ## Middleware Configuration Set up middleware to handle locale detection and routing: ```typescript middleware.ts import createMiddleware from 'next-intl/middleware'; import { routing } from './src/i18n/routing'; export default createMiddleware(routing); export const config = { // Match only internationalized pathnames matcher: ['/', '/(de|en|es|fr)/:path*'], }; ``` ```javascript middleware.js import createMiddleware from 'next-intl/middleware'; import { routing } from './src/i18n/routing'; export default createMiddleware(routing); export const config = { // Match only internationalized pathnames matcher: ['/', '/(de|en|es|fr)/:path*'], }; ``` ## Next.js Configuration Update your `next.config.js` to include the internationalization plugin: ```javascript next.config.js const withNextIntl = require('next-intl/plugin')( // This is the default (also the `src` folder is supported out of the box) './src/i18n/request.ts' ); module.exports = withNextIntl({ // Other Next.js configuration }); ``` ```typescript next.config.ts import withNextIntl from 'next-intl/plugin'; const withNextIntlConfig = withNextIntl('./src/i18n/request.ts'); export default withNextIntlConfig({ // Other Next.js configuration }); ``` ## Root Layout Set up the root layout: ```typescript src/app/layout.tsx import { ReactNode } from 'react'; type Props = { children: ReactNode; }; // Since we have a `not-found.tsx` page on the root, a layout file // is required, even if it's just passing children through. export default function RootLayout({ children }: Props) { return children; } ``` ```javascript src/app/layout.js // Since we have a `not-found.tsx` page on the root, a layout file // is required, even if it's just passing children through. export default function RootLayout({ children }) { return children; } ``` ## Locale Layout Create a layout for your localized pages: ```typescript src/app/[locale]/layout.tsx import { NextIntlClientProvider } from 'next-intl'; import { getMessages } from 'next-intl/server'; import { notFound } from 'next/navigation'; import { routing } from '@/i18n/routing'; export default async function LocaleLayout({ children, params: { locale } }: { children: React.ReactNode; params: { locale: string }; }) { // Ensure that the incoming `locale` is valid if (!routing.locales.includes(locale as any)) { notFound(); } // Providing all messages to the client // side is the easiest way to get started const messages = await getMessages(); return ( {children} ); } ``` ```javascript src/app/[locale]/layout.js import { NextIntlClientProvider } from 'next-intl'; import { getMessages } from 'next-intl/server'; import { notFound } from 'next/navigation'; import { routing } from '@/i18n/routing'; export default async function LocaleLayout({ children, params: { locale } }) { // Ensure that the incoming `locale` is valid if (!routing.locales.includes(locale)) { notFound(); } // Providing all messages to the client // side is the easiest way to get started const messages = await getMessages(); return ( {children} ); } ``` ## Using Translations in Server Components ### Basic Usage ```typescript src/app/[locale]/page.tsx import { getTranslations } from 'next-intl/server'; export default async function HomePage() { const t = await getTranslations('common'); return (

{t('welcome')}

{t('description')}

); } ``` ```javascript src/app/[locale]/page.js import { getTranslations } from 'next-intl/server'; export default async function HomePage() { const t = await getTranslations('common'); return (

{t('welcome')}

{t('description')}

); } ```
### With Interpolation ```typescript import { getTranslations } from 'next-intl/server'; export default async function UserPage({ params }: { params: { userId: string } }) { const t = await getTranslations('user'); const user = await getUserById(params.userId); return (

{t('greeting', { name: user.name })}

{t('lastSeen', { date: new Date(user.lastSeen) })}

); } ``` ## Using Translations in Client Components For client components, use the `useTranslations` hook: ```typescript components/LanguageSwitcher.tsx 'use client'; import { useLocale, useTranslations } from 'next-intl'; import { useRouter } from 'next/navigation'; export default function LanguageSwitcher() { const t = useTranslations('common'); const locale = useLocale(); const router = useRouter(); const languages = [ { code: 'en', name: 'English' }, { code: 'es', name: 'Español' }, { code: 'fr', name: 'Français' }, { code: 'de', name: 'Deutsch' } ]; const changeLanguage = (newLocale: string) => { router.push(`/${newLocale}`); }; return (
); } ``` ```javascript components/LanguageSwitcher.js 'use client'; import { useLocale, useTranslations } from 'next-intl'; import { useRouter } from 'next/navigation'; export default function LanguageSwitcher() { const t = useTranslations('common'); const locale = useLocale(); const router = useRouter(); const languages = [ { code: 'en', name: 'English' }, { code: 'es', name: 'Español' }, { code: 'fr', name: 'Français' }, { code: 'de', name: 'Deutsch' }, ]; const changeLanguage = newLocale => { router.push(`/${newLocale}`); }; return (
); } ```
## Advanced Features ### Multiple Namespaces Configure multiple namespaces in your request configuration: ```typescript // Enhanced i18n/request.ts export default getRequestConfig(async ({ requestLocale }) => { const requested = await requestLocale; const locale = hasLocale(routing.locales, requested) ? requested : routing.defaultLocale; const namespaces = ['common', 'navigation', 'dashboard', 'auth']; const messages = {}; // Fetch all namespaces in parallel await Promise.all( namespaces.map(async namespace => { try { const url = new URL('/v1/translations', 'https://api.unlingo.com'); url.searchParams.set('release', process.env.UNLINGO_RELEASE_TAG); url.searchParams.set('namespace', namespace); url.searchParams.set('lang', locale); const response = await fetch(url.toString(), { method: 'GET', headers: { Authorization: `Bearer ${process.env.UNLINGO_API_KEY}`, 'Content-Type': 'application/json', }, next: { revalidate: 300 }, }); if (response.ok) { const namespaceMessages = await response.json(); messages[namespace] = namespaceMessages; } } catch (error) { console.error(`Failed to load ${namespace} namespace:`, error); messages[namespace] = {}; } }) ); return { locale, messages, }; }); ``` ## Next Steps Integrate applications using i18next Explore the API reference # Introduction Source: https://docs.unlingo.com/introduction Welcome to Unlingo - The modern translation management platform for developers Hero ## What is Unlingo? Unlingo is a modern, developer-friendly translation management platform designed to simplify internationalization for web and mobile applications. Built with performance and developer experience in mind, Unlingo provides a seamless way to manage, deliver, and scale your application's translations globally. ## Key Features Instantly propagates translation keys across all languages when you edit the primary language Simple, intuitive API that developers love to work with Maintain multiple versions of your translations Smart caching system that optimizes performance automatically ## How It Works Unlingo follows a simple, intuitive workflow: 1. **Create Projects & Namespaces**: Organize your translations into logical groups 2. **Upload Translations**: Add your translation keys and values through our dashboard 3. **Create Releases**: Package your translations into versioned releases 4. **Integrate**: Use our API to fetch translations in your application 5. **Enjoy**: Your translations are automatically distributed Unlingo is designed to work with your existing translation workflow. You can import existing translations and start using the platform immediately. ## Community & Support Join our Discord server for real-time help and community discussions Get in touch with our support team for any questions or issues ## What's Next? Set up your first project and start translating Explore our API documentation # Quickstart Source: https://docs.unlingo.com/quickstart Get started with Unlingo in under 5 minutes ## Overview This quickstart guide will help you set up Unlingo and integrate it into your application in just a few minutes. We'll create a project, add some translations, and fetch them using our REST API. ## Prerequisites * An Unlingo account (sign up at [unlingo.com](https://unlingo.com/sign-up)) * Basic knowledge of REST APIs * A web or mobile application project ## Step 1: Create Your Project Navigate to [unlingo.com](https://unlingo.com/sign-in) and sign in to your account. Click **Create Project** and enter your project details. Within your project, create a namespace: - **Name**: "translation" (you can use any name but i18next uses "translation" by default) ## Step 2: Add New Language Navigate to your namespace Select `main` version Click **Add language** and enter the language code (e.g., `en`) ## Step 3: Add Translations Click on the language card Click **JSON Mode** Paste your translations in JSON format ```json { "welcome": "Welcome to our application", "login": "Sign In", "logout": "Sign Out", "nav": { "home": "Home", "about": "About", "contact": "Contact" } } ``` Click **Apply Changes** and Click **Save Changes** in top right corner ## Step 4: Create Your First Release Go to the **Releases** tab in your project dashboard Click **Create Release** and enter: - **Tag**: "1.0.0". Select your `translation` namespace and `main` version Click **Create Release** to make it available via the API ## Step 4: Get Your API Key Go to the **API Keys** tab in your project dashboard Click **Generate Key** and give it a name like **Production API Key** Copy the generated API key - you'll need it for the next step Save your key somewhere safe because it will not be shown again. ## Step 5: Fetch Translations Now you can fetch your translations using our API: ```bash cURL curl -X GET "https://api.unlingo.com/v1/translations?tag=1.0.0&namespace=translation&lang=en" \ -H "Authorization: Bearer YOUR_API_KEY" ``` ```javascript JavaScript/Fetch const response = await fetch('https://api.unlingo.com/v1/translations?tag=1.0.0&namespace=translation&lang=en', { headers: { Authorization: 'Bearer YOUR_API_KEY', }, }); const translations = await response.json(); console.log(translations); ``` Expected response: ```json { "translation": { "welcome": "Welcome to our application", "login": "Sign In", "logout": "Sign Out", "nav": { "home": "Home", "about": "About", "contact": "Contact" } } } ``` ## Common Patterns ### Environment-Based Tags Use different tags for different environments: ```javascript const tag = process.env.NODE_ENV === 'production' ? '1.0.0' : 'staging'; const translations = await fetch(`https://api.unlingo.com/v1/translations?tag=${tag}&namespace=translation&lang=en`, { headers: { Authorization: `Bearer ${process.env.UNLINGO_API_KEY}`, }, }); ``` ## Troubleshooting Make sure your API key is correct. Check that you're using the correct project ID. **Verify that:** * Your release is published * The version, namespace, and language parameters are correct * Your translations were saved properly in the dashboard Need help? Join our [Discord](https://discord.gg/TdDYte7KjG) for community support. ## Next Steps Understand projects Organize your translations within projects using namespaces Understand the relationship between versions and releases Deep dive into translation management