lesli_babel 1.1.1 → 1.1.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 89a771fb721d2c01fd8cc3c7a6c309a7ed102bff7381013a7cb4dcc9323317df
4
- data.tar.gz: 4e736b6fdb2726a3f56b29a905d3c60a962f82ede7709e549af737406626a0c7
3
+ metadata.gz: 8164c242dfa1ccc58035909df600d0275e0be6727b489373c3bc3330025c349c
4
+ data.tar.gz: b1f4a8d43873994e7e2cc5cd773bd4029befaa781cd9bfdb75e2dd81173e03cb
5
5
  SHA512:
6
- metadata.gz: 639892e037b491a7a6e3a198eab82c9c45505c19730cd10cd3d275d52b779b635024eb799c17384c4338da026a285eeaa08222d4345e216559750d51b710bf0c
7
- data.tar.gz: 3387e4faa48b35730ded81c3ff38fe3bd025539f8cd6f8c93a8b15247d0859d4c73111b9d50aab3b7344173b076202d70c72c945aa6562b470e12036c6e925a1
6
+ metadata.gz: 473c046acfb89d09bb13b5798d88a6c8a0190b61b45c0fe5d2260f372e8e3a41163e53b7951352edde10ce6bb0e244aaa53fbb889f931b014ddddb2afd494458
7
+ data.tar.gz: 056bab6d9d69bec84892a7a85c34be10464b8e5e34bb792be6bf95bc39f62aa2dde78511f5ecd281b429c9934cac312f4552fe9ae4c81b94f91ed8ba31a025dd
data/Rakefile CHANGED
@@ -1,5 +1,7 @@
1
1
  require "bundler/setup"
2
2
 
3
- load "rails/tasks/statistics.rake"
3
+ APP_RAKEFILE = File.expand_path("test/dummy/Rakefile", __dir__)
4
+
5
+ load "rails/tasks/engine.rake"
4
6
 
5
7
  require "bundler/gem_tasks"
