internationalize 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/context/configuration.md +83 -0
- data/context/getting-started.md +98 -0
- data/context/index.yaml +14 -0
- data/context/model-api.md +101 -0
- data/context/query-api.md +129 -0
- data/lib/internationalize/version.rb +1 -1
- metadata +6 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3f85c4969fc4c969bf8ad61c4cbdb76a5364c90b4c7853a446aaeb6a4ac629ff
|
|
4
|
+
data.tar.gz: 83c19c5597f26d23634cc37f3aaede5d7a58c62460c6a2cd5295a1d3e43c3017
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 02037bac922bbd2e7a7ccf82399e5892436a32f02970c87365935745ebc2858b16b4befbf11b26a9e70e54833ae0347a3d45a8450c839a95d93111dc92109035
|
|
7
|
+
data.tar.gz: 7dced1dca63327c7e66c527be390ac39bff028615f10696094b545514573000a52962fdbd807a77e7bb823b4c6151c56284b075e18be37bbea36d4140e10450d
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# Internationalize: Configuration
|
|
2
|
+
|
|
3
|
+
## Global Configuration
|
|
4
|
+
|
|
5
|
+
```ruby
|
|
6
|
+
# config/initializers/internationalize.rb
|
|
7
|
+
Internationalize.configure do |config|
|
|
8
|
+
# Override fallback locale (defaults to I18n.default_locale)
|
|
9
|
+
config.fallback_locale = :en
|
|
10
|
+
|
|
11
|
+
# Override available locales (defaults to I18n.available_locales)
|
|
12
|
+
config.available_locales = [:en, :de, :fr, :es]
|
|
13
|
+
end
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Per-Attribute Configuration
|
|
17
|
+
|
|
18
|
+
```ruby
|
|
19
|
+
class Article < ApplicationRecord
|
|
20
|
+
include Internationalize::Model
|
|
21
|
+
|
|
22
|
+
# With fallback (default)
|
|
23
|
+
international :title
|
|
24
|
+
|
|
25
|
+
# Without fallback
|
|
26
|
+
international :description, fallback: false
|
|
27
|
+
end
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Database Setup
|
|
31
|
+
|
|
32
|
+
Use the generator to create migrations:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
rails generate internationalize:translation Article title description
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Or create migrations manually:
|
|
39
|
+
|
|
40
|
+
### SQLite / MySQL
|
|
41
|
+
|
|
42
|
+
```ruby
|
|
43
|
+
class AddTranslationsToArticles < ActiveRecord::Migration[7.1]
|
|
44
|
+
def change
|
|
45
|
+
add_column :articles, :title_translations, :json, default: {}
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### PostgreSQL
|
|
51
|
+
|
|
52
|
+
For better query performance, use `jsonb`:
|
|
53
|
+
|
|
54
|
+
```ruby
|
|
55
|
+
class AddTranslationsToArticles < ActiveRecord::Migration[7.1]
|
|
56
|
+
def change
|
|
57
|
+
add_column :articles, :title_translations, :jsonb, default: {}
|
|
58
|
+
|
|
59
|
+
# Optional: Add GIN index for faster queries
|
|
60
|
+
add_index :articles, :title_translations, using: :gin
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Supported Databases
|
|
66
|
+
|
|
67
|
+
| Database | Minimum Version | JSON Type | Query Syntax |
|
|
68
|
+
|----------|-----------------|-----------|--------------|
|
|
69
|
+
| SQLite | 3.38+ | `json` | `json_extract()` |
|
|
70
|
+
| PostgreSQL | 9.4+ | `json`/`jsonb` | `->>` operator |
|
|
71
|
+
| MySQL | 8.0+ | `json` | `->>` operator |
|
|
72
|
+
|
|
73
|
+
## I18n Integration
|
|
74
|
+
|
|
75
|
+
Internationalize automatically uses Rails I18n settings:
|
|
76
|
+
|
|
77
|
+
```ruby
|
|
78
|
+
I18n.locale # Used for current locale
|
|
79
|
+
I18n.default_locale # Used for fallbacks
|
|
80
|
+
I18n.available_locales # Used for locale-specific accessors
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Override these with the configuration options above if needed.
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# Internationalize: Getting Started
|
|
2
|
+
|
|
3
|
+
Internationalize is a lightweight internationalization gem for Rails that stores translations in JSON columns instead of separate tables.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```ruby
|
|
8
|
+
# Gemfile
|
|
9
|
+
gem "internationalize"
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## Quick Setup
|
|
13
|
+
|
|
14
|
+
### 1. Generate a migration for translation columns
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
rails generate internationalize:translation Article title description
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
This creates a migration adding `title_translations` and `description_translations` JSON columns.
|
|
21
|
+
|
|
22
|
+
Or write the migration manually:
|
|
23
|
+
|
|
24
|
+
```ruby
|
|
25
|
+
class AddTranslationsToArticles < ActiveRecord::Migration[7.1]
|
|
26
|
+
def change
|
|
27
|
+
add_column :articles, :title_translations, :json, default: {}
|
|
28
|
+
add_column :articles, :description_translations, :json, default: {}
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### 2. Include the mixin and declare translatable attributes
|
|
34
|
+
|
|
35
|
+
```ruby
|
|
36
|
+
class Article < ApplicationRecord
|
|
37
|
+
include Internationalize::Model
|
|
38
|
+
international :title, :description
|
|
39
|
+
end
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### 3. Use translations
|
|
43
|
+
|
|
44
|
+
```ruby
|
|
45
|
+
# Create with translations (hash for multiple locales)
|
|
46
|
+
Article.international_create!(
|
|
47
|
+
title: { en: "Hello World", de: "Hallo Welt" },
|
|
48
|
+
status: "published"
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
# Or direct string for current locale
|
|
52
|
+
I18n.locale = :de
|
|
53
|
+
Article.international_create!(title: "Achtung!") # Sets title_de
|
|
54
|
+
|
|
55
|
+
# Set translation for current locale
|
|
56
|
+
article.title = "Hello World"
|
|
57
|
+
|
|
58
|
+
# Set for specific locale
|
|
59
|
+
article.title_en = "Hello World"
|
|
60
|
+
article.title_de = "Hallo Welt"
|
|
61
|
+
|
|
62
|
+
# Read translation
|
|
63
|
+
article.title # => uses I18n.locale
|
|
64
|
+
article.title_de # => "Hallo Welt"
|
|
65
|
+
|
|
66
|
+
# Access raw hash
|
|
67
|
+
article.title_translations # => {"en" => "Hello World", "de" => "Hallo Welt"}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### 4. Query translations
|
|
71
|
+
|
|
72
|
+
```ruby
|
|
73
|
+
# Exact match
|
|
74
|
+
Article.international(title: "Hello World")
|
|
75
|
+
|
|
76
|
+
# Partial match (LIKE)
|
|
77
|
+
Article.international(title: "Hello", match: :partial)
|
|
78
|
+
|
|
79
|
+
# Order by translation
|
|
80
|
+
Article.international_order(:title, :desc)
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Key Concepts
|
|
84
|
+
|
|
85
|
+
- Translations stored in `*_translations` JSON columns
|
|
86
|
+
- No JOINs - data lives in the same table
|
|
87
|
+
- Automatic fallback to default locale
|
|
88
|
+
- Works with SQLite, PostgreSQL, and MySQL
|
|
89
|
+
|
|
90
|
+
## Important: Column Defaults
|
|
91
|
+
|
|
92
|
+
JSON columns **must** have `default: {}` set in the migration. The generator does this automatically, but if writing migrations manually, ensure you include it:
|
|
93
|
+
|
|
94
|
+
```ruby
|
|
95
|
+
add_column :articles, :title_translations, :json, default: {}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
This is required for optimal performance and correct behavior.
|
data/context/index.yaml
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
description: "Lightweight, performant internationalization for Rails using JSON columns"
|
|
2
|
+
files:
|
|
3
|
+
- path: getting-started.md
|
|
4
|
+
title: "Getting Started"
|
|
5
|
+
description: "Quick setup guide for Internationalize"
|
|
6
|
+
- path: model-api.md
|
|
7
|
+
title: "Model API"
|
|
8
|
+
description: "Model mixin methods and generated accessors"
|
|
9
|
+
- path: query-api.md
|
|
10
|
+
title: "Query API"
|
|
11
|
+
description: "Query methods for searching and filtering translations"
|
|
12
|
+
- path: configuration.md
|
|
13
|
+
title: "Configuration"
|
|
14
|
+
description: "Global and per-attribute configuration options"
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# Internationalize: Model API
|
|
2
|
+
|
|
3
|
+
## Including the Mixin
|
|
4
|
+
|
|
5
|
+
```ruby
|
|
6
|
+
class Article < ApplicationRecord
|
|
7
|
+
include Internationalize::Model
|
|
8
|
+
international :title, :description
|
|
9
|
+
end
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## Options
|
|
13
|
+
|
|
14
|
+
```ruby
|
|
15
|
+
# With fallback (default: true)
|
|
16
|
+
international :title, fallback: true
|
|
17
|
+
|
|
18
|
+
# Without fallback - returns nil if translation missing
|
|
19
|
+
international :title, fallback: false
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Generated Instance Methods
|
|
23
|
+
|
|
24
|
+
For each `international :title` declaration:
|
|
25
|
+
|
|
26
|
+
### Accessors
|
|
27
|
+
|
|
28
|
+
| Method | Description |
|
|
29
|
+
|--------|-------------|
|
|
30
|
+
| `title` | Get translation for current `I18n.locale` |
|
|
31
|
+
| `title=` | Set translation for current `I18n.locale` |
|
|
32
|
+
| `title?` | Check if translation exists |
|
|
33
|
+
| `title_translations` | Get raw hash of all translations |
|
|
34
|
+
| `title_translations=` | Set all translations at once |
|
|
35
|
+
|
|
36
|
+
### Locale-Specific Accessors
|
|
37
|
+
|
|
38
|
+
For each locale in `I18n.available_locales`:
|
|
39
|
+
|
|
40
|
+
| Method | Description |
|
|
41
|
+
|--------|-------------|
|
|
42
|
+
| `title_en` | Get English translation directly |
|
|
43
|
+
| `title_en=` | Set English translation |
|
|
44
|
+
| `title_en?` | Check if English translation exists |
|
|
45
|
+
| `title_de` | Get German translation |
|
|
46
|
+
| `title_de=` | Set German translation |
|
|
47
|
+
| ... | etc. for all locales |
|
|
48
|
+
|
|
49
|
+
### Instance Helper Methods
|
|
50
|
+
|
|
51
|
+
| Method | Description |
|
|
52
|
+
|--------|-------------|
|
|
53
|
+
| `set_translation(:title, :de, "Hallo")` | Set translation for attribute/locale |
|
|
54
|
+
| `translation_for(:title, :de)` | Get translation without fallback |
|
|
55
|
+
| `translated?(:title, :de)` | Check if translation exists |
|
|
56
|
+
| `translated_locales(:title)` | Array of locales with translations |
|
|
57
|
+
|
|
58
|
+
## Class Methods (Querying)
|
|
59
|
+
|
|
60
|
+
All query methods default to current `I18n.locale` and return `ActiveRecord::Relation`:
|
|
61
|
+
|
|
62
|
+
| Method | Description |
|
|
63
|
+
|--------|-------------|
|
|
64
|
+
| `international(**conditions, locale: nil)` | Exact match query |
|
|
65
|
+
| `international_not(**conditions, locale: nil)` | Exclude matching records |
|
|
66
|
+
| `international_search(**conditions, locale: nil, case_sensitive: false)` | Substring search |
|
|
67
|
+
| `international_order(attr, dir = :asc, locale: nil)` | Order by translation |
|
|
68
|
+
| `translated(*attrs, locale: nil)` | Find records with translation |
|
|
69
|
+
| `untranslated(*attrs, locale: nil)` | Find records missing translation |
|
|
70
|
+
|
|
71
|
+
```ruby
|
|
72
|
+
# Examples
|
|
73
|
+
Article.international(title: "Hello World")
|
|
74
|
+
Article.international_search(title: "hello", locale: :de)
|
|
75
|
+
Article.international_order(:title, :desc)
|
|
76
|
+
Article.translated(:title, locale: :de)
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Class Attributes
|
|
80
|
+
|
|
81
|
+
```ruby
|
|
82
|
+
Article.international_attributes # => [:title, :description]
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Fallback Behavior
|
|
86
|
+
|
|
87
|
+
When `fallback: true` (default):
|
|
88
|
+
|
|
89
|
+
```ruby
|
|
90
|
+
article.title_en = "Hello"
|
|
91
|
+
I18n.locale = :de
|
|
92
|
+
article.title # => "Hello" (falls back to default locale)
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
When `fallback: false`:
|
|
96
|
+
|
|
97
|
+
```ruby
|
|
98
|
+
article.title_en = "Hello"
|
|
99
|
+
I18n.locale = :de
|
|
100
|
+
article.title # => nil
|
|
101
|
+
```
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
# Internationalize: Query API
|
|
2
|
+
|
|
3
|
+
All query methods are class methods on models that include `Internationalize::Model`. They return `ActiveRecord::Relation` objects that can be chained with standard AR methods.
|
|
4
|
+
|
|
5
|
+
## Default Locale Behavior
|
|
6
|
+
|
|
7
|
+
All query methods default to the current `I18n.locale`. Use the `locale:` option to override:
|
|
8
|
+
|
|
9
|
+
```ruby
|
|
10
|
+
# Uses current I18n.locale
|
|
11
|
+
Article.international(title: "Hello World")
|
|
12
|
+
|
|
13
|
+
# Explicit locale
|
|
14
|
+
Article.international(title: "Hallo Welt", locale: :de)
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Query Methods
|
|
18
|
+
|
|
19
|
+
### international(**conditions, locale: nil)
|
|
20
|
+
|
|
21
|
+
Exact match on translated attributes:
|
|
22
|
+
|
|
23
|
+
```ruby
|
|
24
|
+
Article.international(title: "Hello World")
|
|
25
|
+
Article.international(title: "Hello", status: "published")
|
|
26
|
+
Article.international(title: "Hallo Welt", locale: :de)
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### international_not(**conditions, locale: nil)
|
|
30
|
+
|
|
31
|
+
Exclude records matching conditions:
|
|
32
|
+
|
|
33
|
+
```ruby
|
|
34
|
+
Article.international_not(title: "Draft")
|
|
35
|
+
Article.international_not(title: "Entwurf", locale: :de)
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### international_search(**conditions, locale: nil, case_sensitive: false)
|
|
39
|
+
|
|
40
|
+
Substring search (LIKE/ILIKE):
|
|
41
|
+
|
|
42
|
+
```ruby
|
|
43
|
+
# Case-insensitive (default)
|
|
44
|
+
Article.international_search(title: "hello")
|
|
45
|
+
Article.international_search(title: "hello", description: "world")
|
|
46
|
+
|
|
47
|
+
# Case-sensitive
|
|
48
|
+
Article.international_search(title: "Hello", case_sensitive: true)
|
|
49
|
+
|
|
50
|
+
# With explicit locale
|
|
51
|
+
Article.international_search(title: "welt", locale: :de)
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### international_order(attribute, direction = :asc, locale: nil)
|
|
55
|
+
|
|
56
|
+
Order by translated attribute:
|
|
57
|
+
|
|
58
|
+
```ruby
|
|
59
|
+
Article.international_order(:title)
|
|
60
|
+
Article.international_order(:title, :desc)
|
|
61
|
+
Article.international_order(:title, :asc, locale: :de)
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### translated(*attributes, locale: nil)
|
|
65
|
+
|
|
66
|
+
Find records with translations in specified locale:
|
|
67
|
+
|
|
68
|
+
```ruby
|
|
69
|
+
Article.translated(:title)
|
|
70
|
+
Article.translated(:title, locale: :de)
|
|
71
|
+
Article.translated(:title, :description, locale: :de)
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### untranslated(*attributes, locale: nil)
|
|
75
|
+
|
|
76
|
+
Find records missing translations:
|
|
77
|
+
|
|
78
|
+
```ruby
|
|
79
|
+
Article.untranslated(:title)
|
|
80
|
+
Article.untranslated(:title, locale: :de)
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Chaining with ActiveRecord
|
|
84
|
+
|
|
85
|
+
All methods return `ActiveRecord::Relation`, so they chain naturally with AR methods:
|
|
86
|
+
|
|
87
|
+
```ruby
|
|
88
|
+
Article.international(title: "Hello World")
|
|
89
|
+
.where(published: true)
|
|
90
|
+
.order(created_at: :desc)
|
|
91
|
+
.limit(10)
|
|
92
|
+
.includes(:author)
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Combining Multiple Queries
|
|
96
|
+
|
|
97
|
+
Use `merge` to combine multiple international queries:
|
|
98
|
+
|
|
99
|
+
```ruby
|
|
100
|
+
# Search + filter + order
|
|
101
|
+
Article.international_search(title: "hello")
|
|
102
|
+
.merge(Article.international(status: "published"))
|
|
103
|
+
.merge(Article.international_order(:title, :desc))
|
|
104
|
+
|
|
105
|
+
# Query across multiple locales
|
|
106
|
+
Article.international(title: "Hello World", locale: :en)
|
|
107
|
+
.merge(Article.international(title: "Hallo Welt", locale: :de))
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Examples
|
|
111
|
+
|
|
112
|
+
```ruby
|
|
113
|
+
# Find published articles with German title containing "Welt"
|
|
114
|
+
Article.international_search(title: "Welt", locale: :de)
|
|
115
|
+
.where(published: true)
|
|
116
|
+
.merge(Article.international_order(:title, locale: :de))
|
|
117
|
+
.limit(10)
|
|
118
|
+
|
|
119
|
+
# Find articles missing German translation
|
|
120
|
+
Article.untranslated(:title, locale: :de).count
|
|
121
|
+
|
|
122
|
+
# Complex multi-locale query - find articles with both EN and DE titles
|
|
123
|
+
Article.translated(:title, locale: :en)
|
|
124
|
+
.merge(Article.translated(:title, locale: :de))
|
|
125
|
+
|
|
126
|
+
# Exclude drafts and order by title
|
|
127
|
+
Article.international_not(status: "draft")
|
|
128
|
+
.merge(Article.international_order(:title))
|
|
129
|
+
```
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: internationalize
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Sampo Kuokkanen
|
|
@@ -49,6 +49,11 @@ files:
|
|
|
49
49
|
- CHANGELOG.md
|
|
50
50
|
- LICENSE.txt
|
|
51
51
|
- README.md
|
|
52
|
+
- context/configuration.md
|
|
53
|
+
- context/getting-started.md
|
|
54
|
+
- context/index.yaml
|
|
55
|
+
- context/model-api.md
|
|
56
|
+
- context/query-api.md
|
|
52
57
|
- lib/generators/internationalize/translation/templates/add_translations_migration.rb.erb
|
|
53
58
|
- lib/generators/internationalize/translation_generator.rb
|
|
54
59
|
- lib/internationalize.rb
|