testimonials 0.1.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.
Files changed (66) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +8 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README.md +175 -0
  5. data/Rakefile +11 -0
  6. data/app/controllers/testimonials/api/base_controller.rb +30 -0
  7. data/app/controllers/testimonials/api/stats_controller.rb +20 -0
  8. data/app/controllers/testimonials/api/testimonials_controller.rb +41 -0
  9. data/app/controllers/testimonials/application_controller.rb +50 -0
  10. data/app/controllers/testimonials/collection_controller.rb +18 -0
  11. data/app/controllers/testimonials/events_controller.rb +25 -0
  12. data/app/controllers/testimonials/media_controller.rb +48 -0
  13. data/app/controllers/testimonials/nps_controller.rb +71 -0
  14. data/app/controllers/testimonials/nps_responses_controller.rb +25 -0
  15. data/app/controllers/testimonials/testimonials_controller.rb +194 -0
  16. data/app/controllers/testimonials/widgets_controller.rb +36 -0
  17. data/app/helpers/testimonials/widget_helper.rb +83 -0
  18. data/app/models/testimonials/application_record.rb +7 -0
  19. data/app/models/testimonials/nps_response.rb +24 -0
  20. data/app/models/testimonials/prompt_event.rb +60 -0
  21. data/app/models/testimonials/testimonial.rb +53 -0
  22. data/app/views/layouts/testimonials/application.html.erb +118 -0
  23. data/app/views/layouts/testimonials/collection.html.erb +23 -0
  24. data/app/views/testimonials/collection/show.html.erb +12 -0
  25. data/app/views/testimonials/nps_responses/index.html.erb +67 -0
  26. data/app/views/testimonials/testimonials/index.html.erb +108 -0
  27. data/app/views/testimonials/testimonials/show.html.erb +105 -0
  28. data/config/locales/testimonials.ar.yml +101 -0
  29. data/config/locales/testimonials.bg.yml +101 -0
  30. data/config/locales/testimonials.bn.yml +101 -0
  31. data/config/locales/testimonials.de.yml +101 -0
  32. data/config/locales/testimonials.el.yml +101 -0
  33. data/config/locales/testimonials.en.yml +101 -0
  34. data/config/locales/testimonials.es.yml +101 -0
  35. data/config/locales/testimonials.fr.yml +101 -0
  36. data/config/locales/testimonials.hi.yml +101 -0
  37. data/config/locales/testimonials.hr.yml +101 -0
  38. data/config/locales/testimonials.id.yml +101 -0
  39. data/config/locales/testimonials.it.yml +101 -0
  40. data/config/locales/testimonials.ja.yml +101 -0
  41. data/config/locales/testimonials.ko.yml +101 -0
  42. data/config/locales/testimonials.lb.yml +101 -0
  43. data/config/locales/testimonials.nl.yml +101 -0
  44. data/config/locales/testimonials.pl.yml +101 -0
  45. data/config/locales/testimonials.pt.yml +101 -0
  46. data/config/locales/testimonials.ro.yml +101 -0
  47. data/config/locales/testimonials.ru.yml +101 -0
  48. data/config/locales/testimonials.th.yml +101 -0
  49. data/config/locales/testimonials.tr.yml +101 -0
  50. data/config/locales/testimonials.uk.yml +101 -0
  51. data/config/locales/testimonials.ur.yml +101 -0
  52. data/config/locales/testimonials.vi.yml +101 -0
  53. data/config/locales/testimonials.zh-CN.yml +101 -0
  54. data/config/routes.rb +29 -0
  55. data/lib/generators/testimonials/install/install_generator.rb +42 -0
  56. data/lib/generators/testimonials/install/templates/create_testimonials_tables.rb.tt +53 -0
  57. data/lib/generators/testimonials/install/templates/initializer.rb +70 -0
  58. data/lib/testimonials/configuration.rb +129 -0
  59. data/lib/testimonials/dashboard.js +33 -0
  60. data/lib/testimonials/engine.rb +16 -0
  61. data/lib/testimonials/prompt_helper.rb +15 -0
  62. data/lib/testimonials/version.rb +5 -0
  63. data/lib/testimonials/widget.js +1045 -0
  64. data/lib/testimonials/widget.rb +170 -0
  65. data/lib/testimonials.rb +69 -0
  66. metadata +132 -0
