rails-mermaid_erd 0.7.0 → 0.8.0

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: 02a09db4c8fe0efe3647b171cd713eb46664a961c36eb820691b069f1dec82b2
4
- data.tar.gz: 0bc7bec06228e7a2e03055b0b82a9ff63031ef2e6ce008e0e3c7edbf6044128b
3
+ metadata.gz: 5a6ae2943632ef191d3758420e84a0fc2e43f17a677359e21328bc67b83bd172
4
+ data.tar.gz: d1ecd0768360f3bdbca63e1569ac26f708af009bfc3b18d09c8001ff474ea77a
5
5
  SHA512:
6
- metadata.gz: 5228d44560de7ae4bc244b7854a926144eee9ef1b1d16c77ddd71b999e1b260ccc3ae6de468968de1a208b2257d31121445366c72e0e9df932a9c61a751019b0
7
- data.tar.gz: 856f64ddfa060ce33f859fe914c4be5ce93bd9898e3c75ec5ab2fa8fe2657ab2063b3bd56129e869af52723844c9e4b22e36085842813b5ceb672fd6e44ed180
6
+ metadata.gz: 4ef1270960ec9ce3f1a91d7c8c9d6182f0ef489f11e10be3653f905e72dbf344d39cee5da22ac35cc2f799836e49da799f0db2df82f2e9c3b59f120b6592fcdd
7
+ data.tar.gz: f3a1d2f73421f4f2cbec8c7d394ca55ced02835df12e2fb3bfb24ec6c97685609cdd30137be1b9943d853b80ff86d6debdd996aa19066dd173009635c0615464
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- [English](./README.md) | [日本語](./README.ja.md)
1
+ [English](./README.md) | [日本語](./README.ja.md) | [简体中文](./README.zh-CN.md) | [繁體中文](./README.zh-TW.md) | [한국어](./README.ko.md) | [Español](./README.es.md) | [Français](./README.fr.md) | [Deutsch](./README.de.md) | [Italiano](./README.it.md) | [Português (Brasil)](./README.pt-BR.md) | [Русский](./README.ru.md) | [العربية](./README.ar.md)
2
2
 
3
3
  # Rails Mermaid ERD
4
4
 
@@ -64,6 +64,22 @@ If you share this file, it can be used by those who do not have a Ruby on Rails
64
64
 
65
65
  It would be very smart to generate it automatically using CI.
66
66
 
67
+ ### Print the Mermaid source to stdout
68
+
69
+ Run rake task `mermaid_erd:print` to print the raw `erDiagram` source to stdout instead of writing the HTML viewer. This pipes cleanly into other tools:
70
+
71
+ ```bash
72
+ $ bundle exec rails mermaid_erd:print
73
+ $ bundle exec rails mermaid_erd:print > er.mmd
74
+ $ bundle exec rails mermaid_erd:print | mmdc -i - -o er.svg
75
+ ```
76
+
77
+ The output is the full diagram — every table, column, key, comment, and relation — equivalent to the HTML viewer with all of its detail toggles enabled.
78
+
79
+ ## Languages
80
+
81
+ The viewer UI ships in 12 languages: English, 日本語, 简体中文, 繁體中文, 한국어, Español, Français, Deutsch, Italiano, Português (Brasil), Русский, and العربية (right-to-left). It auto-detects the browser language (`navigator.language`) on load, falls back to English for unsupported locales, and can be switched manually from the selector in the top-right corner.
82
+
67
83
  ## Supported versions
68
84
 
69
85
  The Ruby × Rails combinations exercised by CI on every push and pull request:
@@ -0,0 +1,74 @@
1
+ class RailsMermaidErd::MermaidText
2
+ # Renders the schema dump from RailsMermaidErd::Builder.model_data into
3
+ # Mermaid `erDiagram` source text.
4
+ #
5
+ # This is the *maximal* projection of the bundled front-end viewer
6
+ # (lib/templates/index.html.erb): the dump always shows every table, every
7
+ # column with its key marker and comment, and every relation label — i.e.
8
+ # the diagram the viewer produces with all of its detail toggles ("Show
9
+ # key", "Show comment", "Show relation comment") enabled and with no
10
+ # model-selection filtering. The viewer defaults those toggles off, so the
11
+ # dump is deliberately more detailed than the viewer's initial view. The only
12
+ # thing it drops is the viewer's "Restore Hash" comment line, which encodes
13
+ # browser-only UI state and is meaningless on the command line. Apart from
14
+ # that line and a single trailing newline (added by the rake task's `puts`),
15
+ # it is byte-identical to the viewer's "all toggles on" output.
16
+ #
17
+ # Comment values come from arbitrary DB metadata, so they are sanitised the
18
+ # same way the viewer's renderer must (and now does): newlines collapse to a
19
+ # space (a newline would split a label or terminate a `%%` line mid-diagram)
20
+ # and a literal `"` becomes Mermaid's `#quot;` entity (an unescaped quote
21
+ # closes the quoted label early). Keep this byte-aligned with the viewer at
22
+ # index.html.erb:809-845.
23
+ HEADER = [
24
+ "erDiagram",
25
+ " %% --------------------------------------------------------",
26
+ ' %% Generated by "Rails Mermaid ERD"',
27
+ " %% https://github.com/koedame/rails-mermaid_erd",
28
+ " %% --------------------------------------------------------",
29
+ ""
30
+ ].freeze
31
+
32
+ class << self
33
+ # `result` is the hash returned by RailsMermaidErd::Builder.model_data.
34
+ def build(result)
35
+ lines = HEADER.dup
36
+
37
+ result[:Models].each do |model|
38
+ lines << " %% table name: #{one_line(model[:TableName])}"
39
+ lines << " %% table comment: #{one_line(model[:TableComment])}"
40
+ # Mermaid entity names can't contain ":", so namespaced models like
41
+ # `Admin::User` are written as `Admin-User` (matches the front-end).
42
+ lines << " #{model[:ModelName].tr(":", "-")} {"
43
+ model[:Columns].each do |column|
44
+ lines << " #{column[:type]} #{column[:name]} #{column[:key]} #{quoted(column[:comment])}"
45
+ end
46
+ lines << " }"
47
+ lines << ""
48
+ end
49
+
50
+ result[:Relations].each do |relation|
51
+ left = relation[:LeftModelName].tr(":", "-")
52
+ right = relation[:RightModelName].tr(":", "-")
53
+ lines << " #{left} #{relation[:LeftValue]}#{relation[:Line]}#{relation[:RightValue]} #{right} : #{quoted(relation[:Comment])}"
54
+ end
55
+
56
+ lines.join("\n")
57
+ end
58
+
59
+ private
60
+
61
+ # Collapse newlines so a value can't split a label or terminate a `%%`
62
+ # comment line mid-diagram.
63
+ def one_line(value)
64
+ value.to_s.gsub(/[\r\n]+/, " ")
65
+ end
66
+
67
+ # A Mermaid quoted label: newline-free, with `"` escaped to the `#quot;`
68
+ # entity so a comment can't close the string early.
69
+ def quoted(value)
70
+ escaped = one_line(value).gsub('"', "#quot;")
71
+ "\"#{escaped}\""
72
+ end
73
+ end
74
+ end
@@ -1,3 +1,3 @@
1
1
  module RailsMermaidErd
