mix ash_phoenix_translations.install (ash_phoenix_translations v1.0.0)
View SourceInstalls AshPhoenixTranslations into your Phoenix application.
This task automates the initial setup process for AshPhoenixTranslations, configuring your application, creating necessary files, and generating example resources to help you get started quickly.
Features
- Backend Selection: Choose between Database or Gettext backend
- Configuration Generation: Automatic config.exs setup
- Migration Creation: Database backend migration generation
- Gettext Setup: Complete Gettext directory structure
- Example Resource: Working example to learn from
- Interactive Installation: Step-by-step guidance
Basic Usage
# Install with database backend (default)
mix ash_phoenix_translations.install
# Install with gettext backend
mix ash_phoenix_translations.install --backend gettext
# Install without modifying config
mix ash_phoenix_translations.install --no-config
# Skip migration generation
mix ash_phoenix_translations.install --no-migrationOptions
--backend- The default backend to use (database, gettext). Default: database--no-config- Skip config file modifications--no-gettext- Skip Gettext setup even if selected as backend--no-migration- Skip migration generation for database backend
Installation Steps
1. Configuration
Adds the following to config/config.exs:
config :ash_phoenix_translations,
default_backend: :database,
default_locales: [:en, :es, :fr],
cache_ttl: 3600,
cache_backend: :ets2. Backend-Specific Setup
Database Backend
Creates a migration file in priv/repo/migrations/:
defmodule Repo.Migrations.CreateTranslationsTable do
use Ecto.Migration
def change do
create table(:translations) do
add :resource_type, :string, null: false
add :resource_id, :uuid, null: false
add :field, :string, null: false
add :locale, :string, null: false
add :value, :text
add :metadata, :map, default: %{}
timestamps()
end
create index(:translations, [:resource_type, :resource_id])
create index(:translations, [:locale])
create unique_index(:translations,
[:resource_type, :resource_id, :field, :locale])
end
endAfter installation, run:
mix ecto.migrateGettext Backend
Creates the following directory structure in priv/gettext/:
priv/gettext/
├── en/
│ └── LC_MESSAGES/
│ └── translations.po
├── es/
│ └── LC_MESSAGES/
│ └── translations.po
└── fr/
└── LC_MESSAGES/
└── translations.poAfter installation, extract and compile translations:
mix ash_phoenix_translations.extract
mix gettext.merge priv/gettext
mix compile.gettext3. Example Resource
Creates lib/example/product.ex with a working example:
defmodule Example.Product do
use Ash.Resource,
extensions: [AshPhoenixTranslations]
translations do
translatable_attribute :name,
locales: [:en, :es, :fr],
required: [:en]
translatable_attribute :description,
locales: [:en, :es, :fr],
translate: true
backend :database
cache_ttl 7200
end
attributes do
uuid_primary_key :id
attribute :sku, :string
attribute :price, :decimal
timestamps()
end
actions do
defaults [:create, :read, :update, :destroy]
end
endPost-Installation Setup
1. Add Extension to Your Resources
defmodule MyApp.Shop.Product do
use Ash.Resource,
extensions: [AshPhoenixTranslations]
translations do
translatable_attribute :name, locales: [:en, :es, :fr]
translatable_attribute :description, locales: [:en, :es, :fr]
backend :database
end
end2. Configure Router Plugs
Add to your Phoenix router:
pipeline :browser do
# ... other plugs
plug AshPhoenixTranslations.Plugs.SetLocale
plug AshPhoenixTranslations.Plugs.LoadTranslations
end3. Import Helpers in Views
In your MyAppWeb module:
def html do
quote do
# ... other imports
import AshPhoenixTranslations.Helpers
end
end4. Use in Templates
# Access translated attributes
<%= t(@product, :name) %>
<%= t(@product, :description) %>
# Locale selector
<%= locale_select(@conn, [:en, :es, :fr]) %>
# Get all translations for a field
<%= all_translations(@product, :name) %>Workflow Examples
New Project Setup
# 1. Install with database backend
mix ash_phoenix_translations.install --backend database
# 2. Run migration
mix ecto.migrate
# 3. Add to your first resource
# Edit lib/my_app/shop/product.ex and add translations block
# 4. Start your application
mix phx.serverAdding to Existing Project
# 1. Install without modifying config (you'll configure manually)
mix ash_phoenix_translations.install --no-config
# 2. Review generated files
# - Check migration file
# - Review example resource
# 3. Manually add configuration to config/config.exs
# 4. Add plugs to router.ex
# 5. Import helpers in your view moduleGettext-Based Project
# 1. Install with Gettext backend
mix ash_phoenix_translations.install --backend gettext
# 2. Extract strings from resources
mix ash_phoenix_translations.extract
# 3. Merge with existing Gettext files
mix gettext.merge priv/gettext
# 4. Translate .po files
# Edit priv/gettext/*/LC_MESSAGES/translations.po
# 5. Compile translations
mix compile.gettextConfiguration Options
Default Configuration
The installer creates this configuration:
config :ash_phoenix_translations,
default_backend: :database, # or :gettext
default_locales: [:en, :es, :fr], # Your supported locales
cache_ttl: 3600, # 1 hour cache
cache_backend: :ets # ETS-based cachingAdvanced Configuration
You can extend the configuration after installation:
config :ash_phoenix_translations,
default_backend: :database,
default_locales: [:en, :es, :fr, :de, :it],
cache_ttl: 7200,
cache_backend: :ets,
# Fallback chain
fallback_chain: [:es, :en],
# Security
supported_locales: [:en, :es, :fr, :de, :it],
# Performance
lazy_load: true,
preload_translations: falseBackend Comparison
Database Backend
Pros:
- Dynamic translation updates without deployment
- Audit trail with timestamps
- Per-resource translation storage
- Ideal for user-editable content
Cons:
- Additional database queries
- Requires migration
- More storage usage
Best For:
- E-commerce product catalogs
- CMS content
- User-generated content
- Applications requiring frequent translation updates
Gettext Backend
Pros:
- Compiled translations (fast runtime)
- Standard .po file format
- Integrates with existing Gettext tools
- CAT tool compatible
Cons:
- Requires recompilation for updates
- Less dynamic
- Not per-resource
Best For:
- Static content
- UI labels and messages
- Applications with stable translations
- Integration with professional translation workflows
Troubleshooting
Configuration Not Applied
Problem: Configuration doesn't seem to take effect
Solution:
- Restart your application after installation
- Check
config/config.exsfor syntax errors - Ensure configuration is not overridden in environment-specific configs
Migration Fails
Problem: Database migration fails to run
Solution:
- Check PostgreSQL version (JSONB requires 9.4+)
- Verify database connection in
config/dev.exs - Check for table name conflicts
- Ensure migrations directory exists
Gettext Files Not Created
Problem: priv/gettext/ directory not created
Solution:
- Ensure
--no-gettextflag was not used - Check directory permissions
- Manually create directory structure if needed
Example Resource Conflicts
Problem: Example resource causes compilation errors
Solution:
- Delete
lib/example/product.exif not needed - Rename the module to avoid conflicts
- Use it as a reference, then remove
Security Considerations
Atom Exhaustion Prevention
The installer configures locale validation to prevent atom exhaustion:
# In config/config.exs (generated)
config :ash_phoenix_translations,
supported_locales: [:en, :es, :fr] # Whitelist onlyOnly these locales can be converted to atoms, preventing malicious input from exhausting the atom table.
Database Security
The generated migration includes:
- NOT NULL constraints: Prevent incomplete records
- Unique indexes: Prevent duplicate translations
- JSONB type: Secure JSON storage (PostgreSQL)
Related Tasks
After installation, you'll commonly use:
mix ash_phoenix_translations.export- Export translations to filesmix ash_phoenix_translations.import- Import translations from filesmix ash_phoenix_translations.validate- Validate translation completenessmix ash_phoenix_translations.extract- Extract to Gettext POT files
Examples
Full Database Backend Setup
# Install
mix ash_phoenix_translations.install --backend database
# Run migration
mix ecto.migrate
# Add to resource
# lib/my_app/shop/product.ex
defmodule MyApp.Shop.Product do
use Ash.Resource,
extensions: [AshPhoenixTranslations]
translations do
translatable_attribute :name, locales: [:en, :es, :fr]
backend :database
end
end
# Test in IEx
iex -S mix
iex> alias MyApp.Shop.Product
iex> product = Product.create!(%{name_translations: %{en: "Coffee", es: "Café"}})
iex> AshPhoenixTranslations.translate(product, :name, :es)
"Café"Full Gettext Backend Setup
# Install
mix ash_phoenix_translations.install --backend gettext
# Extract strings
mix ash_phoenix_translations.extract
# Merge and edit
mix gettext.merge priv/gettext
# Edit priv/gettext/es/LC_MESSAGES/translations.po
# Compile
mix compile.gettext
# Test
iex -S mix
iex> AshPhoenixTranslations.translate(product, :name, :es)
"Café"Minimal Installation
# Skip everything except example
mix ash_phoenix_translations.install --no-config --no-migration --no-gettext
# Review the example resource
cat lib/example/product.ex
# Manually configure as needed
Summary
Functions
Callback implementation for Mix.Task.run/1.
Functions
Callback implementation for Mix.Task.run/1.