@@ -0,0 +1,101 @@
1
+ tr:
2
+ testimonials:
3
+ questions:
4
+ - "Kimsiniz ve %{app} uygulamasını nasıl kullanıyorsunuz?"
5
+ - "%{app} size nasıl yardımcı oldu?"
6
+ - "%{app} uygulamasının en iyi yanı nedir?"
7
+ consent: "Bu yorumun sosyal medyada ve diğer pazarlama çalışmalarında kullanılmasına izin veriyorum."
8
+ cta: "Yorum bırak"
9
+ update_title: "Yorumunuzu güncelleyin"
10
+ enjoying: "%{app} hoşunuza gidiyor mu?"
11
+ not_now: "Şimdi değil"
12
+ rate_aria: "5 üzerinden %{count} puan ver"
13
+ share_title: "Deneyiminizi paylaşın"
14
+ promoter_title: "Bunu duymak güzel! Herkese açık söylemek ister misiniz?"
15
+ questions_title: "Sorular"
16
+ message: "Görüşünüz"
17
+ message_placeholder: "Bir arkadaşınıza %{app} hakkında ne söylerdiniz?"
18
+ record_video: "Video kaydet"
19
+ record_video_hint: "Kısa bir video, bir sayfa metinden fazlasını anlatır."
20
+ name: "Adınız"
21
+ email: "E-postanız"
22
+ title_company: "Unvan, şirket"
23
+ photo: "Fotoğrafınız"
24
+ optional: "isteğe bağlı"
25
+ submit: "Gönder"
26
+ cancel: "İptal"
27
+ close: "Kapat"
28
+ thanks: "Çok teşekkürler!"
29
+ video_check_title: "Kamera kontrolü"
30
+ video_hint: "En fazla %{seconds} saniye. Göndermeden önce izleyebilirsiniz."
31
+ start_recording: "Kaydı başlat"
32
+ stop_recording: "Bitir"
33
+ record_again: "Yeniden kaydet"
34
+ use_video: "Bu videoyu kullan"
35
+ upload_instead: "Bunun yerine video dosyası yükle"
36
+ video_attached: "Video eklendi"
37
+ remove: "Kaldır"
38
+ nps_question: "%{app} uygulamasını bir arkadaşınıza veya meslektaşınıza önerme olasılığınız nedir?"
39
+ nps_low: "Hiç olası değil"
40
+ nps_high: "Son derece olası"
41
+ nps_comment_label: "Puanınızın ana nedeni nedir?"
42
+ error_blank: "Lütfen bir şeyler yazın veya video kaydedin."
43
+ error_contact: "Lütfen adınızı ve e-postanızı girin."
44
+ error_save: "Gönderilemedi. Lütfen tekrar deneyin."
45
+ error_video_too_large: "Video çok büyük (en fazla %{size} MB)."
46
+ error_camera: "Kameraya erişilemedi. Bunun yerine bir video dosyası yükleyebilirsiniz."
47
+ error_rate_limited: "Çok fazla gönderim. Lütfen biraz bekleyip tekrar deneyin."
48
+ page:
49
+ title: "%{app} deneyiminizi paylaşın"
50
+ subtitle: "Sözleriniz başkalarının karar vermesine yardımcı olur — teşekkürler!"
51
+ kinds:
52
+ text: "Metin"
53
+ video: "Video"
54
+ sources:
55
+ widget: "Uygulama içi bileşen"
56
+ page: "Toplama sayfası"
57
+ nps: "NPS takibi"
58
+ collection_page: "Görüş isteyin"
59
+ download_video: "Videoyu indir"
60
+ statuses:
61
+ pending: "Beklemede"
62
+ approved: "Onaylandı"
63
+ archived: "Arşivlendi"
64
+ dashboard:
65
+ title: "Görüşler"
66
+ nps: "NPS"
67
+ all_kinds: "Tüm türler"
68
+ search: "Ara"
69
+ search_placeholder: "Metin, ad, e-posta ara…"
70
+ rating: "Puan"
71
+ testimonial: "Görüş"
72
+ from: "Kimden"
73
+ consent: "Onay"
74
+ no_consent: "Yayın onayı yok. API üzerinden sunulmaz."
75
+ received: "Alındı"
76
+ featured: "Öne çıkan"
77
+ approve: "Onayla"
78
+ feature: "Öne çıkar"
79
+ unfeature: "Öne çıkarmayı kaldır"
80
+ best_line: "En iyi cümle"
81
+ best_line_hint: "Sitenizde gösterilecek alıntı. Tam metni kullanmak için boş bırakın. Videolarda söylenen en iyi cümleyi yazın."
82
+ save_best_line: "Kaydet"
83
+ email: "E-posta"
84
+ source: "Kaynak"
85
+ page: "Sayfa"
86
+ locale: "Dil"
87
+ browser: "Tarayıcı"
88
+ empty: "Henüz burada bir şey yok."
89
+ newer: "← Daha yeni"
90
+ older: "Daha eski →"
91
+ move_to_pending: "Beklemeye al"
92
+ move_to_approved: "Onayla"
93
+ move_to_archived: "Arşivle"
94
+ delete: "Sil"
95
+ delete_confirm: "Bu görüş silinsin mi?"
96
+ nps_score: "NPS puanı"
97
+ promoters: "Destekleyenler (9–10)"
98
+ passives: "Pasifler (7–8)"
99
+ detractors: "Eleştirenler (0–6)"
100
+ score: "Puan"
101
+ comment: "Yorum"
@@ -0,0 +1,101 @@
1
+ uk:
2
+ testimonials:
3
+ questions:
4
+ - "Хто ви і як ви використовуєте %{app}?"
5
+ - "Як %{app} вам допоміг?"
6
+ - "Що найкраще в %{app}?"
7
+ consent: "Я дозволяю використовувати цей відгук у соцмережах та інших маркетингових матеріалах."
8
+ cta: "Залишити відгук"
9
+ update_title: "Оновити ваш відгук"
10
+ enjoying: "Подобається %{app}?"
11
+ not_now: "Не зараз"
12
+ rate_aria: "Оцінити на %{count} з 5"
13
+ share_title: "Поділіться своїм досвідом"
14
+ promoter_title: "Приємно чути! Розкажете про це публічно?"
15
+ questions_title: "Питання"
16
+ message: "Ваш відгук"
17
+ message_placeholder: "Що б ви розповіли другові про %{app}?"
18
+ record_video: "Записати відео"
19
+ record_video_hint: "Коротке відео скаже більше, ніж сторінка тексту."
20
+ name: "Ваше ім'я"
21
+ email: "Ваша електронна пошта"
22
+ title_company: "Посада, компанія"
23
+ photo: "Ваше фото"
24
+ optional: "необов'язково"
25
+ submit: "Надіслати"
26
+ cancel: "Скасувати"
27
+ close: "Закрити"
28
+ thanks: "Щиро дякуємо!"
29
+ video_check_title: "Перевірка камери"
30
+ video_hint: "До %{seconds} секунд. Ви зможете переглянути перед надсиланням."
31
+ start_recording: "Почати запис"
32
+ stop_recording: "Завершити"
33
+ record_again: "Записати ще раз"
34
+ use_video: "Використати це відео"
35
+ upload_instead: "Натомість завантажити відеофайл"
36
+ video_attached: "Відео додано"
37
+ remove: "Прибрати"
38
+ nps_question: "Наскільки ймовірно, що ви порекомендуєте %{app} другові чи колезі?"
39
+ nps_low: "Зовсім неймовірно"
40
+ nps_high: "Дуже ймовірно"
41
+ nps_comment_label: "Яка головна причина вашої оцінки?"
42
+ error_blank: "Напишіть щось або запишіть відео."
43
+ error_contact: "Вкажіть ваше ім'я та електронну пошту."
44
+ error_save: "Не вдалося надіслати. Спробуйте ще раз."
45
+ error_video_too_large: "Відео завелике (макс. %{size} МБ)."
46
+ error_camera: "Немає доступу до камери. Можете натомість завантажити відеофайл."
47
+ error_rate_limited: "Забагато надсилань. Зачекайте хвилинку і спробуйте знову."
48
+ page:
49
+ title: "Поділіться своїм досвідом із %{app}"
50
+ subtitle: "Ваші слова допомагають іншим зважитися — дякуємо!"
51
+ kinds:
52
+ text: "Текст"
53
+ video: "Відео"
54
+ sources:
55
+ widget: "Віджет у застосунку"
56
+ page: "Сторінка збору"
57
+ nps: "Після NPS"
58
+ collection_page: "Попросити відгуки"
59
+ download_video: "Завантажити відео"
60
+ statuses:
61
+ pending: "Очікує"
62
+ approved: "Схвалено"
63
+ archived: "В архіві"
64
+ dashboard:
65
+ title: "Відгуки"
66
+ nps: "NPS"
67
+ all_kinds: "Усі типи"
68
+ search: "Пошук"
69
+ search_placeholder: "Шукати текст, ім'я, пошту…"
70
+ rating: "Оцінка"
71
+ testimonial: "Відгук"
72
+ from: "Від"
73
+ consent: "Згода"
74
+ no_consent: "Немає згоди на публікацію. Не віддається через API."
75
+ received: "Отримано"
76
+ featured: "Обране"
77
+ approve: "Схвалити"
78
+ feature: "В обране"
79
+ unfeature: "Прибрати з обраного"
80
+ best_line: "Найкраща фраза"
81
+ best_line_hint: "Цитата, яку показуватиме ваш сайт. Залиште порожнім, щоб використати повний текст. Для відео впишіть найкращу сказану фразу."
82
+ save_best_line: "Зберегти"
83
+ email: "Пошта"
84
+ source: "Джерело"
85
+ page: "Сторінка"
86
+ locale: "Мова"
87
+ browser: "Браузер"
88
+ empty: "Поки що тут нічого немає."
89
+ newer: "← Новіші"
90
+ older: "Старіші →"
91
+ move_to_pending: "Позначити як очікує"
92
+ move_to_approved: "Схвалити"
93
+ move_to_archived: "В архів"
94
+ delete: "Видалити"
95
+ delete_confirm: "Видалити цей відгук?"
96
+ nps_score: "Показник NPS"
97
+ promoters: "Промоутери (9–10)"
98
+ passives: "Нейтральні (7–8)"
99
+ detractors: "Критики (0–6)"
100
+ score: "Оцінка"
101
+ comment: "Коментар"
@@ -0,0 +1,101 @@
1
+ ur:
2
+ testimonials:
3
+ questions:
4
+ - "آپ کون ہیں اور %{app} کیسے استعمال کرتے ہیں؟"
5
+ - "%{app} نے آپ کی کیسے مدد کی؟"
6
+ - "%{app} کی سب سے اچھی بات کیا ہے؟"
7
+ consent: "میں اس تعریفی کلمات کو سوشل میڈیا اور دیگر مارکیٹنگ سرگرمیوں میں استعمال کرنے کی اجازت دیتا/دیتی ہوں۔"
8
+ cta: "تبصرہ چھوڑیں"
9
+ update_title: "اپنا تبصرہ اپ ڈیٹ کریں"
10
+ enjoying: "%{app} پسند آ رہا ہے؟"
11
+ not_now: "ابھی نہیں"
12
+ rate_aria: "5 میں سے %{count} دیں"
13
+ share_title: "اپنا تجربہ شیئر کریں"
14
+ promoter_title: "سن کر خوشی ہوئی! کیا آپ یہ عوامی طور پر کہنا چاہیں گے؟"
15
+ questions_title: "سوالات"
16
+ message: "آپ کی رائے"
17
+ message_placeholder: "آپ کسی دوست کو %{app} کے بارے میں کیا بتائیں گے؟"
18
+ record_video: "ویڈیو ریکارڈ کریں"
19
+ record_video_hint: "ایک مختصر ویڈیو ایک صفحہ تحریر سے زیادہ کہتی ہے۔"
20
+ name: "آپ کا نام"
21
+ email: "آپ کا ای میل"
22
+ title_company: "عہدہ، کمپنی"
23
+ photo: "آپ کی تصویر"
24
+ optional: "اختیاری"
25
+ submit: "بھیجیں"
26
+ cancel: "منسوخ"
27
+ close: "بند کریں"
28
+ thanks: "بہت شکریہ!"
29
+ video_check_title: "کیمرے کی جانچ"
30
+ video_hint: "زیادہ سے زیادہ %{seconds} سیکنڈ۔ بھیجنے سے پہلے دیکھ سکتے ہیں۔"
31
+ start_recording: "ریکارڈنگ شروع کریں"
32
+ stop_recording: "مکمل کریں"
33
+ record_again: "دوبارہ ریکارڈ کریں"
34
+ use_video: "یہ ویڈیو استعمال کریں"
35
+ upload_instead: "اس کے بجائے ویڈیو فائل اپ لوڈ کریں"
36
+ video_attached: "ویڈیو منسلک ہے"
37
+ remove: "ہٹائیں"
38
+ nps_question: "کتنا امکان ہے کہ آپ %{app} کسی دوست یا ساتھی کو تجویز کریں؟"
39
+ nps_low: "بالکل امکان نہیں"
40
+ nps_high: "انتہائی امکان ہے"
41
+ nps_comment_label: "آپ کے اسکور کی بنیادی وجہ کیا ہے؟"
42
+ error_blank: "براہ کرم کچھ لکھیں یا ویڈیو ریکارڈ کریں۔"
43
+ error_contact: "براہ کرم اپنا نام اور ای میل درج کریں۔"
44
+ error_save: "بھیجا نہیں جا سکا۔ دوبارہ کوشش کریں۔"
45
+ error_video_too_large: "ویڈیو بہت بڑی ہے (زیادہ سے زیادہ %{size} MB)۔"
46
+ error_camera: "کیمرے تک رسائی نہیں ہو سکی۔ آپ اس کے بجائے ویڈیو فائل اپ لوڈ کر سکتے ہیں۔"
47
+ error_rate_limited: "بہت زیادہ اندراجات۔ تھوڑا انتظار کر کے دوبارہ کوشش کریں۔"
48
+ page:
49
+ title: "%{app} کے ساتھ اپنا تجربہ شیئر کریں"
50
+ subtitle: "آپ کے الفاظ دوسروں کو فیصلہ کرنے میں مدد دیتے ہیں — شکریہ!"
51
+ kinds:
52
+ text: "متن"
53
+ video: "ویڈیو"
54
+ sources:
55
+ widget: "ایپ کے اندر ویجیٹ"
56
+ page: "جمع کرنے کا صفحہ"
57
+ nps: "NPS فالو اپ"
58
+ collection_page: "تعریفی کلمات طلب کریں"
59
+ download_video: "ویڈیو ڈاؤن لوڈ کریں"
60
+ statuses:
61
+ pending: "زیر التوا"
62
+ approved: "منظور شدہ"
63
+ archived: "محفوظ شدہ"
64
+ dashboard:
65
+ title: "تعریفی کلمات"
66
+ nps: "NPS"
67
+ all_kinds: "تمام اقسام"
68
+ search: "تلاش"
69
+ search_placeholder: "متن، نام، ای میل تلاش کریں…"
70
+ rating: "درجہ بندی"
71
+ testimonial: "تعریفی کلمات"
72
+ from: "منجانب"
73
+ consent: "رضامندی"
74
+ no_consent: "اشاعت کی رضامندی نہیں۔ API سے فراہم نہیں کیا جاتا۔"
75
+ received: "موصول ہوا"
76
+ featured: "نمایاں"
77
+ approve: "منظور کریں"
78
+ feature: "نمایاں کریں"
79
+ unfeature: "نمایاں سے ہٹائیں"
80
+ best_line: "بہترین جملہ"
81
+ best_line_hint: "وہ اقتباس جو آپ کی سائٹ دکھائے گی۔ پورا متن استعمال کرنے کے لیے خالی چھوڑیں۔ ویڈیو کے لیے ان کا کہا بہترین جملہ لکھیں۔"
82
+ save_best_line: "محفوظ کریں"
83
+ email: "ای میل"
84
+ source: "ماخذ"
85
+ page: "صفحہ"
86
+ locale: "زبان"
87
+ browser: "براؤزر"
88
+ empty: "یہاں ابھی کچھ نہیں ہے۔"
89
+ newer: "→ نئے"
90
+ older: "پرانے ←"
91
+ move_to_pending: "زیر التوا نشان زد کریں"
92
+ move_to_approved: "منظور کریں"
93
+ move_to_archived: "محفوظ کریں"
94
+ delete: "حذف کریں"
95
+ delete_confirm: "یہ تعریفی کلمات حذف کریں؟"
96
+ nps_score: "NPS اسکور"
97
+ promoters: "حامی (9–10)"
98
+ passives: "غیر جانبدار (7–8)"
99
+ detractors: "ناقدین (0–6)"
100
+ score: "اسکور"
101
+ comment: "تبصرہ"
@@ -0,0 +1,101 @@
1
+ vi:
2
+ testimonials:
3
+ questions:
4
+ - "Bạn là ai và bạn dùng %{app} như thế nào?"
5
+ - "%{app} đã giúp bạn ra sao?"
6
+ - "Điều tuyệt nhất ở %{app} là gì?"
7
+ consent: "Tôi cho phép sử dụng cảm nhận này trên mạng xã hội và các hoạt động tiếp thị khác."
8
+ cta: "Để lại đánh giá"
9
+ update_title: "Cập nhật đánh giá của bạn"
10
+ enjoying: "Bạn thích %{app} chứ?"
11
+ not_now: "Để sau"
12
+ rate_aria: "Chấm %{count} trên 5"
13
+ share_title: "Chia sẻ trải nghiệm của bạn"
14
+ promoter_title: "Thật vui khi nghe điều đó! Bạn có muốn nói công khai không?"
15
+ questions_title: "Câu hỏi"
16
+ message: "Cảm nhận của bạn"
17
+ message_placeholder: "Bạn sẽ nói gì với một người bạn về %{app}?"
18
+ record_video: "Quay video"
19
+ record_video_hint: "Một video ngắn nói lên nhiều hơn một trang chữ."
20
+ name: "Tên của bạn"
21
+ email: "Email của bạn"
22
+ title_company: "Chức danh, công ty"
23
+ photo: "Ảnh của bạn"
24
+ optional: "không bắt buộc"
25
+ submit: "Gửi"
26
+ cancel: "Hủy"
27
+ close: "Đóng"
28
+ thanks: "Cảm ơn bạn rất nhiều!"
29
+ video_check_title: "Kiểm tra camera"
30
+ video_hint: "Tối đa %{seconds} giây. Bạn có thể xem lại trước khi gửi."
31
+ start_recording: "Bắt đầu quay"
32
+ stop_recording: "Hoàn tất"
33
+ record_again: "Quay lại"
34
+ use_video: "Dùng video này"
35
+ upload_instead: "Tải lên tệp video thay thế"
36
+ video_attached: "Đã đính kèm video"
37
+ remove: "Gỡ bỏ"
38
+ nps_question: "Khả năng bạn giới thiệu %{app} cho bạn bè hoặc đồng nghiệp là bao nhiêu?"
39
+ nps_low: "Hoàn toàn không"
40
+ nps_high: "Rất có thể"
41
+ nps_comment_label: "Lý do chính cho điểm số của bạn là gì?"
42
+ error_blank: "Vui lòng viết gì đó hoặc quay video."
43
+ error_contact: "Vui lòng nhập tên và email của bạn."
44
+ error_save: "Không gửi được. Vui lòng thử lại."
45
+ error_video_too_large: "Video quá lớn (tối đa %{size} MB)."
46
+ error_camera: "Không truy cập được camera. Bạn có thể tải lên tệp video thay thế."
47
+ error_rate_limited: "Gửi quá nhiều lần. Vui lòng đợi một chút rồi thử lại."
48
+ page:
49
+ title: "Chia sẻ trải nghiệm của bạn với %{app}"
50
+ subtitle: "Lời của bạn giúp người khác quyết định — cảm ơn bạn!"
51
+ kinds:
52
+ text: "Văn bản"
53
+ video: "Video"
54
+ sources:
55
+ widget: "Widget trong ứng dụng"
56
+ page: "Trang thu thập"
57
+ nps: "Tiếp nối NPS"
58
+ collection_page: "Xin cảm nhận"
59
+ download_video: "Tải video xuống"
60
+ statuses:
61
+ pending: "Đang chờ"
62
+ approved: "Đã duyệt"
63
+ archived: "Đã lưu trữ"
64
+ dashboard:
65
+ title: "Cảm nhận khách hàng"
66
+ nps: "NPS"
67
+ all_kinds: "Tất cả các loại"
68
+ search: "Tìm kiếm"
69
+ search_placeholder: "Tìm văn bản, tên, email…"
70
+ rating: "Đánh giá"
71
+ testimonial: "Cảm nhận"
72
+ from: "Từ"
73
+ consent: "Sự đồng ý"
74
+ no_consent: "Chưa đồng ý công bố. Không được cung cấp qua API."
75
+ received: "Đã nhận"
76
+ featured: "Nổi bật"
77
+ approve: "Duyệt"
78
+ feature: "Đặt nổi bật"
79
+ unfeature: "Bỏ nổi bật"
80
+ best_line: "Câu hay nhất"
81
+ best_line_hint: "Trích dẫn mà trang của bạn sẽ hiển thị. Để trống để dùng toàn văn. Với video, hãy gõ câu hay nhất họ đã nói."
82
+ save_best_line: "Lưu"
83
+ email: "Email"
84
+ source: "Nguồn"
85
+ page: "Trang"
86
+ locale: "Ngôn ngữ"
87
+ browser: "Trình duyệt"
88
+ empty: "Chưa có gì ở đây."
89
+ newer: "← Mới hơn"
90
+ older: "Cũ hơn →"
91
+ move_to_pending: "Đánh dấu đang chờ"
92
+ move_to_approved: "Duyệt"
93
+ move_to_archived: "Lưu trữ"
94
+ delete: "Xóa"
95
+ delete_confirm: "Xóa cảm nhận này?"
96
+ nps_score: "Điểm NPS"
97
+ promoters: "Người ủng hộ (9–10)"
98
+ passives: "Trung lập (7–8)"
99
+ detractors: "Người phản đối (0–6)"
100
+ score: "Điểm"
101
+ comment: "Bình luận"
@@ -0,0 +1,101 @@
1
+ zh-CN:
2
+ testimonials:
3
+ questions:
4
+ - "您是谁?您如何使用 %{app}?"
5
+ - "%{app} 是如何帮助您的?"
6
+ - "%{app} 最棒的地方是什么?"
7
+ consent: "我允许在社交媒体和其他营销活动中使用这条评价。"
8
+ cta: "写评价"
9
+ update_title: "更新您的评价"
10
+ enjoying: "喜欢 %{app} 吗?"
11
+ not_now: "暂不"
12
+ rate_aria: "评 %{count} 分(满分 5 分)"
13
+ share_title: "分享您的体验"
14
+ promoter_title: "很高兴听到!愿意公开说说吗?"
15
+ questions_title: "问题"
16
+ message: "您的评价"
17
+ message_placeholder: "您会如何向朋友介绍 %{app}?"
18
+ record_video: "录制视频"
19
+ record_video_hint: "一段简短的视频胜过一页文字。"
20
+ name: "您的姓名"
21
+ email: "您的邮箱"
22
+ title_company: "职位、公司"
23
+ photo: "您的照片"
24
+ optional: "可选"
25
+ submit: "发送"
26
+ cancel: "取消"
27
+ close: "关闭"
28
+ thanks: "非常感谢!"
29
+ video_check_title: "摄像头检查"
30
+ video_hint: "最长 %{seconds} 秒。发送前可以先查看。"
31
+ start_recording: "开始录制"
32
+ stop_recording: "完成"
33
+ record_again: "重新录制"
34
+ use_video: "使用此视频"
35
+ upload_instead: "改为上传视频文件"
36
+ video_attached: "已附加视频"
37
+ remove: "移除"
38
+ nps_question: "您向朋友或同事推荐 %{app} 的可能性有多大?"
39
+ nps_low: "完全不可能"
40
+ nps_high: "非常可能"
41
+ nps_comment_label: "您打这个分数的主要原因是什么?"
42
+ error_blank: "请写点什么或录制一段视频。"
43
+ error_contact: "请输入您的姓名和邮箱。"
44
+ error_save: "发送失败,请重试。"
45
+ error_video_too_large: "视频太大(最大 %{size} MB)。"
46
+ error_camera: "无法访问摄像头。您可以改为上传视频文件。"
47
+ error_rate_limited: "提交过于频繁,请稍候再试。"
48
+ page:
49
+ title: "分享您使用 %{app} 的体验"
50
+ subtitle: "您的评价能帮助他人做出选择——谢谢!"
51
+ kinds:
52
+ text: "文字"
53
+ video: "视频"
54
+ sources:
55
+ widget: "应用内组件"
56
+ page: "收集页面"
57
+ nps: "NPS 跟进"
58
+ collection_page: "征集用户评价"
59
+ download_video: "下载视频"
60
+ statuses:
61
+ pending: "待处理"
62
+ approved: "已批准"
63
+ archived: "已归档"
64
+ dashboard:
65
+ title: "用户评价"
66
+ nps: "NPS"
67
+ all_kinds: "所有类型"
68
+ search: "搜索"
69
+ search_placeholder: "搜索文字、姓名、邮箱…"
70
+ rating: "评分"
71
+ testimonial: "评价"
72
+ from: "来自"
73
+ consent: "授权"
74
+ no_consent: "未授权发布。API 不会提供此条。"
75
+ received: "收到时间"
76
+ featured: "精选"
77
+ approve: "批准"
78
+ feature: "设为精选"
79
+ unfeature: "取消精选"
80
+ best_line: "最佳金句"
81
+ best_line_hint: "网站将展示的引言。留空则使用全文。视频请写下他们说的最精彩的一句。"
82
+ save_best_line: "保存"
83
+ email: "邮箱"
84
+ source: "来源"
85
+ page: "页面"
86
+ locale: "语言"
87
+ browser: "浏览器"
88
+ empty: "这里还没有内容。"
89
+ newer: "← 较新"
90
+ older: "较旧 →"
91
+ move_to_pending: "标为待处理"
92
+ move_to_approved: "批准"
93
+ move_to_archived: "归档"
94
+ delete: "删除"
95
+ delete_confirm: "删除这条评价?"
96
+ nps_score: "NPS 得分"
97
+ promoters: "推荐者(9–10)"
98
+ passives: "中立者(7–8)"
99
+ detractors: "贬损者(0–6)"
100
+ score: "分数"
101
+ comment: "评论"
data/config/routes.rb ADDED
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ Testimonials::Engine.routes.draw do
4
+ # Everything with a fixed name goes first; the flat testimonial routes at
5
+ # the bottom own "/:id".
6
+ get 'widget.js', to: 'widgets#show', as: :widget
7
+ get 'dashboard.js', to: 'widgets#dashboard', as: :dashboard_script
8
+ get 'new', to: 'collection#show', as: :collection
9
+ resources :events, only: :create
10
+ resource :nps, only: :create, controller: 'nps'
11
+ resources :nps_responses, only: :index
12
+
13
+ # Read-only JSON for rendering testimonials anywhere.
14
+ namespace :api do
15
+ resources :testimonials, only: :index
16
+ get 'stats', to: 'stats#show'
17
+ end
18
+
19
+ # Media by testimonial id, gated (admin, author, or public_api + publishable).
20
+ get ':id/video', to: 'media#video', as: :testimonial_video, constraints: { id: /\d+/ }
21
+ get ':id/avatar', to: 'media#avatar', as: :testimonial_avatar, constraints: { id: /\d+/ }
22
+
23
+ # Flat, human URLs: the mount path IS the resource. /testimonials is the
24
+ # dashboard, POST /testimonials the widget endpoint, /testimonials/2 a testimonial.
25
+ resources :testimonials, path: '', only: %i[create index show update destroy],
26
+ constraints: { id: /\d+/ }
27
+
28
+ root to: 'testimonials#index'
29
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails/generators'
4
+ require 'rails/generators/active_record'
5
+
6
+ module Testimonials
7
+ module Generators
8
+ class InstallGenerator < Rails::Generators::Base
9
+ include ActiveRecord::Generators::Migration
10
+
11
+ source_root File.expand_path('templates', __dir__)
12
+
13
+ desc 'Installs testimonials: config initializer, migration, and engine mount.'
14
+
15
+ def create_initializer
16
+ copy_file 'initializer.rb', 'config/initializers/testimonials.rb'
17
+ end
18
+
19
+ def create_migration_file
20
+ migration_template 'create_testimonials_tables.rb.tt',
21
+ 'db/migrate/create_testimonials_tables.rb'
22
+ end
23
+
24
+ def mount_engine
25
+ route %(mount Testimonials::Engine => "/testimonials")
26
+ end
27
+
28
+ def post_install
29
+ say "\ntestimonials installed. Run `rails db:migrate`, then add", :green
30
+ say '`<%= testimonials_tag %>` before </body> in your layout.'
31
+ say 'Triage testimonials at /testimonials (development only until you set config.authorize_admin).'
32
+ say "Collect from outside the app via /testimonials/new.\n"
33
+ end
34
+
35
+ private
36
+
37
+ def migration_version
38
+ "[#{ActiveRecord::VERSION::MAJOR}.#{ActiveRecord::VERSION::MINOR}]"
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ class CreateTestimonialsTables < ActiveRecord::Migration<%= migration_version %>
4
+ def change
5
+ create_table :testimonials_testimonials do |t|
6
+ t.string :kind, null: false, default: 'text'
7
+ t.text :body
8
+ t.integer :rating
9
+ t.text :best_line
10
+ t.string :status, null: false, default: 'pending'
11
+ t.boolean :featured, null: false, default: false
12
+ t.boolean :consent_given, null: false, default: false
13
+ t.string :consent_text
14
+ t.string :author_id
15
+ t.string :name
16
+ t.string :email
17
+ t.string :title_company
18
+ t.string :source, null: false, default: 'widget'
19
+ t.string :page_url
20
+ t.string :user_agent
21
+ t.string :locale
22
+
23
+ t.timestamps
24
+ end
25
+ add_index :testimonials_testimonials, :status
26
+ add_index :testimonials_testimonials, %i[status consent_given]
27
+
28
+ create_table :testimonials_nps_responses do |t|
29
+ t.integer :score, null: false
30
+ t.text :comment
31
+ t.string :author_id
32
+ t.string :name
33
+ t.string :email
34
+ t.string :page_url
35
+ t.string :user_agent
36
+ t.string :locale
37
+
38
+ t.timestamps
39
+ end
40
+ add_index :testimonials_nps_responses, :score
41
+
42
+ create_table :testimonials_prompt_events do |t|
43
+ t.string :kind, null: false
44
+ t.string :action, null: false
45
+ t.string :author_id
46
+ t.string :visitor_token
47
+
48
+ t.timestamps
49
+ end
50
+ add_index :testimonials_prompt_events, %i[author_id kind]
51
+ add_index :testimonials_prompt_events, %i[visitor_token kind]
52
+ end
53
+ end