2
- VERSION = "0.7.0"
2
+ VERSION = "0.8.0"
3
3
  end
@@ -8,6 +8,7 @@ module RailsMermaidErd
8
8
  # means "when the rake task runs."
9
9
  autoload :Builder, "rails-mermaid_erd/builder"
10
10
  autoload :Configuration, "rails-mermaid_erd/configuration"
11
+ autoload :MermaidText, "rails-mermaid_erd/mermaid_text"
11
12
 
12
13
  class << self
13
14
  def configuration
@@ -6,6 +6,7 @@ require "fileutils"
6
6
  # deep inside the task body where the cause is harder to diagnose.
7
7
  require_relative "../rails-mermaid_erd/builder"
8
8
  require_relative "../rails-mermaid_erd/configuration"
9
+ require_relative "../rails-mermaid_erd/mermaid_text"
9
10
 
10
11
  desc "Generate Mermaid ERD."
11
12
  task mermaid_erd: :environment do
@@ -35,3 +36,26 @@ task mermaid_erd: :environment do
35
36
  "Check the `result_path` key in config/mermaid_erd.yml and that the directory is writable."
36
37
  end
37
38
  end
39
+
40
+ namespace :mermaid_erd do
41
+ desc "Print Mermaid ERD source to stdout."
42
+ task print: :environment do
43
+ # Builder calls `ActiveRecord::Schema.foreign_keys`, whose migration-style
44
+ # `-- foreign_keys(...)` / `-> 0.001s` logging would otherwise land on
45
+ # stdout and corrupt the piped diagram. Mute it just for the build, and
46
+ # restore it in `ensure` so an error mid-build can't leak the muted global
47
+ # into later tasks running in the same process.
48
+ was_verbose = ActiveRecord::Migration.verbose
49
+ ActiveRecord::Migration.verbose = false
50
+ result =
51
+ begin
52
+ RailsMermaidErd::Builder.model_data
53
+ ensure
54
+ ActiveRecord::Migration.verbose = was_verbose
55
+ end
56
+
57
+ # Stream the raw `erDiagram` text to stdout so it pipes into other tools
58
+ # (`> er.mmd`, `| mmdc -i - -o er.svg`) without writing the HTML viewer.
59
+ $stdout.puts RailsMermaidErd::MermaidText.build(result)
60
+ end
61
+ end
@@ -1,5 +1,5 @@
1
1
  <!DOCTYPE html>
2
- <html lang="en">
2
+ <html lang="en" dir="ltr">
3
3
  <head>
4
4
  <meta charset="UTF-8">
5
5
  <title><%= app_name %> - Rails Mermaid ERD</title>
@@ -23,8 +23,7 @@
23
23
  </h1>
24
24
  <div class="space-x-4 inline-flex items-center">
25
25
  <select v-model="language" @change="setLanguage(language)" class="text-xs border-0 rounded py-1 pl-3 pr-8 focus:ring-2 focus:ring-white focus:ring-offset-2 focus:ring-offset-red-600">
26
- <option value="en">English</option>
27
- <option value="ja">Japanese - 日本語</option>
26
+ <option v-for="loc in locales" :key="loc.code" :value="loc.code">{{ loc.label }}</option>
28
27
  </select>
29
28
  <a href="https://github.com/koedame/rails-mermaid_erd" class="text-white hover:text-red-200" target="_blank" rel="noopener noreferrer">
30
29
  <svg class="h-6 w-6" fill="currentColor" viewBox="0 0 24 24">
@@ -330,6 +329,20 @@
330
329
 
331
330
  <script>window.SCHEMA_DATA=<%= result.to_json %></script>
332
331
  <script>
