1use serde::{Deserialize, Serialize};
38
39#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
41pub enum Language {
42 #[default]
43 English,
44 German,
45 Chinese,
46 French,
47 Italian,
48 Russian,
49 Spanish,
50 PortugueseBrazil,
51}
52
53impl Language {
54 pub fn from_code(code: &str) -> Self {
56 match code.to_lowercase().as_str() {
57 "en" => Self::English,
58 "de" => Self::German,
59 "zh" | "zh-cn" | "zh-hans" => Self::Chinese,
60 "fr" => Self::French,
61 "it" => Self::Italian,
62 "ru" => Self::Russian,
63 "es" => Self::Spanish,
64 "pt" | "pt-br" => Self::PortugueseBrazil,
65 _ => Self::English,
66 }
67 }
68
69 pub fn code(&self) -> &'static str {
71 match self {
72 Self::English => "en",
73 Self::German => "de",
74 Self::Chinese => "zh",
75 Self::French => "fr",
76 Self::Italian => "it",
77 Self::Russian => "ru",
78 Self::Spanish => "es",
79 Self::PortugueseBrazil => "pt-BR",
80 }
81 }
82
83 pub fn native_name(&self) -> &'static str {
85 match self {
86 Self::English => "English",
87 Self::German => "Deutsch",
88 Self::Chinese => "简体中文",
89 Self::French => "Français",
90 Self::Italian => "Italiano",
91 Self::Russian => "Русский",
92 Self::Spanish => "Español",
93 Self::PortugueseBrazil => "Português (Brasil)",
94 }
95 }
96
97 pub fn all() -> &'static [Language] {
99 &[
100 Self::English,
101 Self::German,
102 Self::Chinese,
103 Self::French,
104 Self::Italian,
105 Self::Russian,
106 Self::Spanish,
107 Self::PortugueseBrazil,
108 ]
109 }
110}
111
112#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
114pub struct Locale {
115 pub meta: LocaleMeta,
116 pub diagram: DiagramLocale,
117 pub spectral: SpectralLocale,
118 pub luminaire: LuminaireLocale,
119 pub validation: ValidationLocale,
120 pub ui: UiLocale,
121 pub report: ReportLocale,
122 #[serde(default)]
123 pub comparison: ComparisonLocale,
124}
125
126#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
128pub struct LocaleMeta {
129 pub language: String,
130 pub code: String,
131 pub direction: String,
132}
133
134#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
136pub struct DiagramLocale {
137 pub units: DiagramUnits,
138 pub bug: DiagramBug,
139 pub axis: DiagramAxis,
140 pub plane: DiagramPlane,
141 pub angle: DiagramAngle,
142 pub metrics: DiagramMetrics,
143 pub title: DiagramTitle,
144 pub placeholder: DiagramPlaceholder,
145 pub cone: DiagramCone,
146 pub greenhouse: DiagramGreenhouse,
147}
148
149#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
150pub struct DiagramBug {
151 pub forward_light: String,
152 pub back_light: String,
153 pub uplight: String,
154 pub total: String,
155 pub sum: String,
156 pub zone_low: String,
157 pub zone_medium: String,
158 pub zone_high: String,
159 pub zone_very_high: String,
160 pub lumens: String,
161 pub percent: String,
162}
163
164#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
165pub struct DiagramUnits {
166 pub intensity: String,
167 pub intensity_short: String,
168 pub candela: String,
169 pub lumen: String,
170 pub watt: String,
171 pub lux: String,
172}
173
174#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
175pub struct DiagramAxis {
176 pub gamma: String,
177 pub intensity: String,
178 pub c_plane: String,
179 pub gamma_angle: String,
180}
181
182#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
183pub struct DiagramPlane {
184 pub c0_c180: String,
185 pub c90_c270: String,
186}
187
188#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
189pub struct DiagramAngle {
190 pub beam: String,
191 pub field: String,
192 pub beam_50: String,
193 pub field_10: String,
194}
195
196#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
197pub struct DiagramMetrics {
198 pub cie: String,
199 pub efficacy: String,
200 pub max: String,
201 pub sh_ratio: String,
202}
203
204#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
205pub struct DiagramTitle {
206 pub heatmap: String,
207 pub polar: String,
208 pub cartesian: String,
209 pub cone: String,
210}
211
212#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
213pub struct DiagramPlaceholder {
214 pub no_data: String,
215}
216
217#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
219pub struct DiagramCone {
220 pub beam_angle: String,
221 pub field_angle: String,
222 pub mounting_height: String,
223 pub beam_diameter: String,
224 pub field_diameter: String,
225 pub intensity_50: String,
226 pub intensity_10: String,
227 pub floor: String,
228 pub meter: String,
229 pub classification: ConeClassification,
230 pub c_plane: String,
231 pub all_planes: String,
232 pub symmetric_note: String,
233 pub illuminance_table: ConeIlluminanceTableLocale,
234}
235
236#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
238pub struct ConeIlluminanceTableLocale {
239 pub title: String,
240 pub height: String,
241 pub beam_field_diameter: String,
242 pub e_nadir: String,
243 pub e_c0: String,
244 pub e_c90: String,
245 pub no_flux: String,
246}
247
248#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
250pub struct ConeClassification {
251 pub very_narrow_spot: String,
252 pub narrow_spot: String,
253 pub spot: String,
254 pub medium_flood: String,
255 pub wide_flood: String,
256 pub very_wide_flood: String,
257}
258
259#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
261pub struct DiagramGreenhouse {
262 pub max_height: String,
263}
264
265#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
267pub struct SpectralLocale {
268 pub axis: SpectralAxis,
269 pub title: SpectralTitle,
270 pub region: SpectralRegion,
271 pub warning: SpectralWarning,
272 pub units: SpectralUnits,
273 pub tm30: Tm30Locale,
274 pub metrics: SpectralMetrics,
275}
276
277#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
278pub struct SpectralAxis {
279 pub wavelength: String,
280 pub relative_power: String,
281}
282
283#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
284pub struct SpectralTitle {
285 pub spd: String,
286 pub cvg: String,
287 pub hue: String,
288}
289
290#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
291pub struct SpectralRegion {
292 pub uv_a: String,
293 pub visible: String,
294 pub near_ir: String,
295 pub blue: String,
296 pub green: String,
297 pub red: String,
298}
299
300#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
301pub struct SpectralWarning {
302 pub uv_thermal: String,
303 pub uv_exposure: String,
304 pub high_thermal: String,
305}
306
307#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
308pub struct SpectralUnits {
309 pub watts_per_nm: String,
310 pub relative: String,
311}
312
313#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
314pub struct Tm30Locale {
315 pub rf: String,
316 pub rg: String,
317 pub reference: String,
318 pub test: String,
319}
320
321#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
322pub struct SpectralMetrics {
323 pub energy_distribution: String,
324 pub uv_percent: String,
325 pub visible_percent: String,
326 pub ir_percent: String,
327 pub r_fr_ratio: String,
328}
329
330#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
332pub struct LuminaireLocale {
333 pub info: LuminaireInfo,
334 pub physical: LuminairePhysical,
335 pub optical: LuminaireOptical,
336 pub photometric: LuminairePhotometric,
337 pub electrical: LuminaireElectrical,
338 pub lamp_set: LampSetLocale,
339 pub summary: SummaryLocale,
340 pub direct_ratios: DirectRatiosLocale,
341}
342
343#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
344pub struct LuminaireInfo {
345 pub manufacturer: String,
346 pub catalog_number: String,
347 pub description: String,
348 pub luminaire_name: String,
349 pub luminaire_number: String,
350 pub luminaire_type: String,
351 pub lamp_type: String,
352 pub test_date: String,
353 pub report_number: String,
354 pub laboratory: String,
355 pub identification: String,
356 pub type_indicator: String,
357 pub type_indicator_1: String,
358 pub type_indicator_2: String,
359 pub type_indicator_3: String,
360 pub symmetry: String,
361 pub symmetry_0: String,
362 pub symmetry_1: String,
363 pub symmetry_2: String,
364 pub symmetry_3: String,
365 pub symmetry_4: String,
366 pub num_c_planes: String,
367 pub c_plane_distance: String,
368 pub num_g_planes: String,
369 pub g_plane_distance: String,
370 pub measurement_report: String,
371 pub file_name: String,
372 pub date_user: String,
373}
374
375#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
376pub struct LuminairePhysical {
377 pub dimensions: String,
378 pub dimensions_mm: String,
379 pub length: String,
380 pub length_diameter: String,
381 pub width: String,
382 pub width_b: String,
383 pub height: String,
384 pub height_h: String,
385 pub luminous_area: String,
386 pub luminous_area_mm: String,
387 pub luminous_length: String,
388 pub luminous_width: String,
389 pub luminous_height_c_planes: String,
390 pub mounting: String,
391}
392
393#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
394pub struct LuminaireOptical {
395 pub title: String,
396 pub downward_flux_fraction: String,
397 pub light_output_ratio: String,
398 pub conversion_factor: String,
399 pub tilt_angle: String,
400}
401
402#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
403pub struct LuminairePhotometric {
404 pub total_flux: String,
405 pub total_lamp_flux: String,
406 pub total_wattage: String,
407 pub lamp_efficacy: String,
408 pub luminaire_efficacy: String,
409 pub efficacy: String,
410 pub lor: String,
411 pub dlor: String,
412 pub ulor: String,
413 pub cct: String,
414 pub cri: String,
415 pub beam_angle: String,
416 pub beam_angle_50: String,
417 pub field_angle: String,
418 pub field_angle_10: String,
419 pub cie_class: String,
420 pub symmetry: String,
421 pub max_intensity: String,
422 pub spacing_criterion: String,
423 pub photometric_code: String,
424 pub cutoff_angle: String,
425}
426
427#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
428pub struct LuminaireElectrical {
429 pub power: String,
430 pub voltage: String,
431 pub current: String,
432 pub power_factor: String,
433}
434
435#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
436pub struct LampSetLocale {
437 pub title: String,
438 pub set_n: String,
439 pub num_lamps: String,
440 pub luminous_flux: String,
441 pub wattage: String,
442 pub lamp_type: String,
443 pub color_appearance: String,
444 pub color_rendering: String,
445 pub remove: String,
446}
447
448#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
449pub struct SummaryLocale {
450 pub title: String,
451 pub description: String,
452 pub beam_characteristics: String,
453 pub zonal_lumens: String,
454 pub glare_assessment: String,
455 pub luminaire_luminance: String,
456 pub room_config: String,
457}
458
459#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
460pub struct DirectRatiosLocale {
461 pub description: String,
462 pub calculate: String,
463}
464
465#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
467pub struct ValidationLocale {
468 pub level: ValidationLevel,
469 pub messages: ValidationMessageLocale,
470}
471
472#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
473pub struct ValidationLevel {
474 pub error: String,
475 pub warning: String,
476 pub info: String,
477}
478
479#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
482pub struct ValidationMessageLocale {
483 pub w001: String,
484 pub w002: String,
485 pub w003: String,
486 pub w004: String,
487 pub w005: String,
488 pub w006: String,
489 pub w007: String,
490 pub w008: String,
491 pub w009: String,
492 pub w010: String,
493 pub w011: String,
494 pub w012: String,
495 pub w013: String,
496 pub w014: String,
497 pub w015: String,
498 pub w016: String,
499 pub w017: String,
500 pub w018: String,
501 pub w019: String,
502 pub w020: String,
503 pub w021: String,
504 pub w022: String,
505 pub w023: String,
506 pub w024: String,
507 pub w025: String,
508 pub w026: String,
509 pub w027: String,
510 pub w028: String,
511 pub w029: String,
512 pub w030: String,
513 pub w031: String,
514 pub w032: String,
515 pub w033: String,
516 pub w034: String,
517 pub w035: String,
518 pub w036: String,
519 pub w037: String,
520 pub w038: String,
521 pub w039: String,
522 pub w040: String,
523 pub w041: String,
524 pub w042: String,
525 pub w043: String,
526 pub w044: String,
527 pub w045: String,
528 pub w046: String,
529 pub w047: String,
530 pub e001: String,
531 pub e002: String,
532 pub e003: String,
533 pub e004: String,
534 pub e005: String,
535 pub e006: String,
536}
537
538#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
540pub struct UiLocale {
541 pub header: UiHeader,
542 pub tabs: UiTabs,
543 pub subtabs: UiSubtabs,
544 pub dropzone: UiDropzone,
545 pub diagram: UiDiagram,
546 pub intensity: UiIntensity,
547 pub validation: UiValidation,
548 pub spectral: UiSpectral,
549 pub butterfly: UiButterfly,
550 pub bevy_scene: UiBevyScene,
551 pub bug_rating: UiBugRating,
552 pub lcs: UiLcs,
553 pub floodlight: UiFloodlight,
554 pub data_table: UiDataTable,
555 pub validation_panel: UiValidationPanel,
556 pub spectral_badges: UiSpectralBadges,
557 pub actions: UiActions,
558 pub file: UiFile,
559 pub theme: UiTheme,
560 pub language: UiLanguage,
561 pub template: UiTemplate,
562 pub messages: UiMessages,
563 pub compare: UiCompare,
564}
565
566#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
567pub struct UiHeader {
568 pub title: String,
569 pub file: String,
570 pub new: String,
571 pub open: String,
572 pub templates: String,
573 pub save_ldt: String,
574 pub export_ies: String,
575 pub atla_xml: String,
576 pub atla_json: String,
577 pub switch_to_dark: String,
578 pub switch_to_light: String,
579}
580
581#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
582pub struct UiTabs {
583 pub general: String,
585 pub dimensions: String,
586 pub lamp_sets: String,
587 pub direct_ratios: String,
588 pub intensity: String,
589 pub diagram_2d: String,
590 pub diagram_3d: String,
591 pub heatmap: String,
592 pub spectral: String,
593 pub greenhouse: String,
594 pub bug_rating: String,
595 pub lcs: String,
596 pub validation: String,
597 pub scene_3d: String,
598 pub floodlight_vh: String,
599 pub floodlight_isolux: String,
600 pub floodlight_isocandela: String,
601 pub info: String,
603 pub data: String,
604 pub diagrams: String,
605 pub analysis: String,
606 pub floodlight: String,
607 pub polar: String,
609 pub cartesian: String,
610 pub cone: String,
611 pub export: String,
612 pub compare: String,
613}
614
615#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
616pub struct UiSubtabs {
617 pub spd: String,
618 pub tm30_cvg: String,
619 pub tm30_hue: String,
620 pub metrics: String,
621}
622
623#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
624pub struct UiDropzone {
625 pub text: String,
626 pub current_file: String,
627}
628
629#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
630pub struct UiDiagram {
631 pub title_2d: String,
632 pub title_3d: String,
633 pub title_heatmap: String,
634 pub title_spectral: String,
635 pub title_greenhouse: String,
636 pub title_bug: String,
637 pub title_lcs: String,
638 pub title_scene: String,
639 pub title_floodlight_vh: String,
640 pub title_isolux: String,
641 pub title_isocandela: String,
642 pub polar: String,
643 pub cartesian: String,
644 pub zoom_hint: String,
645 pub rotate_hint: String,
646 pub scene_controls: String,
647}
648
649#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
650pub struct UiIntensity {
651 pub title: String,
652 pub table_info: String,
653}
654
655#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
656pub struct UiValidation {
657 pub title: String,
658}
659
660#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
661pub struct UiSpectral {
662 pub subtitle: String,
663 pub greenhouse_subtitle: String,
664 pub bug_subtitle: String,
665 pub lcs_subtitle: String,
666 pub direct_spd: String,
667 pub sample: String,
668 pub load_hint: String,
669 pub wavelength_range: String,
670 pub peak: String,
671 pub energy_distribution: String,
672 pub par_distribution: String,
673 pub par_total: String,
674 pub hort_metrics: String,
675 pub far_red: String,
676 pub r_fr_hint: String,
677 pub warnings: String,
678 pub thermal_warning: String,
679 pub uv_warning: String,
680 pub cvg_legend1: String,
681 pub cvg_legend2: String,
682 pub hue_table: UiHueTable,
683 pub hue_legend: UiHueLegend,
684}
685
686#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
687pub struct UiHueTable {
688 pub hue: String,
689 pub rf: String,
690 pub rcs: String,
691 pub rhs: String,
692}
693
694#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
695pub struct UiHueLegend {
696 pub rf: String,
697 pub rcs: String,
698 pub rhs: String,
699}
700
701#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
702pub struct UiButterfly {
703 pub pause: String,
704 pub auto: String,
705 pub reset: String,
706 pub drag_hint: String,
707 pub max: String,
708}
709
710#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
711pub struct UiBevyScene {
712 pub title: String,
713 pub click_to_load: String,
714 pub load_button: String,
715 pub loading: String,
716 pub downloading: String,
717 pub load_failed: String,
718 pub try_again: String,
719 pub scene_type: String,
721 pub scene_room: String,
722 pub scene_road: String,
723 pub scene_parking: String,
724 pub scene_outdoor: String,
725 pub room_width: String,
726 pub room_length: String,
727 pub room_height: String,
728 pub mounting_height: String,
729 pub pendulum_length: String,
730 pub show_luminaire: String,
731 pub show_solid: String,
732 pub show_shadows: String,
733 pub controls_hint: String,
734}
735
736#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
737pub struct UiBugRating {
738 pub title: String,
739 pub title_detailed: String,
740 pub show_details: String,
741 pub hide_details: String,
742 pub footer_basic: String,
743 pub footer_detailed: String,
744}
745
746#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
747pub struct UiLcs {
748 pub footer: String,
749}
750
751#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
752pub struct UiFloodlight {
753 pub vh_subtitle: String,
754 pub isolux_subtitle: String,
755 pub isocandela_subtitle: String,
756 pub h_plane: String,
757 pub v_plane: String,
758 pub log_scale: String,
759 pub linear_scale: String,
760 pub mounting_height: String,
761 pub tilt_angle: String,
762 pub area_size: String,
763 pub nema_classification: String,
764 pub show_contours: String,
765}
766
767#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
768pub struct UiDataTable {
769 pub no_data: String,
770 pub copy_to_clipboard: String,
771}
772
773#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
774pub struct UiValidationPanel {
775 pub all_passed: String,
776 pub error_count: String,
777}
778
779#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
780pub struct UiSpectralBadges {
781 pub ir: String,
782 pub uv: String,
783 pub ir_high_title: String,
784 pub ir_title: String,
785 pub uv_high_title: String,
786 pub uv_title: String,
787 pub rg: String,
788 pub duv: String,
789}
790
791#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
792pub struct UiActions {
793 pub load: String,
794 pub save: String,
795 pub export: String,
796 pub import: String,
797 pub clear: String,
798 pub reset: String,
799 pub apply: String,
800 pub cancel: String,
801 pub close: String,
802 pub download: String,
803}
804
805#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
806pub struct UiFile {
807 pub open: String,
808 pub save_as: String,
809 pub export_ldt: String,
810 pub export_ies: String,
811 pub export_atla: String,
812 pub export_svg: String,
813 pub export_pdf: String,
814}
815
816#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
817pub struct UiTheme {
818 pub light: String,
819 pub dark: String,
820 pub system: String,
821}
822
823#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
824pub struct UiLanguage {
825 pub select: String,
826}
827
828#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
829pub struct UiTemplate {
830 pub select: String,
831 pub downlight: String,
832 pub projector: String,
833 pub linear: String,
834 pub fluorescent: String,
835 pub road: String,
836 pub uplight: String,
837 pub atla_fluorescent_xml: String,
838 pub atla_fluorescent_json: String,
839 pub atla_grow_light_fs: String,
840 pub atla_grow_light_rb: String,
841 pub halogen: String,
842 pub incandescent: String,
843 pub heat_lamp: String,
844 pub uv_blacklight: String,
845}
846
847#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
848pub struct UiMessages {
849 pub loading: String,
850 pub saving: String,
851 pub error: String,
852 pub success: String,
853 pub file_loaded: String,
854 pub file_saved: String,
855 pub invalid_file: String,
856 pub no_file: String,
857}
858
859#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
861pub struct UiCompare {
862 pub title: String,
863 pub drop_hint: String,
864 pub browse: String,
865 pub or: String,
866 pub select_template: String,
867 pub file_b: String,
868 pub file_b_label: String,
869 pub clear: String,
870 pub similarity: String,
871 pub export_pdf: String,
872 pub export_typ: String,
873 pub exporting: String,
874 pub file_a_c_plane: String,
875 pub file_b_c_plane: String,
876 pub link_sliders: String,
877 pub metric: String,
878 pub file_a: String,
879 pub delta: String,
880 pub percent: String,
881 pub empty_title: String,
882 pub empty_hint: String,
883}
884
885#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
887pub struct ComparisonLocale {
888 pub metrics: ComparisonMetricLocale,
889}
890
891#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
893pub struct ComparisonMetricLocale {
894 pub total_lamp_flux: String,
895 pub calculated_flux: String,
896 pub lor: String,
897 pub dlor: String,
898 pub ulor: String,
899 pub lamp_efficacy: String,
900 pub luminaire_efficacy: String,
901 pub total_wattage: String,
902 pub beam_angle: String,
903 pub field_angle: String,
904 pub beam_angle_cie: String,
905 pub field_angle_cie: String,
906 pub upward_beam_angle: String,
907 pub upward_field_angle: String,
908 pub max_intensity: String,
909 pub min_intensity: String,
910 pub avg_intensity: String,
911 pub spacing_c0: String,
912 pub spacing_c90: String,
913 pub zonal_0_30: String,
914 pub zonal_30_60: String,
915 pub zonal_60_90: String,
916 pub zonal_90_120: String,
917 pub zonal_120_150: String,
918 pub zonal_150_180: String,
919 pub cie_n1: String,
920 pub cie_n2: String,
921 pub cie_n3: String,
922 pub cie_n4: String,
923 pub cie_n5: String,
924 pub bug_b: String,
925 pub bug_u: String,
926 pub bug_g: String,
927 pub length: String,
928 pub width: String,
929 pub height: String,
930}
931
932#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
934pub struct ReportLocale {
935 pub title: String,
936 pub generated: String,
937 pub page: String,
938 pub of: String,
939 pub summary: String,
940 pub details: String,
941 pub appendix: String,
942}
943
944const EN_JSON: &str = include_str!("../locales/en.json");
946const DE_JSON: &str = include_str!("../locales/de.json");
947const ZH_JSON: &str = include_str!("../locales/zh.json");
948const FR_JSON: &str = include_str!("../locales/fr.json");
949const IT_JSON: &str = include_str!("../locales/it.json");
950const RU_JSON: &str = include_str!("../locales/ru.json");
951const ES_JSON: &str = include_str!("../locales/es.json");
952const PT_BR_JSON: &str = include_str!("../locales/pt-BR.json");
953
954impl Locale {
955 pub fn from_json(json: &str) -> Result<Self, serde_json::Error> {
957 serde_json::from_str(json)
958 }
959
960 pub fn english() -> Self {
962 Self::from_json(EN_JSON).expect("embedded English locale is valid")
963 }
964
965 pub fn german() -> Self {
967 Self::from_json(DE_JSON).expect("embedded German locale is valid")
968 }
969
970 pub fn chinese() -> Self {
972 Self::from_json(ZH_JSON).expect("embedded Chinese locale is valid")
973 }
974
975 pub fn french() -> Self {
977 Self::from_json(FR_JSON).expect("embedded French locale is valid")
978 }
979
980 pub fn italian() -> Self {
982 Self::from_json(IT_JSON).expect("embedded Italian locale is valid")
983 }
984
985 pub fn russian() -> Self {
987 Self::from_json(RU_JSON).expect("embedded Russian locale is valid")
988 }
989
990 pub fn spanish() -> Self {
992 Self::from_json(ES_JSON).expect("embedded Spanish locale is valid")
993 }
994
995 pub fn portuguese_brazil() -> Self {
997 Self::from_json(PT_BR_JSON).expect("embedded Portuguese locale is valid")
998 }
999
1000 pub fn for_language(lang: Language) -> Self {
1002 match lang {
1003 Language::English => Self::english(),
1004 Language::German => Self::german(),
1005 Language::Chinese => Self::chinese(),
1006 Language::French => Self::french(),
1007 Language::Italian => Self::italian(),
1008 Language::Russian => Self::russian(),
1009 Language::Spanish => Self::spanish(),
1010 Language::PortugueseBrazil => Self::portuguese_brazil(),
1011 }
1012 }
1013
1014 pub fn for_code(code: &str) -> Self {
1016 Self::for_language(Language::from_code(code))
1017 }
1018
1019 pub fn validation_message(&self, code: &str) -> Option<&str> {
1022 let m = &self.validation.messages;
1023 let s = match code {
1024 "W001" => &m.w001,
1025 "W002" => &m.w002,
1026 "W003" => &m.w003,
1027 "W004" => &m.w004,
1028 "W005" => &m.w005,
1029 "W006" => &m.w006,
1030 "W007" => &m.w007,
1031 "W008" => &m.w008,
1032 "W009" => &m.w009,
1033 "W010" => &m.w010,
1034 "W011" => &m.w011,
1035 "W012" => &m.w012,
1036 "W013" => &m.w013,
1037 "W014" => &m.w014,
1038 "W015" => &m.w015,
1039 "W016" => &m.w016,
1040 "W017" => &m.w017,
1041 "W018" => &m.w018,
1042 "W019" => &m.w019,
1043 "W020" => &m.w020,
1044 "W021" => &m.w021,
1045 "W022" => &m.w022,
1046 "W023" => &m.w023,
1047 "W024" => &m.w024,
1048 "W025" => &m.w025,
1049 "W026" => &m.w026,
1050 "W027" => &m.w027,
1051 "W028" => &m.w028,
1052 "W029" => &m.w029,
1053 "W030" => &m.w030,
1054 "W031" => &m.w031,
1055 "W032" => &m.w032,
1056 "W033" => &m.w033,
1057 "W034" => &m.w034,
1058 "W035" => &m.w035,
1059 "W036" => &m.w036,
1060 "W037" => &m.w037,
1061 "W038" => &m.w038,
1062 "W039" => &m.w039,
1063 "W040" => &m.w040,
1064 "W041" => &m.w041,
1065 "W042" => &m.w042,
1066 "W043" => &m.w043,
1067 "W044" => &m.w044,
1068 "W045" => &m.w045,
1069 "W046" => &m.w046,
1070 "W047" => &m.w047,
1071 "E001" => &m.e001,
1072 "E002" => &m.e002,
1073 "E003" => &m.e003,
1074 "E004" => &m.e004,
1075 "E005" => &m.e005,
1076 "E006" => &m.e006,
1077 _ => return None,
1078 };
1079 Some(s.as_str())
1080 }
1081
1082 pub fn comparison_metric_name(&self, key: &str) -> Option<&str> {
1084 let m = &self.comparison.metrics;
1085 let s = match key {
1086 "total_lamp_flux" => &m.total_lamp_flux,
1087 "calculated_flux" => &m.calculated_flux,
1088 "lor" => &m.lor,
1089 "dlor" => &m.dlor,
1090 "ulor" => &m.ulor,
1091 "lamp_efficacy" => &m.lamp_efficacy,
1092 "luminaire_efficacy" => &m.luminaire_efficacy,
1093 "total_wattage" => &m.total_wattage,
1094 "beam_angle" => &m.beam_angle,
1095 "field_angle" => &m.field_angle,
1096 "beam_angle_cie" => &m.beam_angle_cie,
1097 "field_angle_cie" => &m.field_angle_cie,
1098 "upward_beam_angle" => &m.upward_beam_angle,
1099 "upward_field_angle" => &m.upward_field_angle,
1100 "max_intensity" => &m.max_intensity,
1101 "min_intensity" => &m.min_intensity,
1102 "avg_intensity" => &m.avg_intensity,
1103 "spacing_c0" => &m.spacing_c0,
1104 "spacing_c90" => &m.spacing_c90,
1105 "zonal_0_30" => &m.zonal_0_30,
1106 "zonal_30_60" => &m.zonal_30_60,
1107 "zonal_60_90" => &m.zonal_60_90,
1108 "zonal_90_120" => &m.zonal_90_120,
1109 "zonal_120_150" => &m.zonal_120_150,
1110 "zonal_150_180" => &m.zonal_150_180,
1111 "cie_n1" => &m.cie_n1,
1112 "cie_n2" => &m.cie_n2,
1113 "cie_n3" => &m.cie_n3,
1114 "cie_n4" => &m.cie_n4,
1115 "cie_n5" => &m.cie_n5,
1116 "bug_b" => &m.bug_b,
1117 "bug_u" => &m.bug_u,
1118 "bug_g" => &m.bug_g,
1119 "length" => &m.length,
1120 "width" => &m.width,
1121 "height" => &m.height,
1122 _ => return None,
1123 };
1124 Some(s.as_str())
1125 }
1126}
1127
1128pub fn format_template(template: &str, args: &[&dyn std::fmt::Display]) -> String {
1130 let mut result = template.to_string();
1131 for (i, arg) in args.iter().enumerate() {
1132 result = result.replace(&format!("{{{}}}", i), &arg.to_string());
1133 }
1134 result
1135}
1136
1137impl Default for Locale {
1138 fn default() -> Self {
1139 Self::english()
1140 }
1141}
1142
1143#[cfg(test)]
1144mod tests {
1145 use super::*;
1146
1147 #[test]
1148 fn test_english_locale() {
1149 let en = Locale::english();
1150 assert_eq!(en.meta.code, "en");
1151 assert_eq!(en.diagram.axis.gamma, "Gamma (γ)");
1152 assert_eq!(en.ui.tabs.polar, "Polar");
1153 }
1154
1155 #[test]
1156 fn test_german_locale() {
1157 let de = Locale::german();
1158 assert_eq!(de.meta.code, "de");
1159 assert_eq!(de.diagram.axis.intensity, "Lichtstärke (cd/klm)");
1160 assert_eq!(de.ui.tabs.polar, "Polar");
1161 }
1162
1163 #[test]
1164 fn test_chinese_locale() {
1165 let zh = Locale::chinese();
1166 assert_eq!(zh.meta.code, "zh");
1167 assert_eq!(zh.diagram.placeholder.no_data, "无数据");
1168 assert_eq!(zh.ui.tabs.polar, "极坐标");
1169 }
1170
1171 #[test]
1172 fn test_russian_locale() {
1173 let ru = Locale::russian();
1174 assert_eq!(ru.meta.code, "ru");
1175 assert_eq!(ru.diagram.placeholder.no_data, "Нет данных");
1176 assert_eq!(ru.luminaire.photometric.cct, "Цветовая температура");
1177 }
1178
1179 #[test]
1180 fn test_spanish_locale() {
1181 let es = Locale::spanish();
1182 assert_eq!(es.meta.code, "es");
1183 assert_eq!(es.diagram.placeholder.no_data, "Sin datos");
1184 assert_eq!(es.ui.actions.save, "Guardar");
1185 }
1186
1187 #[test]
1188 fn test_portuguese_brazil_locale() {
1189 let pt = Locale::portuguese_brazil();
1190 assert_eq!(pt.meta.code, "pt-BR");
1191 assert_eq!(pt.diagram.placeholder.no_data, "Sem dados");
1192 assert_eq!(pt.ui.actions.save, "Salvar");
1193 }
1194
1195 #[test]
1196 fn test_french_locale() {
1197 let fr = Locale::french();
1198 assert_eq!(fr.meta.code, "fr");
1199 assert_eq!(fr.diagram.placeholder.no_data, "Aucune donnée");
1200 assert_eq!(fr.ui.actions.save, "Enregistrer");
1201 }
1202
1203 #[test]
1204 fn test_italian_locale() {
1205 let it = Locale::italian();
1206 assert_eq!(it.meta.code, "it");
1207 assert_eq!(it.diagram.placeholder.no_data, "Nessun dato");
1208 assert_eq!(it.ui.actions.save, "Salva");
1209 }
1210
1211 #[test]
1212 fn test_language_from_code() {
1213 assert_eq!(Language::from_code("de"), Language::German);
1214 assert_eq!(Language::from_code("zh-CN"), Language::Chinese);
1215 assert_eq!(Language::from_code("fr"), Language::French);
1216 assert_eq!(Language::from_code("it"), Language::Italian);
1217 assert_eq!(Language::from_code("ru"), Language::Russian);
1218 assert_eq!(Language::from_code("es"), Language::Spanish);
1219 assert_eq!(Language::from_code("pt-BR"), Language::PortugueseBrazil);
1220 assert_eq!(Language::from_code("unknown"), Language::English);
1221 }
1222
1223 #[test]
1224 fn test_for_code() {
1225 let locale = Locale::for_code("de");
1226 assert_eq!(locale.meta.code, "de");
1227
1228 let locale_ru = Locale::for_code("ru");
1229 assert_eq!(locale_ru.meta.code, "ru");
1230 }
1231
1232 #[test]
1233 fn test_all_languages() {
1234 let all = Language::all();
1235 assert_eq!(all.len(), 8);
1236
1237 for lang in all {
1239 let locale = Locale::for_language(*lang);
1240 assert_eq!(locale.meta.code, lang.code());
1241 }
1242 }
1243}