@@ -0,0 +1,2 @@
1
+ /*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */
2
+ @layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-ordinal:initial;--tw-slashed-zero:initial;--tw-numeric-figure:initial;--tw-numeric-spacing:initial;--tw-numeric-fraction:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000}}}@layer theme{:root,:host{--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--color-sky-500:oklch(68.5% .169 237.323);--color-slate-100:oklch(96.8% .007 247.896);--color-slate-200:oklch(92.9% .013 255.508);--color-slate-400:oklch(70.4% .04 256.788);--color-slate-500:oklch(55.4% .046 257.417);--color-slate-600:oklch(44.6% .043 257.281);--color-slate-900:oklch(20.8% .042 265.755);--color-white:#fff;--spacing:.25rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-lg:1.125rem;--text-lg--line-height:calc(1.75 / 1.125);--font-weight-medium:500;--font-weight-semibold:600;--tracking-wider:.05em;--radius-lg:.5rem;--radius-2xl:1rem;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1)}}@layer utilities{.my-6{margin-block:calc(var(--spacing) * 6)}.mt-1{margin-top:var(--spacing)}.mb-3{margin-bottom:calc(var(--spacing) * 3)}.flex{display:flex}.grid{display:grid}.inline-flex{display:inline-flex}.size-5{width:calc(var(--spacing) * 5);height:calc(var(--spacing) * 5)}.h-12{height:calc(var(--spacing) * 12)}.w-16{width:calc(var(--spacing) * 16)}.max-w-full{max-width:100%}.shrink-0{flex-shrink:0}.flex-col{flex-direction:column}.items-center{align-items:center}.items-start{align-items:flex-start}.justify-center{justify-content:center}.gap-2{gap:calc(var(--spacing) * 2)}.gap-5{gap:calc(var(--spacing) * 5)}.rounded-2xl{border-radius:var(--radius-2xl)}.rounded-lg{border-radius:var(--radius-lg)}.border{border-style:var(--tw-border-style);border-width:1px}.border-0{border-style:var(--tw-border-style);border-width:0}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-slate-200{border-color:var(--color-slate-200)}.bg-white{background-color:var(--color-white)}.p-5{padding:calc(var(--spacing) * 5)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-4{padding-inline:calc(var(--spacing) * 4)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-6{padding-block:calc(var(--spacing) * 6)}.pt-1{padding-top:var(--spacing)}.pb-2{padding-bottom:calc(var(--spacing) * 2)}.text-center{text-align:center}.text-left{text-align:left}.font-mono{font-family:var(--font-mono)}.text-lg{font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.leading-5{--tw-leading:calc(var(--spacing) * 5);line-height:calc(var(--spacing) * 5)}.leading-none{--tw-leading:1;line-height:1}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-wider{--tw-tracking:var(--tracking-wider);letter-spacing:var(--tracking-wider)}.break-all{word-break:break-all}.text-slate-400{color:var(--color-slate-400)}.text-slate-500{color:var(--color-slate-500)}.text-slate-600{color:var(--color-slate-600)}.text-slate-900{color:var(--color-slate-900)}.uppercase{text-transform:uppercase}.tabular-nums{--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}.shadow-sm{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}@media (hover:hover){.group-hover\:text-slate-600:is(:where(.group):hover *){color:var(--color-slate-600)}.hover\:bg-slate-100:hover{background-color:var(--color-slate-100)}.hover\:text-slate-900:hover{color:var(--color-slate-900)}}.focus-visible\:ring-2:focus-visible{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.focus-visible\:ring-sky-500\/40:focus-visible{--tw-ring-color:#00a5ef66}@supports (color:color-mix(in lab, red, red)){.focus-visible\:ring-sky-500\/40:focus-visible{--tw-ring-color:color-mix(in oklab, var(--color-sky-500) 40%, transparent)}}.focus-visible\:outline-none:focus-visible{--tw-outline-style:none;outline-style:none}@media (min-width:40rem){.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.sm\:gap-6{gap:calc(var(--spacing) * 6)}.sm\:p-6{padding:calc(var(--spacing) * 6)}.sm\:py-8{padding-block:calc(var(--spacing) * 8)}}@media (min-width:64rem){.lg\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}}@media (min-width:80rem){.xl\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}}}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-ordinal{syntax:"*";inherits:false}@property --tw-slashed-zero{syntax:"*";inherits:false}@property --tw-numeric-figure{syntax:"*";inherits:false}@property --tw-numeric-spacing{syntax:"*";inherits:false}@property --tw-numeric-fraction{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}
@@ -1,6 +1,6 @@
1
1
  module LesliBabel
2
2
  class Bucket < ApplicationRecord
3
3
  belongs_to :module
4
- has_many :strings
4
+ has_many :labels
5
5
  end
6
6
  end
@@ -1,7 +1,7 @@
1
1
  module LesliBabel
2
2
  class Module < ApplicationRecord
3
3
  has_many :buckets
4
- has_many :labels
4
+ has_many :labels, through: :buckets
5
5
 
6
6
  validates_presence_of :platform
7
7
 
@@ -7,18 +7,20 @@
7
7
 
8
8
  <%= render(LesliView::Components::Toolbar.new) %>
9
9
 
10
- <section class="container">
11
- <div class="columns is-multiline is-variable dashboard-components">
10
+ <section class="py-6 sm:py-8" aria-label="Translation status by locale">
11
+ <div class="grid gap-5 sm:grid-cols-2 sm:gap-6 lg:grid-cols-3 xl:grid-cols-4">
12
12
  <% @stats[:total_strings_translations].each do |locale| %>
13
- <div class="column">
14
- <div class="box has-text-centered">
15
- <svg class="flag-icon mb-2" width="64px" height="48px">
16
- <use xlink:href="#locale-<%= locale[:code] %>"></use>
17
- </svg>
18
- <p class="is-size-5"><%= locale[:name] %>: <%= locale[:total] %></p>
19
- <small>missing: <%= @stats[:total_strings].to_i - locale[:total] %> translations</small>
20
- </div>
21
- </div>
13
+ <article class="flex flex-col items-center rounded-2xl border border-slate-200 bg-white p-5 text-center shadow-sm sm:p-6">
14
+ <svg class="mb-3 h-12 w-16" aria-hidden="true">
15
+ <use xlink:href="#locale-<%= locale[:code] %>"></use>
16
+ </svg>
17
+ <h2 class="text-lg font-semibold text-slate-900">
18
+ <%= locale[:name] %>: <span class="tabular-nums"><%= locale[:total] %></span>
19
+ </h2>
20
+ <p class="mt-1 text-sm text-slate-500">
21
+ missing: <span class="tabular-nums"><%= @stats[:total_strings].to_i - locale[:total] %></span> translations
22
+ </p>
23
+ </article>
22
24
  <% end %>
23
25
  </div>
24
26
  </section>
@@ -1,7 +1,7 @@
1
1
 
2
2
  <%= form_with(
3
3
  id: "lesli-babel-labels-form",
4
- model: @label,
4
+ model: @label,
5
5
  builder: LesliView::Forms::BuilderHorizontal
6
6
  ) do |form| %>
7
7
 
@@ -21,13 +21,13 @@
21
21
  <% I18n.available_locales.each do |locale| %>
22
22
  <%= form.field_control(locale, label:language_name(locale)) %>
23
23
  <% end %>
24
- <hr>
24
+ <hr class="my-6 border-0 border-t border-slate-200">
25
25
  <%= form.field_control(:context) %>
26
26
  <%= form.field_control_select(:status, LesliBabel::Label.statuses) %>
27
27
  <%= form.field_control(:path) unless @label[:path].blank? %>
28
28
  <% end %>
29
29
 
30
- <hr>
30
+ <hr class="my-6 border-0 border-t border-slate-200">
31
31
 
32
32
  <%= form.field_control_button("Update", icon:"save") %>
33
33
 
@@ -25,8 +25,8 @@ columns = [{
25
25
 
26
26
  <%= render LesliView::Elements::Table.new(columns: columns) do |table| %>
27
27
  <% @labels[:records].each do |record| %>
28
- <% table.with_row(css_class:"is-#{record.category}") do |row| %>
29
- <% row.with_cell(css_class:"has-text-centered") do %>
28
+ <% table.with_row(status: record.category) do |row| %>
29
+ <% row.with_cell(align: :center) do %>
30
30
  <%= turbo_link_to(record["id"], label_path(record["id"])) %>
31
31
  <% end %>
32
32
  <% row.with_cell do %>
@@ -38,16 +38,18 @@ columns = [{
38
38
  <% row.with_cell do %>
39
39
  <div x-data="{ copied: false }">
40
40
  <button
41
- class="button is-primary is-inverted"
41
+ type="button"
42
+ class="group inline-flex max-w-full items-start gap-2 rounded-lg px-3 py-2 text-left text-sm font-medium text-slate-600 transition-colors hover:bg-slate-100 hover:text-slate-900 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-sky-500/40"
43
+ :aria-label="copied ? 'Path copied' : 'Copy path'"
42
44
  @click="
43
45
  navigator.clipboard.writeText($refs.path.innerText.trim());
44
46
  copied = true;
45
47
  setTimeout(() => copied = false, 2000)
46
48
  ">
47
- <span class="icon has-text-grey">
48
- <span class="material-symbols" x-text="copied ? 'check' : 'content_copy'" x-transition></span>
49
+ <span class="inline-flex size-5 shrink-0 items-center justify-center text-slate-400 transition-colors group-hover:text-slate-600" aria-hidden="true">
50
+ <span class="material-symbols text-lg leading-none" x-text="copied ? 'check' : 'content_copy'" x-transition></span>
49
51
  </span>
50
- <span x-ref="path">
52
+ <span class="break-all font-mono text-xs leading-5" x-ref="path">
51
53
  <%= record["path"] %>
52
54
  </span>
53
55
  </button>
@@ -33,11 +33,13 @@ Building a better future, one line of code at a time.
33
33
  %>
34
34
 
35
35
 
36
- <p class="menu-label">Modules</p>
36
+ <li class="px-4 pb-2 pt-1">
37
+ <h2 class="text-xs font-semibold uppercase tracking-wider text-slate-500">Modules</h2>
38
+ </li>
37
39
  <% LesliBabel::Module.all.order(:code).each do |engine| %>
38
40
  <%= navigation_item(
39
- lesli_babel.modules_path + "/" + engine.id.to_s,
40
- engine.code.titleize,
41
+ lesli_babel.modules_path + "/" + engine.id.to_s,
42
+ engine.code.titleize,
41
43
  "ri-folder-line"
42
- ); %>
44
+ ) %>
43
45
  <% end %>
@@ -1,4 +1,4 @@
1
1
  module LesliBabel
2
- VERSION = "1.1.1"
3
- BUILD = "1780272810"
2
+ VERSION = "1.1.2"
3
+ BUILD = "1791607001"
4
4
  end
data/readme.md CHANGED
@@ -1,14 +1,15 @@
1
1
  <div align="center">
2
- <img width="100" alt="LesliBabel logo" src="./app/assets/images/lesli_babel/babel-logo.svg" />
3
- <h3 align="center">Translation Management System for the Lesli Framework.</h3>
2
+ <h1 align="center">
3
+ <img width="100" alt="LesliBabel" src="./app/assets/images/lesli_babel/babel-logo.svg" />
4
+ </h1>
5
+ <h3 align="center">Translation management for the Lesli Framework.</h3>
4
6
  </div>
5
7
 
6
8
  <br />
7
- <hr/>
8
9
 
9
10
  <div align="center">
10
- <a target="_blank" href="https://github.com/LesliTech/LesliBabel/actions">
11
- <img alt="Tests passing" src="https://img.shields.io/badge/Tests-passing-green?style=for-the-badge&logo=github">
11
+ <a target="_blank" href="https://github.com/LesliTech/LesliBabel/actions/workflows/lesli-ci.yaml">
12
+ <img alt="LesliBabel test status" src="https://img.shields.io/github/actions/workflow/status/LesliTech/LesliBabel/lesli-ci.yaml?branch=master&style=for-the-badge&logo=github&label=tests">
12
13
  </a>
13
14
  <a target="_blank" href="https://rubygems.org/gems/lesli_babel">
14
15
  <img alt="Gem Version" src="https://img.shields.io/gem/v/lesli_babel?style=for-the-badge&logo=ruby">
@@ -16,83 +17,179 @@
16
17
  <a target="_blank" href="https://codecov.io/github/LesliTech/LesliBabel">
17
18
  <img alt="Codecov" src="https://img.shields.io/codecov/c/github/LesliTech/LesliBabel?style=for-the-badge&logo=codecov">
18
19
  </a>
20
+ <a target="_blank" href="https://sonarcloud.io/project/overview?id=LesliTech_LesliBabel">
21
+ <img alt="Sonar Quality Gate" src="https://img.shields.io/sonar/quality_gate/LesliTech_LesliBabel?server=https%3A%2F%2Fsonarcloud.io&style=for-the-badge&logo=sonarqubecloud&label=Quality">
22
+ </a>
19
23
  </div>
20
24
 
21
- <hr/>
22
25
  <br />
23
26
 
24
27
  <div align="center">
25
28
  <img
26
29
  style="width:100%;max-width:800px;border-radius:6px;"
27
- alt="Lesli screenshot" src="./docs/images/screenshot.png" />
30
+ alt="LesliBabel translation management"
31
+ src="./docs/images/screenshot.png" />
28
32
  </div>
29
33
 
34
+ ---
35
+
36
+ <br />
37
+
38
+ ## Introduction
39
+
40
+ LesliBabel is the official translation management engine for the [Lesli Framework](https://github.com/LesliTech/Lesli).
41
+
42
+ It organizes application text and helps teams maintain, synchronize, and deploy translations across Lesli engines.
43
+
44
+ <br />
45
+
46
+ ## Features
47
+
48
+ - Translation modules and buckets
49
+ - Centralized label management
50
+ - Language-specific translation values
51
+ - Synchronization of source labels
52
+ - Translation deployment across Lesli applications
53
+
30
54
  <br />
31
- <hr/>
55
+
56
+ ## Try LesliBabel
57
+
58
+ - [Try the online demo](https://demo.lesli.dev/)
59
+ - [Run the Docker demo](https://github.com/LesliTech/lesli-docker-demo)
60
+
32
61
  <br />
33
62
 
34
- ### Installation
63
+ ## Quick Start
64
+
65
+ ### Requirements
66
+
67
+ - A Rails application with [Lesli](https://rubygems.org/gems/lesli)
68
+ - SQLite by default, or PostgreSQL when preferred by the host application
69
+
70
+ ### Install LesliBabel
71
+
72
+ Add the engine to the host Rails application and prepare its database:
35
73
 
36
74
  ```shell
37
- # Add LesliBabel engine gem
38
75
  bundle add lesli_babel
76
+ bin/rails lesli:db:prepare
77
+ ```
78
+
79
+ ### Mount the engine
39
80
 
40
- # Setup & initialize the database
41
- rake lesli:db:setup
81
+ Applications using Lesli's standard router mount LesliBabel automatically at `/babel`:
82
+
83
+ ```ruby
84
+ # config/routes.rb
85
+ Rails.application.routes.draw do
86
+ Lesli::Router.mount(self)
87
+ end
42
88
  ```
43
89
 
90
+ If the application does not use the standard Lesli router, mount the engine directly:
91
+
44
92
  ```ruby
45
- # Load LesliBabel engine
93
+ # config/routes.rb
46
94
  Rails.application.routes.draw do
47
95
  mount LesliBabel::Engine => "/babel"
48
96
  end
49
97
  ```
50
98
 
51
- <br />
52
- <hr/>
99
+ Start Rails and visit [http://127.0.0.1:3000/babel](http://127.0.0.1:3000/babel):
100
+
101
+ ```shell
102
+ bin/rails server
103
+ ```
104
+
53
105
  <br />
54
106
 
55
- ### Development
107
+ ## Development
108
+
109
+ Clone LesliBabel into the host application's `engines` directory:
56
110
 
57
111
  ```shell
58
- # clone the lesli repo inside your engine folder: RailsApp/engines
59
- git clone https://github.com/LesliTech/LesliBabel.git
112
+ cd RailsApp
113
+ mkdir -p engines
114
+ git clone https://github.com/LesliTech/LesliBabel.git engines/LesliBabel
115
+ ```
60
116
 
61
- # Load LesliBabel as a Gem
62
- gem "lesli", path: "engines/LesliBabel"
117
+ Reference the local engine from the host application's `Gemfile`:
63
118
 
64
- # Install the necessary Gems to run LesliBabel
119
+ ```ruby
120
+ gem "lesli_babel", path: "engines/LesliBabel"
121
+ ```
122
+
123
+ Install dependencies, prepare the host database, and start Rails:
124
+
125
+ ```shell
65
126
  bundle install
127
+ bin/rails lesli:db:prepare
128
+ bin/rails server
129
+ ```
66
130
 
67
- # Setup & initialize the database
68
- rake lesli:db:setup
131
+ ### Frontend
69
132
 
133
+ LesliBabel uses LesliView for shared interface components and Tailwind CSS for engine-specific presentation. Tailwind source files and generated Rails assets are kept separate:
134
+
135
+ ```text
136
+ source/tailwind/application.tailwind.css
137
+ ↓ build
138
+ app/assets/stylesheets/lesli_babel/application.tailwind.css
70
139
  ```
71
140
 
72
- <br />
73
- <hr/>
74
- <br />
141
+ From a complete Lesli development workspace, compile the assets through the shared LesliAssets builder:
142
+
143
+ ```shell
144
+ cd gems/LesliAssets
145
+ make build.tailwind
146
+ ```
147
+
148
+ See the [frontend guide](./docs/about/frontend.md) for source registration, view conventions, responsive testing, and utility-collision guidance.
149
+
150
+ ### Tests
151
+
152
+ From a complete Lesli development workspace, run the engine test suite from the LesliBabel directory:
153
+
154
+ ```shell
155
+ cd engines/LesliBabel
156
+ RAILS_ENV=test bundle exec rake app:db:prepare
157
+ bundle exec rake app:test
158
+ ```
159
+
160
+ Run the eager-loaded CI equivalent before pushing changes:
161
+
162
+ ```shell
163
+ CI=true bundle exec rake app:test
164
+ ```
75
165
 
76
- ### Demo
166
+ <br />
77
167
 
78
- * [online demo](https://demo.lesli.dev/)
79
- * [docker demo](https://github.com/LesliTech/lesli-docker-demo)
168
+ ## Documentation
80
169
 
170
+ - [Installation guide](./docs/about/installation.md)
171
+ - [Translation workflow](./docs/about/translations.md)
172
+ - [Frontend development](./docs/about/frontend.md)
173
+ - [Database](./docs/about/database.md)
174
+ - [Tasks](./docs/about/tasks.md)
175
+ - [Lesli website](https://www.lesli.dev/)
176
+ - [Documentation](https://www.lesli.dev/engines/babel)
177
+ - [Release notes](https://github.com/LesliTech/LesliBabel/releases)
178
+ - [Issue tracker](https://github.com/LesliTech/LesliBabel/issues)
179
+ - [Source code](https://github.com/LesliTech/LesliBabel)
81
180
 
82
- ### Documentation
83
- * [website](https://www.lesli.dev/)
84
- * [documentation](https://www.lesli.dev/engines/babel)
181
+ <br />
85
182
 
183
+ ## Community
86
184
 
87
- ### Connect with Lesli
185
+ - [X: @LesliTech](https://x.com/LesliTech)
186
+ - [hello@lesli.tech](mailto:hello@lesli.tech)
187
+ - [https://www.lesli.tech](https://www.lesli.tech)
88
188
 
89
- * [X: @LesliTech](https://x.com/LesliTech)
90
- * [Email: hello@lesli.tech](hello@lesli.tech)
91
- * [Website: https://www.lesli.tech](https://www.lesli.tech)
189
+ <br />
92
190
 
191
+ ## License
93
192
 
94
- ### License
95
- -------
96
193
  Copyright (c) 2026, Lesli Technologies, S. A.
97
194
 
98
195
  This program is free software: you can redistribute it and/or modify
@@ -106,19 +203,16 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
106
203
  GNU General Public License for more details.
107
204
 
108
205
  You should have received a copy of the GNU General Public License
109
- along with this program. If not, see http://www.gnu.org/licenses/.
206
+ along with this program. If not, see [https://www.gnu.org/licenses/](https://www.gnu.org/licenses/).
110
207
 
111
- <br />
112
- <hr />
113
- <br />
114
- <br />
208
+ The complete license text is available in the [license file](./license).
115
209
 
116
- <div align="center" class="has-text-centered">
117
- <img width="200" alt="Lesli logo" src="https://cdn.lesli.tech/lesli/brand/app-logo.svg" />
118
- <h3 align="center" class="mt-0">
119
- The Open-Source SaaS Development Framework for Ruby on Rails.
120
- </h3>
121
- </div>
210
+ ---
122
211
 
123
212
  <br />
124
213
  <br />
214
+
215
+ <div align="center">
216
+ <img width="80" alt="Lesli icon" src="https://cdn.lesli.tech/lesli/brand/app-icon.svg" />
217
+ <h3 align="center">The Open-Source SaaS Development Framework for Ruby on Rails.</h3>
218
+ </div>
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lesli_babel
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.1
4
+ version: 1.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - The Lesli Development Team
@@ -36,6 +36,7 @@ files:
36
36
  - app/assets/images/lesli_babel/babel-logo.svg
37
37
  - app/assets/javascripts/lesli_babel/application.js
38
38
  - app/assets/stylesheets/lesli_babel/application.css
39
+ - app/assets/stylesheets/lesli_babel/application.tailwind.css
39
40
  - app/controllers/lesli_babel/application_controller.rb
40
41
  - app/controllers/lesli_babel/buckets_controller.rb
41
42
  - app/controllers/lesli_babel/dashboards_controller.rb