332
+ window.locales = [
333
+ { code: 'en', label: 'English', dir: 'ltr' },
334
+ { code: 'ja', label: '日本語', dir: 'ltr' },
335
+ { code: 'zh-CN', label: '简体中文', dir: 'ltr' },
336
+ { code: 'zh-TW', label: '繁體中文', dir: 'ltr' },
337
+ { code: 'ko', label: '한국어', dir: 'ltr' },
338
+ { code: 'es', label: 'Español', dir: 'ltr' },
339
+ { code: 'fr', label: 'Français', dir: 'ltr' },
340
+ { code: 'de', label: 'Deutsch', dir: 'ltr' },
341
+ { code: 'it', label: 'Italiano', dir: 'ltr' },
342
+ { code: 'pt-BR', label: 'Português (Brasil)', dir: 'ltr' },
343
+ { code: 'ru', label: 'Русский', dir: 'ltr' },
344
+ { code: 'ar', label: 'العربية', dir: 'rtl' },
345
+ ]
333
346
  window.i18n = {
334
347
  en: {
335
348
  actions: {
@@ -442,6 +455,566 @@
442
455
  pinch: 'ピンチイン/アウト',
443
456
  reset_view: 'ビューをリセット',
444
457
  }
458
+ },
459
+ 'zh-CN': {
460
+ actions: {
461
+ title: '操作',
462
+ reset: '重置',
463
+ copy_mermaid_code: '复制 Mermaid 代码',
464
+ copied_mermaid_code: '已复制 Mermaid 代码',
465
+ copy_markdown_code: '复制 Markdown 代码',
466
+ copied_markdown_code: '已复制 Markdown 代码',
467
+ copy_url: '复制分享链接',
468
+ copied_url: '已复制分享链接',
469
+ download_svg_file: '下载 SVG 文件',
470
+ download_png_file: '下载 PNG 文件',
471
+ },
472
+ options: {
473
+ title: '选项',
474
+ preview_relationships: '预览关系',
475
+ show_relationship_comment: '显示关系注释',
476
+ show_key: '显示键',
477
+ show_column_comment: '显示字段注释',
478
+ hide_columns: '隐藏字段',
479
+ snapshot_mode: '快照模式',
480
+ snapshot_mode_hint: '每次渲染后将图表栅格化。在 Safari 和 Firefox 上平移和缩放会快很多,但代价是无法选择文本。',
481
+ },
482
+ models: {
483
+ title: '模型',
484
+ select: '选择',
485
+ all: '全部',
486
+ none: '无',
487
+ filter: '筛选',
488
+ no_model_file: '无模型文件',
489
+ },
490
+ empty: {
491
+ title: '未选择模型',
492
+ hint: '从侧边栏选择模型以渲染 ERD。',
493
+ },
494
+ errors: {
495
+ render_failed: 'Mermaid 渲染当前选择失败。请查看浏览器控制台了解详情。',
496
+ snapshot_failed: '无法生成快照图像。回退到 SVG 渲染。',
497
+ download_failed: '下载失败。请查看浏览器控制台了解详情。',
498
+ copy_failed: '复制到剪贴板失败。浏览器要求近期的用户操作以及安全上下文。',
499
+ dismiss: '关闭',
500
+ },
501
+ tab: {
502
+ erd: 'ER 图',
503
+ code: '代码',
504
+ },
505
+ controls: {
506
+ movement: '移动',
507
+ zoom: '缩放',
508
+ space_drag: '空格 + 鼠标拖动',
509
+ middle_drag: '中键 + 拖动',
510
+ mouse_wheel: '鼠标滚轮',
511
+ pinch: '双指缩放',
512
+ reset_view: '重置视图',
513
+ }
514
+ },
515
+ 'zh-TW': {
516
+ actions: {
517
+ title: '操作',
518
+ reset: '重設',
519
+ copy_mermaid_code: '複製 Mermaid 程式碼',
520
+ copied_mermaid_code: '已複製 Mermaid 程式碼',
521
+ copy_markdown_code: '複製 Markdown 程式碼',
522
+ copied_markdown_code: '已複製 Markdown 程式碼',
523
+ copy_url: '複製分享連結',
524
+ copied_url: '已複製分享連結',
525
+ download_svg_file: '下載 SVG 檔案',
526
+ download_png_file: '下載 PNG 檔案',
527
+ },
528
+ options: {
529
+ title: '選項',
530
+ preview_relationships: '預覽關聯',
531
+ show_relationship_comment: '顯示關聯註解',
532
+ show_key: '顯示鍵',
533
+ show_column_comment: '顯示欄位註解',
534
+ hide_columns: '隱藏欄位',
535
+ snapshot_mode: '快照模式',
536
+ snapshot_mode_hint: '每次算繪後將圖表點陣化。在 Safari 與 Firefox 上平移與縮放會快很多,但代價是無法選取文字。',
537
+ },
538
+ models: {
539
+ title: '模型',
540
+ select: '選擇',
541
+ all: '全部',
542
+ none: '無',
543
+ filter: '篩選',
544
+ no_model_file: '無模型檔案',
545
+ },
546
+ empty: {
547
+ title: '尚未選擇模型',
548
+ hint: '從側邊欄選擇模型以算繪 ERD。',
549
+ },
550
+ errors: {
551
+ render_failed: 'Mermaid 算繪目前的選擇失敗。請查看瀏覽器主控台以瞭解詳情。',
552
+ snapshot_failed: '無法產生快照影像。回復為 SVG 算繪。',
553
+ download_failed: '下載失敗。請查看瀏覽器主控台以瞭解詳情。',
554
+ copy_failed: '複製到剪貼簿失敗。瀏覽器需要近期的使用者操作以及安全的內容環境。',
555
+ dismiss: '關閉',
556
+ },
557
+ tab: {
558
+ erd: 'ER 圖',
559
+ code: '程式碼',
560
+ },
561
+ controls: {
562
+ movement: '移動',
563
+ zoom: '縮放',
564
+ space_drag: '空白鍵 + 滑鼠拖曳',
565
+ middle_drag: '中鍵 + 拖曳',
566
+ mouse_wheel: '滑鼠滾輪',
567
+ pinch: '雙指縮放',
568
+ reset_view: '重設檢視',
569
+ }
570
+ },
571
+ ko: {
572
+ actions: {
573
+ title: '작업',
574
+ reset: '초기화',
575
+ copy_mermaid_code: 'Mermaid 코드 복사',
576
+ copied_mermaid_code: 'Mermaid 코드 복사됨',
577
+ copy_markdown_code: 'Markdown 코드 복사',
578
+ copied_markdown_code: 'Markdown 코드 복사됨',
579
+ copy_url: '공유 링크 복사',
580
+ copied_url: '공유 링크 복사됨',
581
+ download_svg_file: 'SVG 파일 다운로드',
582
+ download_png_file: 'PNG 파일 다운로드',
583
+ },
584
+ options: {
585
+ title: '옵션',
586
+ preview_relationships: '관계 미리보기',
587
+ show_relationship_comment: '관계 주석 표시',
588
+ show_key: '키 표시',
589
+ show_column_comment: '컬럼 주석 표시',
590
+ hide_columns: '컬럼 숨기기',
591
+ snapshot_mode: '스냅샷 모드',
592
+ snapshot_mode_hint: '렌더링할 때마다 다이어그램을 래스터화합니다. Safari와 Firefox에서 이동과 확대/축소가 훨씬 빨라지지만 텍스트를 선택할 수 없게 됩니다.',
593
+ },
594
+ models: {
595
+ title: '모델',
596
+ select: '선택',
597
+ all: '전체',
598
+ none: '없음',
599
+ filter: '필터',
600
+ no_model_file: '모델 파일 없음',
601
+ },
602
+ empty: {
603
+ title: '선택된 모델이 없습니다',
604
+ hint: '사이드바에서 모델을 선택하여 ERD를 렌더링하세요.',
605
+ },
606
+ errors: {
607
+ render_failed: 'Mermaid가 현재 선택을 렌더링하지 못했습니다. 자세한 내용은 브라우저 콘솔을 확인하세요.',
608
+ snapshot_failed: '스냅샷 이미지를 생성하지 못했습니다. SVG 렌더링으로 대체합니다.',
609
+ download_failed: '다운로드에 실패했습니다. 자세한 내용은 브라우저 콘솔을 확인하세요.',
610
+ copy_failed: '클립보드 복사에 실패했습니다. 브라우저는 최근의 사용자 동작과 보안 컨텍스트를 요구합니다.',
611
+ dismiss: '닫기',
612
+ },
613
+ tab: {
614
+ erd: 'ERD',
615
+ code: '코드',
616
+ },
617
+ controls: {
618
+ movement: '이동',
619
+ zoom: '확대/축소',
620
+ space_drag: '스페이스 + 마우스 드래그',
621
+ middle_drag: '가운데 클릭 + 드래그',
622
+ mouse_wheel: '마우스 휠',
623
+ pinch: '핀치 확대/축소',
624
+ reset_view: '보기 초기화',
625
+ }
626
+ },
627
+ es: {
628
+ actions: {
629
+ title: 'Acciones',
630
+ reset: 'Restablecer',
631
+ copy_mermaid_code: 'Copiar código Mermaid',
632
+ copied_mermaid_code: 'Código Mermaid copiado',
633
+ copy_markdown_code: 'Copiar código Markdown',
634
+ copied_markdown_code: 'Código Markdown copiado',
635
+ copy_url: 'Copiar enlace para compartir',
636
+ copied_url: 'Enlace para compartir copiado',
637
+ download_svg_file: 'Descargar archivo SVG',
638
+ download_png_file: 'Descargar archivo PNG',
639
+ },
640
+ options: {
641
+ title: 'Opciones',
642
+ preview_relationships: 'Previsualizar relaciones',
643
+ show_relationship_comment: 'Mostrar comentario de la relación',
644
+ show_key: 'Mostrar clave',
645
+ show_column_comment: 'Mostrar comentario de la columna',
646
+ hide_columns: 'Ocultar columnas',
647
+ snapshot_mode: 'Modo instantánea',
648
+ snapshot_mode_hint: 'Rasteriza el diagrama después de cada renderizado. El desplazamiento y el zoom son mucho más rápidos en Safari y Firefox, a costa de no poder seleccionar texto.',
649
+ },
650
+ models: {
651
+ title: 'Modelos',
652
+ select: 'Seleccionar',
653
+ all: 'Todos',
654
+ none: 'Ninguno',
655
+ filter: 'Filtrar',
656
+ no_model_file: 'Sin archivo de modelo',
657
+ },
658
+ empty: {
659
+ title: 'Ningún modelo seleccionado',
660
+ hint: 'Elige modelos en la barra lateral para renderizar el ERD.',
661
+ },
662
+ errors: {
663
+ render_failed: 'Mermaid no pudo renderizar la selección actual. Revisa la consola del navegador para más detalles.',
664
+ snapshot_failed: 'No se pudo generar la imagen de la instantánea. Volviendo al renderizado SVG.',
665
+ download_failed: 'La descarga falló. Revisa la consola del navegador para más detalles.',
666
+ copy_failed: 'No se pudo copiar al portapapeles. Los navegadores requieren una acción reciente del usuario y un contexto seguro.',
667
+ dismiss: 'Descartar',
668
+ },
669
+ tab: {
670
+ erd: 'ERD',
671
+ code: 'Código',
672
+ },
673
+ controls: {
674
+ movement: 'Movimiento',
675
+ zoom: 'Zoom',
676
+ space_drag: 'Espacio + arrastrar con el ratón',
677
+ middle_drag: 'Clic central + arrastrar',
678
+ mouse_wheel: 'Rueda del ratón',
679
+ pinch: 'Pellizcar para acercar/alejar',
680
+ reset_view: 'Restablecer vista',
681
+ }
682
+ },
683
+ fr: {
684
+ actions: {
685
+ title: 'Actions',
686
+ reset: 'Réinitialiser',
687
+ copy_mermaid_code: 'Copier le code Mermaid',
688
+ copied_mermaid_code: 'Code Mermaid copié',
689
+ copy_markdown_code: 'Copier le code Markdown',
690
+ copied_markdown_code: 'Code Markdown copié',
691
+ copy_url: 'Copier le lien de partage',
692
+ copied_url: 'Lien de partage copié',
693
+ download_svg_file: 'Télécharger le fichier SVG',
694
+ download_png_file: 'Télécharger le fichier PNG',
695
+ },
696
+ options: {
697
+ title: 'Options',
698
+ preview_relationships: 'Aperçu des relations',
699
+ show_relationship_comment: 'Afficher le commentaire de la relation',
700
+ show_key: 'Afficher la clé',
701
+ show_column_comment: 'Afficher le commentaire de la colonne',
702
+ hide_columns: 'Masquer les colonnes',
703
+ snapshot_mode: 'Mode instantané',
704
+ snapshot_mode_hint: 'Pixellise le diagramme après chaque rendu. Le déplacement et le zoom deviennent beaucoup plus rapides sur Safari et Firefox, au prix de la sélection du texte.',
705
+ },
706
+ models: {
707
+ title: 'Modèles',
708
+ select: 'Sélectionner',
709
+ all: 'Tous',
710
+ none: 'Aucun',
711
+ filter: 'Filtrer',
712
+ no_model_file: 'Aucun fichier de modèle',
713
+ },
714
+ empty: {
715
+ title: 'Aucun modèle sélectionné',
716
+ hint: 'Sélectionnez des modèles dans la barre latérale pour afficher l\'ERD.',
717
+ },
718
+ errors: {
719
+ render_failed: 'Mermaid n\'a pas pu afficher la sélection actuelle. Consultez la console du navigateur pour plus de détails.',
720
+ snapshot_failed: 'Impossible de générer l\'image instantanée. Retour au rendu SVG.',
721
+ download_failed: 'Le téléchargement a échoué. Consultez la console du navigateur pour plus de détails.',
722
+ copy_failed: 'La copie dans le presse-papiers a échoué. Les navigateurs exigent une action utilisateur récente et un contexte sécurisé.',
723
+ dismiss: 'Fermer',
724
+ },
725
+ tab: {
726
+ erd: 'ERD',
727
+ code: 'Code',
728
+ },
729
+ controls: {
730
+ movement: 'Déplacement',
731
+ zoom: 'Zoom',
732
+ space_drag: 'Espace + glisser avec la souris',
733
+ middle_drag: 'Clic du milieu + glisser',
734
+ mouse_wheel: 'Molette de la souris',
735
+ pinch: 'Pincer pour zoomer',
736
+ reset_view: 'Réinitialiser la vue',
737
+ }
738
+ },
739
+ de: {
740
+ actions: {
741
+ title: 'Aktionen',
742
+ reset: 'Zurücksetzen',
743
+ copy_mermaid_code: 'Mermaid-Code kopieren',
744
+ copied_mermaid_code: 'Mermaid-Code kopiert',
745
+ copy_markdown_code: 'Markdown-Code kopieren',
746
+ copied_markdown_code: 'Markdown-Code kopiert',
747
+ copy_url: 'Freigabelink kopieren',
748
+ copied_url: 'Freigabelink kopiert',
749
+ download_svg_file: 'SVG-Datei herunterladen',
750
+ download_png_file: 'PNG-Datei herunterladen',
751
+ },
752
+ options: {
753
+ title: 'Optionen',
754
+ preview_relationships: 'Beziehungen vorschauen',
755
+ show_relationship_comment: 'Beziehungskommentar anzeigen',
756
+ show_key: 'Schlüssel anzeigen',
757
+ show_column_comment: 'Spaltenkommentar anzeigen',
758
+ hide_columns: 'Spalten ausblenden',
759
+ snapshot_mode: 'Schnappschussmodus',
760
+ snapshot_mode_hint: 'Rastert das Diagramm nach jedem Rendern. Verschieben und Zoomen werden in Safari und Firefox deutlich schneller, allerdings auf Kosten der Textauswahl.',
761
+ },
762
+ models: {
763
+ title: 'Modelle',
764
+ select: 'Auswählen',
765
+ all: 'Alle',
766
+ none: 'Keine',
767
+ filter: 'Filtern',
768
+ no_model_file: 'Keine Modelldatei',
769
+ },
770
+ empty: {
771
+ title: 'Keine Modelle ausgewählt',
772
+ hint: 'Wählen Sie Modelle in der Seitenleiste aus, um das ERD darzustellen.',
773
+ },
774
+ errors: {
775
+ render_failed: 'Mermaid konnte die aktuelle Auswahl nicht darstellen. Details finden Sie in der Browser-Konsole.',
776
+ snapshot_failed: 'Das Schnappschussbild konnte nicht erstellt werden. Es wird auf die SVG-Darstellung zurückgegriffen.',
777
+ download_failed: 'Download fehlgeschlagen. Details finden Sie in der Browser-Konsole.',
778
+ copy_failed: 'Kopieren in die Zwischenablage fehlgeschlagen. Browser erfordern eine kürzliche Nutzeraktion und einen sicheren Kontext.',
779
+ dismiss: 'Schließen',
780
+ },
781
+ tab: {
782
+ erd: 'ERD',
783
+ code: 'Code',
784
+ },
785
+ controls: {
786
+ movement: 'Bewegung',
787
+ zoom: 'Zoom',
788
+ space_drag: 'Leertaste + Maus ziehen',
789
+ middle_drag: 'Mittelklick + Ziehen',
790
+ mouse_wheel: 'Mausrad',
791
+ pinch: 'Zwei-Finger-Zoom',
792
+ reset_view: 'Ansicht zurücksetzen',
793
+ }
794
+ },
795
+ it: {
796
+ actions: {
797
+ title: 'Azioni',
798
+ reset: 'Reimposta',
799
+ copy_mermaid_code: 'Copia codice Mermaid',
800
+ copied_mermaid_code: 'Codice Mermaid copiato',
801
+ copy_markdown_code: 'Copia codice Markdown',
802
+ copied_markdown_code: 'Codice Markdown copiato',
803
+ copy_url: 'Copia link di condivisione',
804
+ copied_url: 'Link di condivisione copiato',
805
+ download_svg_file: 'Scarica file SVG',
806
+ download_png_file: 'Scarica file PNG',
807
+ },
808
+ options: {
809
+ title: 'Opzioni',
810
+ preview_relationships: 'Anteprima relazioni',
811
+ show_relationship_comment: 'Mostra commento della relazione',
812
+ show_key: 'Mostra chiave',
813
+ show_column_comment: 'Mostra commento della colonna',
814
+ hide_columns: 'Nascondi colonne',
815
+ snapshot_mode: 'Modalità istantanea',
816
+ snapshot_mode_hint: 'Rasterizza il diagramma dopo ogni rendering. Lo spostamento e lo zoom diventano molto più veloci su Safari e Firefox, a scapito della selezione del testo.',
817
+ },
818
+ models: {
819
+ title: 'Modelli',
820
+ select: 'Seleziona',
821
+ all: 'Tutti',
822
+ none: 'Nessuno',
823
+ filter: 'Filtra',
824
+ no_model_file: 'Nessun file di modello',
825
+ },
826
+ empty: {
827
+ title: 'Nessun modello selezionato',
828
+ hint: 'Seleziona i modelli dalla barra laterale per visualizzare l\'ERD.',
829
+ },
830
+ errors: {
831
+ render_failed: 'Mermaid non è riuscito a visualizzare la selezione corrente. Controlla la console del browser per i dettagli.',
832
+ snapshot_failed: 'Impossibile generare l\'immagine istantanea. Ritorno al rendering SVG.',
833
+ download_failed: 'Download non riuscito. Controlla la console del browser per i dettagli.',
834
+ copy_failed: 'Copia negli appunti non riuscita. I browser richiedono un\'azione utente recente e un contesto sicuro.',
835
+ dismiss: 'Chiudi',
836
+ },
837
+ tab: {
838
+ erd: 'ERD',
839
+ code: 'Codice',
840
+ },
841
+ controls: {
842
+ movement: 'Movimento',
843
+ zoom: 'Zoom',
844
+ space_drag: 'Spazio + trascina con il mouse',
845
+ middle_drag: 'Clic centrale + trascina',
846
+ mouse_wheel: 'Rotellina del mouse',
847
+ pinch: 'Pizzica per zoomare',
848
+ reset_view: 'Reimposta vista',
849
+ }
850
+ },
851
+ 'pt-BR': {
852
+ actions: {
853
+ title: 'Ações',
854
+ reset: 'Redefinir',
855
+ copy_mermaid_code: 'Copiar código Mermaid',
856
+ copied_mermaid_code: 'Código Mermaid copiado',
857
+ copy_markdown_code: 'Copiar código Markdown',
858
+ copied_markdown_code: 'Código Markdown copiado',
859
+ copy_url: 'Copiar link de compartilhamento',
860
+ copied_url: 'Link de compartilhamento copiado',
861
+ download_svg_file: 'Baixar arquivo SVG',
862
+ download_png_file: 'Baixar arquivo PNG',
863
+ },
864
+ options: {
865
+ title: 'Opções',
866
+ preview_relationships: 'Pré-visualizar relacionamentos',
867
+ show_relationship_comment: 'Mostrar comentário do relacionamento',
868
+ show_key: 'Mostrar chave',
869
+ show_column_comment: 'Mostrar comentário da coluna',
870
+ hide_columns: 'Ocultar colunas',
871
+ snapshot_mode: 'Modo instantâneo',
872
+ snapshot_mode_hint: 'Rasteriza o diagrama após cada renderização. Mover e dar zoom ficam muito mais rápidos no Safari e no Firefox, ao custo da seleção de texto.',
873
+ },
874
+ models: {
875
+ title: 'Modelos',
876
+ select: 'Selecionar',
877
+ all: 'Todos',
878
+ none: 'Nenhum',
879
+ filter: 'Filtrar',
880
+ no_model_file: 'Sem arquivo de modelo',
881
+ },
882
+ empty: {
883
+ title: 'Nenhum modelo selecionado',
884
+ hint: 'Escolha modelos na barra lateral para renderizar o ERD.',
885
+ },
886
+ errors: {
887
+ render_failed: 'O Mermaid não conseguiu renderizar a seleção atual. Verifique o console do navegador para mais detalhes.',
888
+ snapshot_failed: 'Não foi possível gerar a imagem do instantâneo. Voltando à renderização SVG.',
889
+ download_failed: 'Falha no download. Verifique o console do navegador para mais detalhes.',
890
+ copy_failed: 'Falha ao copiar para a área de transferência. Os navegadores exigem uma ação recente do usuário e um contexto seguro.',
891
+ dismiss: 'Dispensar',
892
+ },
893
+ tab: {
894
+ erd: 'ERD',
895
+ code: 'Código',
896
+ },
897
+ controls: {
898
+ movement: 'Movimento',
899
+ zoom: 'Zoom',
900
+ space_drag: 'Espaço + arrastar com o mouse',
901
+ middle_drag: 'Clique do meio + arrastar',
902
+ mouse_wheel: 'Roda do mouse',
903
+ pinch: 'Pinçar para ampliar/reduzir',
904
+ reset_view: 'Redefinir visualização',
905
+ }
906
+ },
907
+ ru: {
908
+ actions: {
909
+ title: 'Действия',
910
+ reset: 'Сбросить',
911
+ copy_mermaid_code: 'Копировать код Mermaid',
912
+ copied_mermaid_code: 'Код Mermaid скопирован',
913
+ copy_markdown_code: 'Копировать код Markdown',
914
+ copied_markdown_code: 'Код Markdown скопирован',
915
+ copy_url: 'Копировать ссылку для обмена',
916
+ copied_url: 'Ссылка для обмена скопирована',
917
+ download_svg_file: 'Скачать файл SVG',
918
+ download_png_file: 'Скачать файл PNG',
919
+ },
920
+ options: {
921
+ title: 'Параметры',
922
+ preview_relationships: 'Предпросмотр связей',
923
+ show_relationship_comment: 'Показать комментарий связи',
924
+ show_key: 'Показать ключ',
925
+ show_column_comment: 'Показать комментарий столбца',
926
+ hide_columns: 'Скрыть столбцы',
927
+ snapshot_mode: 'Режим снимка',
928
+ snapshot_mode_hint: 'Растрировать диаграмму после каждой отрисовки. Панорамирование и масштабирование становятся намного быстрее в Safari и Firefox, но текст нельзя будет выделить.',
929
+ },
930
+ models: {
931
+ title: 'Модели',
932
+ select: 'Выбрать',
933
+ all: 'Все',
934
+ none: 'Нет',
935
+ filter: 'Фильтр',
936
+ no_model_file: 'Нет файла модели',
937
+ },
938
+ empty: {
939
+ title: 'Модели не выбраны',
940
+ hint: 'Выберите модели на боковой панели, чтобы отобразить ERD.',
941
+ },
942
+ errors: {
943
+ render_failed: 'Mermaid не удалось отобразить текущий выбор. Подробности смотрите в консоли браузера.',
944
+ snapshot_failed: 'Не удалось создать изображение снимка. Возврат к отрисовке SVG.',
945
+ download_failed: 'Не удалось скачать. Подробности смотрите в консоли браузера.',
946
+ copy_failed: 'Не удалось скопировать в буфер обмена. Браузеры требуют недавнего действия пользователя и безопасного контекста.',
947
+ dismiss: 'Закрыть',
948
+ },
949
+ tab: {
950
+ erd: 'ERD',
951
+ code: 'Код',
952
+ },
953
+ controls: {
954
+ movement: 'Перемещение',
955
+ zoom: 'Масштаб',
956
+ space_drag: 'Пробел + перетаскивание мышью',
957
+ middle_drag: 'Средняя кнопка + перетаскивание',
958
+ mouse_wheel: 'Колесо мыши',
959
+ pinch: 'Щипок для масштабирования',
960
+ reset_view: 'Сбросить вид',
961
+ }
962
+ },
963
+ ar: {
964
+ actions: {
965
+ title: 'الإجراءات',
966
+ reset: 'إعادة تعيين',
967
+ copy_mermaid_code: 'نسخ كود Mermaid',
968
+ copied_mermaid_code: 'تم نسخ كود Mermaid',
969
+ copy_markdown_code: 'نسخ كود Markdown',
970
+ copied_markdown_code: 'تم نسخ كود Markdown',
971
+ copy_url: 'نسخ رابط المشاركة',
972
+ copied_url: 'تم نسخ رابط المشاركة',
973
+ download_svg_file: 'تنزيل ملف SVG',
974
+ download_png_file: 'تنزيل ملف PNG',
975
+ },
976
+ options: {
977
+ title: 'الخيارات',
978
+ preview_relationships: 'معاينة العلاقات',
979
+ show_relationship_comment: 'إظهار تعليق العلاقة',
980
+ show_key: 'إظهار المفتاح',
981
+ show_column_comment: 'إظهار تعليق العمود',
982
+ hide_columns: 'إخفاء الأعمدة',
983
+ snapshot_mode: 'وضع اللقطة',
984
+ snapshot_mode_hint: 'تحويل المخطط إلى صورة نقطية بعد كل عرض. يصبح التحريك والتكبير أسرع بكثير في Safari وFirefox، لكن على حساب إمكانية تحديد النص.',
985
+ },
986
+ models: {
987
+ title: 'النماذج',
988
+ select: 'تحديد',
989
+ all: 'الكل',
990
+ none: 'لا شيء',
991
+ filter: 'تصفية',
992
+ no_model_file: 'لا يوجد ملف نموذج',
993
+ },
994
+ empty: {
995
+ title: 'لم يتم تحديد أي نموذج',
996
+ hint: 'اختر النماذج من الشريط الجانبي لعرض المخطط (ERD).',
997
+ },
998
+ errors: {
999
+ render_failed: 'فشل Mermaid في عرض التحديد الحالي. تحقق من وحدة تحكم المتصفح لمزيد من التفاصيل.',
1000
+ snapshot_failed: 'تعذّر إنشاء صورة اللقطة. سيتم الرجوع إلى عرض SVG.',
1001
+ download_failed: 'فشل التنزيل. تحقق من وحدة تحكم المتصفح لمزيد من التفاصيل.',
1002
+ copy_failed: 'فشل النسخ إلى الحافظة. تتطلب المتصفحات إجراءً حديثًا من المستخدم وسياقًا آمنًا.',
1003
+ dismiss: 'إغلاق',
1004
+ },
1005
+ tab: {
1006
+ erd: 'ERD',
1007
+ code: 'الكود',
1008
+ },
1009
+ controls: {
1010
+ movement: 'الحركة',
1011
+ zoom: 'التكبير',
1012
+ space_drag: 'المسافة + سحب الماوس',
1013
+ middle_drag: 'النقر الأوسط + السحب',
1014
+ mouse_wheel: 'عجلة الماوس',
1015
+ pinch: 'القرص للتكبير/التصغير',
1016
+ reset_view: 'إعادة تعيين العرض',
1017
+ }
445
1018
  }
446
1019
  }
447
1020
  </script>
@@ -807,6 +1380,14 @@
807
1380
  const onCopyUrl = () => clipboardWrite(location.href, isCopiedUrl)
808
1381
 
809
1382
  const mermaidErd = Vue.computed(() => {
1383
+ // Comment metadata is arbitrary DB text. A newline would split a
1384
+ // label or terminate a `%%` line mid-diagram, and a literal `"`
1385
+ // closes a quoted label early — so collapse newlines to a space and
1386
+ // escape `"` as Mermaid's `#quot;` entity. Kept in lockstep with the
1387
+ // Ruby renderer (lib/rails-mermaid_erd/mermaid_text.rb).
1388
+ const oneLine = (v) => String(v ?? '').replace(/[\r\n]+/g, ' ')
1389
+ const quoted = (v) => `"${oneLine(v).replace(/"/g, '#quot;')}"`
1390
+
810
1391
  const lines = []
811
1392
  lines.push('erDiagram')
812
1393
  lines.push(' %% --------------------------------------------------------')
@@ -817,13 +1398,13 @@
817
1398
  lines.push('')
818
1399
 
819
1400
  filteredData.value.Models.forEach(model => {
820
- lines.push(` %% table name: ${model.TableName}`)
821
- lines.push(` %% table comment: ${model.TableComment}`)
1401
+ lines.push(` %% table name: ${oneLine(model.TableName)}`)
1402
+ lines.push(` %% table comment: ${oneLine(model.TableComment)}`)
822
1403
  lines.push(` ${model.ModelName.replace(/:/g, '-')} {`)
823
1404
 
824
1405
  if (!isHideColumns.value) {
825
1406
  model.Columns.forEach(column => {
826
- lines.push(` ${column.type} ${column.name} ${isShowKey.value ? column.key : ''} ${isShowComment.value ? `"${column.comment || ''}"` : ''}`)
1407
+ lines.push(` ${column.type} ${column.name} ${isShowKey.value ? column.key : ''} ${isShowComment.value ? quoted(column.comment) : ''}`)
827
1408
  })
828
1409
  }
829
1410
 
@@ -833,7 +1414,7 @@
833
1414
 
834
1415
  filteredData.value.Relations.forEach(relation => {
835
1416
  if (isShowRelationComment.value) {
836
- lines.push(` ${relation.LeftModelName.replace(/:/g, '-')} ${relation.LeftValue}${relation.Line}${relation.RightValue} ${relation.RightModelName.replace(/:/g, '-')} : "${relation.Comment}"`)
1417
+ lines.push(` ${relation.LeftModelName.replace(/:/g, '-')} ${relation.LeftValue}${relation.Line}${relation.RightValue} ${relation.RightModelName.replace(/:/g, '-')} : ${quoted(relation.Comment)}`)
837
1418
  } else {
838
1419
  lines.push(` ${relation.LeftModelName.replace(/:/g, '-')} ${relation.LeftValue}${relation.Line}${relation.RightValue} ${relation.RightModelName.replace(/:/g, '-')} : ""`)
839
1420
  }
@@ -1205,14 +1786,25 @@
1205
1786
  if (virtualListContainer.value) virtualListContainer.value.scrollTop = 0
1206
1787
  })
1207
1788
 
1789
+ const resolveLocale = (raw) => {
1790
+ if (!raw) return 'en'
1791
+ const codes = window.locales.map((l) => l.code)
1792
+ const exact = codes.find((c) => c.toLowerCase() === raw.toLowerCase())
1793
+ if (exact) return exact
1794
+ const base = raw.toLowerCase().split('-')[0]
1795
+ // zh is the only language that ships two variants, so route it by script/region;
1796
+ // every other region variant (fr-FR, pt-PT, ...) falls back to its base language.
1797
+ if (base === 'zh') return /hant|tw|hk|mo/.test(raw.toLowerCase()) ? 'zh-TW' : 'zh-CN'
1798
+ const baseMatch = codes.find((c) => c.toLowerCase().split('-')[0] === base)
1799
+ return baseMatch || 'en'
1800
+ }
1801
+
1208
1802
  const setLanguage = (l) => {
1209
- if (Object.keys(window.i18n).includes(l)) {
1210
- language.value = l
1211
- document.documentElement.lang = l
1212
- } else {
1213
- language.value = 'en'
1214
- document.documentElement.lang = 'en'
1215
- }
1803
+ const resolved = resolveLocale(l)
1804
+ language.value = resolved
1805
+ const meta = window.locales.find((x) => x.code === resolved)
1806
+ document.documentElement.lang = resolved
1807
+ document.documentElement.dir = (meta && meta.dir) || 'ltr'
1216
1808
  }
1217
1809
 
1218
1810
  Vue.onMounted(() => {
@@ -1267,6 +1859,7 @@
1267
1859
  isEmptySelection,
1268
1860
  renderError,
1269
1861
  language,
1862
+ locales: window.locales,
1270
1863
  mermaidErd,
1271
1864
  onChange,
1272
1865
  onCopyMarkdown,
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails-mermaid_erd
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - 肥溜め
@@ -106,6 +106,7 @@ files:
106
106
  - lib/rails-mermaid_erd.rb
107
107
  - lib/rails-mermaid_erd/builder.rb
108
108
  - lib/rails-mermaid_erd/configuration.rb
109
+ - lib/rails-mermaid_erd/mermaid_text.rb
109
110
  - lib/rails-mermaid_erd/railtie.rb
110
111
  - lib/rails-mermaid_erd/version.rb
111
112
  - lib/tasks/mermaid_erd.rake