Use the localization technology in the website code.

This commit is contained in:
kovacsv 2024-01-27 09:32:12 +01:00
parent 449ce84bcd
commit d10b3a1338
14 changed files with 148 additions and 134 deletions

View File

@ -1,12 +1,13 @@
import { AddDiv } from '../engine/viewer/domutils.js';
import { ButtonDialog, ListPopup } from './dialog.js';
import { Loc } from '../engine/core/localization.js';
export function ShowMessageDialog (title, message, subMessage)
{
let dialog = new ButtonDialog ();
let contentDiv = dialog.Init (title, [
{
name : 'OK',
name : Loc ('OK'),
onClick () {
dialog.Close ();
}

View File

@ -11,6 +11,7 @@ import { ShowMessageDialog } from './dialogs.js';
import { DownloadArrayBufferAsFile } from './utils.js';
import { CookieGetStringVal, CookieSetStringVal } from './cookiehandler.js';
import { HandleEvent } from './eventhandler.js';
import { Loc } from '../engine/core/localization.js';
import * as fflate from 'fflate';
@ -53,8 +54,8 @@ class ModelExporterUI
return AddSelectWithCookieSave (parameterValueDiv, cookieKey, values, defaultIndex);
}
this.visibleOnlySelect = AddSelectItem (parametersDiv, 'Scope', 'ov_last_scope', ['Entire Model', 'Visible Only'], 1);
this.rotationSelect = AddSelectItem (parametersDiv, 'Rotation', 'ov_last_rotation', ['No Rotation', '-90 Degrees', '90 Degrees'], 0);
this.visibleOnlySelect = AddSelectItem (parametersDiv, Loc ('Scope'), 'ov_last_scope', [Loc ('Entire Model'), Loc ('Visible Only')], 1);
this.rotationSelect = AddSelectItem (parametersDiv, Loc ('Rotation'), 'ov_last_rotation', [Loc ('No Rotation'), Loc ('-90 Degrees'), Loc ('90 Degrees')], 0);
}
ExportModel (model, callbacks)
@ -77,15 +78,15 @@ class ModelExporterUI
let exporterModel = new ExporterModel (model, settings);
if (exporterModel.MeshInstanceCount () === 0) {
ShowMessageDialog (
'Export Failed',
'The model doesn\'t contain any meshes.',
Loc ('Export Failed'),
Loc ('The model doesn\'t contain any meshes.'),
null
);
return;
}
let progressDialog = new ProgressDialog ();
progressDialog.Init ('Exporting Model');
progressDialog.Init (Loc ('Exporting Model'));
progressDialog.Open ();
RunTaskAsync (() => {
@ -142,16 +143,16 @@ class ExportDialog
Open (model, viewer)
{
let mainDialog = new ButtonDialog ();
let contentDiv = mainDialog.Init ('Export', [
let contentDiv = mainDialog.Init (Loc ('Export'), [
{
name : 'Close',
name : Loc ('Close'),
subClass : 'outline',
onClick () {
mainDialog.Close ();
}
},
{
name : 'Export',
name : Loc ('Export'),
onClick : () => {
mainDialog.Close ();
this.ExportFormat (model, viewer);
@ -159,7 +160,7 @@ class ExportDialog
}
]);
let text = 'Select the format from the list below, and adjust the settings of the selected format.';
let text = Loc ('Select the format from the list below, and adjust the settings of the selected format.');
AddDiv (contentDiv, 'ov_dialog_section', text);
let formatRow = AddDiv (contentDiv, 'ov_dialog_row');

View File

@ -1,6 +1,7 @@
import { BigEps, IsEqualEps, RadDeg } from '../engine/geometry/geometry.js';
import { AddDiv, ClearDomElement } from '../engine/viewer/domutils.js';
import { AddSvgIconElement, IsDarkTextNeededForColor } from './utils.js';
import { Loc } from '../engine/core/localization.js';
import * as THREE from 'three';
import { ColorComponentToFloat, RGBColor } from '../engine/model/color.js';
@ -231,9 +232,9 @@ export class MeasureTool
this.panel.style.backgroundColor = 'transparent';
}
if (this.markers.length === 0) {
this.panel.innerHTML = 'Select a point.';
this.panel.innerHTML = Loc ('Select a point.');
} else if (this.markers.length === 1) {
this.panel.innerHTML = 'Select another point.';
this.panel.innerHTML = Loc ('Select another point.');
} else {
let calcResult = CalculateMarkerValues (this.markers[0], this.markers[1]);

View File

@ -1,6 +1,7 @@
import { SetDomElementHeight, GetDomElementOuterHeight } from '../engine/viewer/domutils.js';
import { NavigatorPanel } from './navigatorpanel.js';
import { TreeViewButton, TreeViewButtonItem, TreeViewGroupItem, TreeViewSingleItem } from './treeview.js';
import { Loc } from '../engine/core/localization.js';
export class NavigatorFilesPanel extends NavigatorPanel
{
@ -11,7 +12,7 @@ export class NavigatorFilesPanel extends NavigatorPanel
GetName ()
{
return 'Files';
return Loc ('Files');
}
GetIcon ()
@ -38,7 +39,7 @@ export class NavigatorFilesPanel extends NavigatorPanel
const missingFiles = importResult.missingFiles;
if (missingFiles.length > 0) {
let missingFilesItem = new TreeViewGroupItem ('Missing Files', null);
let missingFilesItem = new TreeViewGroupItem (Loc ('Missing Files'), null);
missingFilesItem.ShowChildren (true);
this.treeView.AddChild (missingFilesItem);
for (let i = 0; i < missingFiles.length; i++) {
@ -51,7 +52,7 @@ export class NavigatorFilesPanel extends NavigatorPanel
item.AppendButton (browseButton);
missingFilesItem.AddChild (item);
}
let filesItem = new TreeViewGroupItem ('Available Files', null);
let filesItem = new TreeViewGroupItem (Loc ('Available Files'), null);
filesItem.ShowChildren (true);
this.treeView.AddChild (filesItem);
for (let i = 0; i < usedFiles.length; i++) {

View File

@ -3,6 +3,7 @@ import { CalculatePopupPositionToElementBottomRight, ShowListPopup } from './dia
import { MaterialItem } from './navigatoritems.js';
import { NavigatorPanel, NavigatorPopupButton } from './navigatorpanel.js';
import { GetMaterialName, GetMeshName } from './utils.js';
import { Loc, FLoc } from '../engine/core/localization.js';
class NavigatorMeshesPopupButton extends NavigatorPopupButton
{
@ -19,7 +20,7 @@ class NavigatorMeshesPopupButton extends NavigatorPopupButton
return;
}
let meshesText = 'Meshes (' + this.meshInstanceArray.length + ')';
let meshesText = FLoc ('Meshes ({0})', this.meshInstanceArray.length);
this.buttonText.innerHTML = meshesText;
}
@ -74,7 +75,7 @@ export class NavigatorMaterialsPanel extends NavigatorPanel
GetName ()
{
return 'Materials';
return Loc ('Materials');
}
GetIcon ()

View File

@ -4,6 +4,7 @@ import { CalculatePopupPositionToElementBottomRight, ShowListPopup } from './dia
import { MeshItem, NavigatorItemRecurse, NodeItem } from './navigatoritems.js';
import { NavigatorPanel, NavigatorPopupButton } from './navigatorpanel.js';
import { AddSvgIconElement, GetMaterialName, GetMeshName, GetNodeName, SetSvgIconImageElement } from './utils.js';
import { Loc, FLoc } from '../engine/core/localization.js';
const MeshesPanelMode =
{
@ -27,7 +28,7 @@ class NavigatorMaterialsPopupButton extends NavigatorPopupButton
return;
}
let materialsText = 'Materials (' + this.materialInfoArray.length + ')';
let materialsText = FLoc ('Materials ({0})', this.materialInfoArray.length);
this.buttonText.innerHTML = materialsText;
}
@ -86,7 +87,7 @@ export class NavigatorMeshesPanel extends NavigatorPanel
GetName ()
{
return 'Meshes';
return Loc ('Meshes');
}
GetIcon ()
@ -228,38 +229,38 @@ export class NavigatorMeshesPanel extends NavigatorPanel
this.buttons = {
flatList : {
name : 'Flat list',
name : Loc ('Flat list'),
icon : 'flat_list',
div : null,
iconDiv : null
},
treeView : {
name : 'Tree view',
name : Loc ('Tree view'),
icon : 'tree_view',
div : null,
iconDiv : null
},
separator : null,
expandAll : {
name : 'Expand all',
name : Loc ('Expand all'),
icon : 'expand',
div : null,
iconDiv : null
},
collapseAll : {
name : 'Collapse all',
name : Loc ('Collapse all'),
icon : 'collapse',
div : null,
iconDiv : null
},
showHideMeshes : {
name : 'Show/hide meshes',
name : Loc ('Show/hide meshes'),
icon : 'visible',
div : null,
iconDiv : null
},
fitToWindow : {
name : 'Fit meshes to window',
name : Loc ('Fit meshes to window'),
icon : 'fit',
div : null,
iconDiv : null

View File

@ -1,21 +1,22 @@
import { ReadLines } from '../engine/import/importerutils.js';
import { AddDiv, CreateDomElement } from '../engine/viewer/domutils.js';
import { ButtonDialog } from './dialog.js';
import { Loc } from '../engine/core/localization.js';
export function ShowOpenUrlDialog (onOk)
{
let dialog = new ButtonDialog ();
let urlsTextArea = CreateDomElement ('textarea', 'ov_dialog_textarea');
let contentDiv = dialog.Init ('Open from url', [
let contentDiv = dialog.Init (Loc ('Open from url'), [
{
name : 'Cancel',
name : Loc ('Cancel'),
subClass : 'outline',
onClick () {
dialog.Close ();
}
},
{
name : 'OK',
name : Loc ('OK'),
onClick () {
let urls = [];
ReadLines (urlsTextArea.value, (line) => {
@ -26,7 +27,7 @@ export function ShowOpenUrlDialog (onOk)
}
}
]);
let text = 'Here you can load models based on their urls. You can add more lines if your model builds up from multiple files.';
let text = Loc ('Here you can load models based on their urls. You can add more lines if your model builds up from multiple files.');
AddDiv (contentDiv, 'ov_dialog_section', text);
contentDiv.appendChild (urlsTextArea);
dialog.Open ();

View File

@ -6,6 +6,7 @@ import { ShowMessageDialog } from './dialogs.js';
import { ButtonDialog } from './dialog.js';
import { CopyToClipboard } from './utils.js';
import { HandleEvent } from './eventhandler.js';
import { Loc } from '../engine/core/localization.js';
export function ShowSharingDialog (fileList, settings, viewer)
{
@ -19,8 +20,8 @@ export function ShowSharingDialog (fileList, settings, viewer)
function AddCopyableTextInput (parentDiv, getText)
{
let copyText = 'Copy';
let copiedText = 'Copied';
let copyText = Loc ('Copy');
let copiedText = Loc ('Copied');
let container = AddDiv (parentDiv, 'ov_dialog_copyable_input');
let input = AddDomElement (container, 'input', null);
input.setAttribute ('type', 'text');
@ -47,7 +48,7 @@ export function ShowSharingDialog (fileList, settings, viewer)
}
let section = AddDiv (parentDiv, 'ov_dialog_section');
AddDiv (section, 'ov_dialog_inner_title', 'Sharing Link');
AddDiv (section, 'ov_dialog_inner_title', Loc ('Sharing Link'));
let sharingLinkInput = AddCopyableTextInput (section, () => {
HandleEvent ('model_shared', 'sharing_link');
return GetSharingLink (modelFiles);
@ -88,13 +89,13 @@ export function ShowSharingDialog (fileList, settings, viewer)
let useCurrentSettings = true;
let section = AddDiv (parentDiv, 'ov_dialog_section');
section.style.marginTop = '20px';
AddDiv (section, 'ov_dialog_inner_title', 'Embedding Code');
AddDiv (section, 'ov_dialog_inner_title', Loc ('Embedding Code'));
let optionsSection = AddDiv (section, 'ov_dialog_section');
let embeddingCodeInput = AddCopyableTextInput (section, () => {
HandleEvent ('model_shared', 'embedding_code');
return GetEmbeddingCode (modelFiles, useCurrentSettings, settings, viewer);
});
AddCheckboxLine (optionsSection, 'Use customized settings', 'embed_current_settings', (checked) => {
AddCheckboxLine (optionsSection, Loc ('Use customized settings', 'embed_current_settings'), (checked) => {
useCurrentSettings = checked;
embeddingCodeInput.value = GetEmbeddingCode (modelFiles, useCurrentSettings, settings, viewer);
});
@ -104,8 +105,8 @@ export function ShowSharingDialog (fileList, settings, viewer)
if (!fileList.IsOnlyUrlSource ()) {
return ShowMessageDialog (
'Sharing Failed',
'Sharing works only if you load files by url. Please upload your model files to a web server, open them by url, and try embedding again.',
Loc ('Sharing Failed'),
Loc ('Sharing works only if you load files by url. Please upload your model files to a web server, open them by url, and try embedding again.'),
null
);
}
@ -120,9 +121,9 @@ export function ShowSharingDialog (fileList, settings, viewer)
}
let dialog = new ButtonDialog ();
let contentDiv = dialog.Init ('Share', [
let contentDiv = dialog.Init (Loc ('Share'), [
{
name : 'Close',
name : Loc ('Close'),
onClick () {
dialog.Close ();
}

View File

@ -10,22 +10,23 @@ import { GetFileName, IsUrl } from '../engine/io/fileutils.js';
import { MaterialSource, MaterialType } from '../engine/model/material.js';
import { RGBColorToHexString } from '../engine/model/color.js';
import { Unit } from '../engine/model/unit.js';
import { Loc } from '../engine/core/localization.js';
function UnitToString (unit)
{
switch (unit) {
case Unit.Millimeter:
return 'Millimeter';
return Loc ('Millimeter');
case Unit.Centimeter:
return 'Centimeter';
return Loc ('Centimeter');
case Unit.Meter:
return 'Meter';
return Loc ('Meter');
case Unit.Inch:
return 'Inch';
return Loc ('Inch');
case Unit.Foot:
return 'Foot';
return Loc ('Foot');
}
return 'Unknown';
return Loc ('Unknown');
}
export class SidebarDetailsPanel extends SidebarPanel
@ -37,7 +38,7 @@ export class SidebarDetailsPanel extends SidebarPanel
GetName ()
{
return 'Details';
return Loc ('Details');
}
GetIcon ()
@ -52,29 +53,29 @@ export class SidebarDetailsPanel extends SidebarPanel
let boundingBox = GetBoundingBox (object3D);
let size = SubCoord3D (boundingBox.max, boundingBox.min);
let unit = model.GetUnit ();
this.AddProperty (table, new Property (PropertyType.Integer, 'Vertices', object3D.VertexCount ()));
this.AddProperty (table, new Property (PropertyType.Integer, Loc ('Vertices'), object3D.VertexCount ()));
let lineSegmentCount = object3D.LineSegmentCount ();
if (lineSegmentCount > 0) {
this.AddProperty (table, new Property (PropertyType.Integer, 'Lines', lineSegmentCount));
this.AddProperty (table, new Property (PropertyType.Integer, Loc ('Lines'), lineSegmentCount));
}
let triangleCount = object3D.TriangleCount ();
if (triangleCount > 0) {
this.AddProperty (table, new Property (PropertyType.Integer, 'Triangles', triangleCount));
this.AddProperty (table, new Property (PropertyType.Integer, Loc ('Triangles'), triangleCount));
}
if (unit !== Unit.Unknown) {
this.AddProperty (table, new Property (PropertyType.Text, 'Unit', UnitToString (unit)));
this.AddProperty (table, new Property (PropertyType.Text, Loc ('Unit'), UnitToString (unit)));
}
this.AddProperty (table, new Property (PropertyType.Number, 'Size X', size.x));
this.AddProperty (table, new Property (PropertyType.Number, 'Size Y', size.y));
this.AddProperty (table, new Property (PropertyType.Number, 'Size Z', size.z));
this.AddCalculatedProperty (table, 'Volume', () => {
this.AddProperty (table, new Property (PropertyType.Number, Loc ('Size X'), size.x));
this.AddProperty (table, new Property (PropertyType.Number, Loc ('Size Y'), size.y));
this.AddProperty (table, new Property (PropertyType.Number, Loc ('Size Z'), size.z));
this.AddCalculatedProperty (table, Loc ('Volume'), () => {
if (!IsTwoManifold (object3D)) {
return null;
}
const volume = CalculateVolume (object3D);
return new Property (PropertyType.Number, null, volume);
});
this.AddCalculatedProperty (table, 'Surface', () => {
this.AddCalculatedProperty (table, Loc ('Surface'), () => {
const surfaceArea = CalculateSurfaceArea (object3D);
return new Property (PropertyType.Number, null, surfaceArea);
});
@ -107,35 +108,35 @@ export class SidebarDetailsPanel extends SidebarPanel
let table = AddDiv (this.contentDiv, 'ov_property_table');
let typeString = null;
if (material.type === MaterialType.Phong) {
typeString = 'Phong';
typeString = Loc ('Phong');
} else if (material.type === MaterialType.Physical) {
typeString = 'Physical';
typeString = Loc ('Physical');
}
let materialSource = (material.source !== MaterialSource.Model) ? 'Default' : 'Model';
this.AddProperty (table, new Property (PropertyType.Text, 'Source', materialSource));
this.AddProperty (table, new Property (PropertyType.Text, 'Type', typeString));
let materialSource = (material.source !== MaterialSource.Model) ? Loc ('Default') : Loc ('Model');
this.AddProperty (table, new Property (PropertyType.Text, Loc ('Source'), materialSource));
this.AddProperty (table, new Property (PropertyType.Text, Loc ('Type'), typeString));
if (material.vertexColors) {
this.AddProperty (table, new Property (PropertyType.Text, 'Color', 'Vertex colors'));
this.AddProperty (table, new Property (PropertyType.Text, Loc ('Color'), Loc ('Vertex colors')));
} else {
this.AddProperty (table, new Property (PropertyType.Color, 'Color', material.color));
this.AddProperty (table, new Property (PropertyType.Color, Loc ('Color'), material.color));
if (material.type === MaterialType.Phong) {
this.AddProperty (table, new Property (PropertyType.Color, 'Ambient', material.ambient));
this.AddProperty (table, new Property (PropertyType.Color, 'Specular', material.specular));
this.AddProperty (table, new Property (PropertyType.Color, Loc ('Ambient'), material.ambient));
this.AddProperty (table, new Property (PropertyType.Color, Loc ('Specular'), material.specular));
}
}
if (material.type === MaterialType.Physical) {
this.AddProperty (table, new Property (PropertyType.Percent, 'Metalness', material.metalness));
this.AddProperty (table, new Property (PropertyType.Percent, 'Roughness', material.roughness));
this.AddProperty (table, new Property (PropertyType.Percent, Loc ('Metalness'), material.metalness));
this.AddProperty (table, new Property (PropertyType.Percent, Loc ('Roughness'), material.roughness));
}
this.AddProperty (table, new Property (PropertyType.Percent, 'Opacity', material.opacity));
AddTextureMap (this, table, 'Diffuse Map', material.diffuseMap);
AddTextureMap (this, table, 'Bump Map', material.bumpMap);
AddTextureMap (this, table, 'Normal Map', material.normalMap);
AddTextureMap (this, table, 'Emissive Map', material.emissiveMap);
this.AddProperty (table, new Property (PropertyType.Percent, Loc ('Opacity'), material.opacity));
AddTextureMap (this, table, Loc ('Diffuse Map'), material.diffuseMap);
AddTextureMap (this, table, Loc ('Bump Map'), material.bumpMap);
AddTextureMap (this, table, Loc ('Normal Map'), material.normalMap);
AddTextureMap (this, table, Loc ('Emissive Map'), material.emissiveMap);
if (material.type === MaterialType.Phong) {
AddTextureMap (this, table, 'Specular Map', material.specularMap);
AddTextureMap (this, table, Loc ('Specular Map'), material.specularMap);
} else if (material.type === MaterialType.Physical) {
AddTextureMap (this, table, 'Metallic Map', material.metalnessMap);
AddTextureMap (this, table, Loc ('Metallic Map'), material.metalnessMap);
}
this.Resize ();
}
@ -169,10 +170,10 @@ export class SidebarDetailsPanel extends SidebarPanel
let valueColumn = AddDiv (row, 'ov_property_table_cell ov_property_table_value');
nameColumn.setAttribute ('title', name);
let calculateButton = AddDiv (valueColumn, 'ov_property_table_button', 'Calculate...');
let calculateButton = AddDiv (valueColumn, 'ov_property_table_button', Loc ('Calculate...'));
calculateButton.addEventListener ('click', () => {
ClearDomElement (valueColumn);
valueColumn.innerHTML = 'Please wait...';
valueColumn.innerHTML = Loc ('Please wait...');
RunTaskAsync (() => {
let propertyValue = calculateValue ();
if (propertyValue === null) {

View File

@ -7,6 +7,7 @@ import { Settings } from './settings.js';
import { SidebarPanel } from './sidebarpanel.js';
import { ShadingType } from '../engine/threejs/threeutils.js';
import { ProjectionMode } from '../engine/viewer/camera.js';
import { Loc } from '../engine/core/localization.js';
import * as Pickr from '@simonwep/pickr';
import '@simonwep/pickr/dist/themes/monolith.min.css';
@ -194,7 +195,7 @@ class SettingsModelDisplaySection extends SettingsSection
{
constructor (parentDiv, settings)
{
super (parentDiv, 'Model Display', settings);
super (parentDiv, Loc ('Model Display'), settings);
this.backgroundColorPicker = null;
@ -219,7 +220,7 @@ class SettingsModelDisplaySection extends SettingsSection
let backgroundColorDiv = AddDiv (this.contentDiv, 'ov_sidebar_parameter');
let backgroundColorInput = AddDiv (backgroundColorDiv, 'ov_color_picker');
AddDiv (backgroundColorDiv, null, 'Background Color');
AddDiv (backgroundColorDiv, null, Loc ('Background Color'));
let predefinedBackgroundColors = ['#ffffffff', '#e3e3e3ff', '#c9c9c9ff', '#898989ff', '#5f5f5fff', '#494949ff', '#383838ff', '#0f0f0fff'];
let defaultBackgroundColor = '#' + RGBAColorToHexString (this.settings.backgroundColor);
this.backgroundColorPicker = AddColorPicker (backgroundColorInput, true, defaultBackgroundColor, predefinedBackgroundColors, (r, g, b, a) => {
@ -229,7 +230,7 @@ class SettingsModelDisplaySection extends SettingsSection
this.environmentMapPhongDiv = AddDiv (this.contentDiv, 'ov_sidebar_parameter');
this.environmentMapPhongInput = AddDiv (this.environmentMapPhongDiv, 'ov_sidebar_image_picker');
AddDiv (this.environmentMapPhongDiv, null, 'Background Image');
AddDiv (this.environmentMapPhongDiv, null, Loc ('Background Image'));
this.environmentMapPhongInput.addEventListener ('click', () => {
this.environmentMapPopup = new EnvironmentMapPopup ();
this.environmentMapPopup.ShowPopup (this.environmentMapPhongInput, ShadingType.Phong, this.settings, {
@ -245,7 +246,7 @@ class SettingsModelDisplaySection extends SettingsSection
this.environmentMapPbrDiv = AddDiv (this.contentDiv, 'ov_sidebar_parameter');
this.environmentMapPbrInput = AddDiv (this.environmentMapPbrDiv, 'ov_sidebar_image_picker');
AddDiv (this.environmentMapPbrDiv, null, 'Environment');
AddDiv (this.environmentMapPbrDiv, null, Loc ('Environment'));
this.environmentMapPbrInput.addEventListener ('click', () => {
this.environmentMapPopup = new EnvironmentMapPopup ();
this.environmentMapPopup.ShowPopup (this.environmentMapPbrInput, ShadingType.Physical, this.settings, {
@ -263,7 +264,7 @@ class SettingsModelDisplaySection extends SettingsSection
let edgeParameterDiv = AddDiv (this.contentDiv, 'ov_sidebar_parameter');
this.edgeDisplayToggle = AddToggle (edgeParameterDiv, 'ov_sidebar_parameter_toggle');
AddDiv (edgeParameterDiv, 'ov_sidebar_parameter_text', 'Show Edges');
AddDiv (edgeParameterDiv, 'ov_sidebar_parameter_text', Loc ('Show Edges'));
this.edgeSettingsDiv = AddDiv (this.contentDiv, 'ov_sidebar_settings_padded');
this.edgeDisplayToggle.OnChange (() => {
@ -281,11 +282,11 @@ class SettingsModelDisplaySection extends SettingsSection
this.settings.edgeSettings.edgeColor = new RGBColor (r, g, b);
this.callbacks.onEdgeColorChange ();
});
AddDiv (edgeColorRow, null, 'Edge Color');
AddDiv (edgeColorRow, null, Loc ('Edge Color'));
let thresholdRow = AddDiv (this.edgeSettingsDiv, 'ov_sidebar_settings_row large');
this.thresholdSlider = AddRangeSlider (thresholdRow, 0, 90);
this.thresholdSlider.setAttribute ('title', 'Edge Angle Threshold');
this.thresholdSlider.setAttribute ('title', Loc ('Edge Angle Threshold'));
this.thresholdSliderValue = AddDomElement (thresholdRow, 'span', 'ov_slider_label');
this.thresholdSlider.addEventListener ('input', () => {
this.thresholdSliderValue.innerHTML = this.thresholdSlider.value;
@ -375,7 +376,7 @@ class SettingsImportParametersSection extends SettingsSection
{
constructor (parentDiv, settings)
{
super (parentDiv, 'Import Settings', settings);
super (parentDiv, Loc ('Import Settings'), settings);
this.defaultColorPickerDiv = null;
this.defaultLineColorPickerDiv = null;
this.defaultColorPicker = null;
@ -396,12 +397,12 @@ class SettingsImportParametersSection extends SettingsSection
super.Init (callbacks);
this.defaultColorPickerDiv = AddDiv (this.contentDiv);
this.defaultColorPicker = AddDefaultColorPicker (this.defaultColorPickerDiv, 'Default Color', this.settings.defaultColor, (r, g, b, a) => {
this.defaultColorPicker = AddDefaultColorPicker (this.defaultColorPickerDiv, Loc ('Default Color'), this.settings.defaultColor, (r, g, b, a) => {
this.settings.defaultColor = new RGBColor (r, g, b);
this.callbacks.onDefaultColorChanged ();
});
this.defaultLineColorPickerDiv = AddDiv (this.contentDiv);
this.defaultLineColorPicker = AddDefaultColorPicker (this.defaultLineColorPickerDiv, 'Default Line Color', this.settings.defaultLineColor, (r, g, b, a) => {
this.defaultLineColorPicker = AddDefaultColorPicker (this.defaultLineColorPickerDiv, Loc ('Default Line Color'), this.settings.defaultLineColor, (r, g, b, a) => {
this.settings.defaultLineColor = new RGBColor (r, g, b);
this.callbacks.onDefaultColorChanged ();
});
@ -465,7 +466,7 @@ export class SidebarSettingsPanel extends SidebarPanel
GetName ()
{
return 'Settings';
return Loc ('Settings');
}
HasTitle ()

View File

@ -4,6 +4,7 @@ import { ButtonDialog } from './dialog.js';
import { DownloadUrlAsFile } from './utils.js';
import { CookieGetBoolVal, CookieGetIntVal, CookieGetStringVal, CookieSetBoolVal, CookieSetIntVal, CookieSetStringVal } from './cookiehandler.js';
import { HandleEvent } from './eventhandler.js';
import { Loc } from '../engine/core/localization.js';
export function ShowSnapshotDialog (viewer)
{
@ -66,19 +67,19 @@ export function ShowSnapshotDialog (viewer)
let customIndex = 3;
let sizes = [
{
name : 'Small (1280x720)',
name : Loc ('Small (1280x720)'),
size : [1280, 720]
},
{
name : 'Medium (1920x1080)',
name : Loc ('Medium (1920x1080)'),
size : [1920, 1080]
},
{
name : 'Large (2560x1440)',
name : Loc ('Large (2560x1440)'),
size : [2560, 1440]
},
{
name : 'Custom',
name : Loc ('Custom'),
size : null,
widthInput : null,
heightInput : null
@ -86,16 +87,16 @@ export function ShowSnapshotDialog (viewer)
];
let dialog = new ButtonDialog ();
let contentDiv = dialog.Init ('Create Snapshot', [
let contentDiv = dialog.Init (Loc ('Create Snapshot'), [
{
name : 'Cancel',
name : Loc ('Cancel'),
subClass : 'outline',
onClick () {
dialog.Close ();
}
},
{
name : 'Create',
name : Loc ('Create'),
onClick () {
dialog.Close ();
HandleEvent ('snapshot_created', sizes[selectedIndex].name);
@ -135,11 +136,11 @@ export function ShowSnapshotDialog (viewer)
});
}
customSize.widthInput = AddWidthHeightNumberInput (optionsDiv, 'Width', (val) => {
customSize.widthInput = AddWidthHeightNumberInput (optionsDiv, Loc ('Width'), (val) => {
UpdatePreview (viewer, previewImage, GetSize (sizes, selectedIndex), isTransparent);
CookieSetIntVal ('ov_snapshot_custom_width', val);
});
customSize.heightInput = AddWidthHeightNumberInput (optionsDiv, 'Height', (val) => {
customSize.heightInput = AddWidthHeightNumberInput (optionsDiv, Loc ('Height'), (val) => {
UpdatePreview (viewer, previewImage, GetSize (sizes, selectedIndex), isTransparent);
CookieSetIntVal ('ov_snapshot_custom_height', val);
});
@ -149,7 +150,7 @@ export function ShowSnapshotDialog (viewer)
AddDomElement (optionsDiv, 'div', 'ov_snapshot_dialog_separator', null);
let transparentCheckbox = AddCheckbox (optionsDiv, 'snapshot_transparent_background', 'Transparent background', isTransparent, () => {
let transparentCheckbox = AddCheckbox (optionsDiv, 'snapshot_transparent_background', Loc ('Transparent background'), isTransparent, () => {
isTransparent = transparentCheckbox.checked;
UpdatePreview (viewer, previewImage, GetSize (sizes, selectedIndex), isTransparent);
CookieSetBoolVal ('ov_last_snapshot_transparent', isTransparent);

View File

@ -4,6 +4,7 @@ import { ShowMessageDialog } from './dialogs.js';
import { ButtonDialog, ProgressDialog } from './dialog.js';
import { AddSvgIconElement } from './utils.js';
import { ImportErrorCode } from '../engine/import/importer.js';
import { Loc } from '../engine/core/localization.js';
export class ThreeModelLoaderUI
{
@ -25,7 +26,7 @@ export class ThreeModelLoaderUI
this.CloseDialogIfOpen ();
callbacks.onStart ();
progressDialog = new ProgressDialog ();
progressDialog.Init ('Loading Model');
progressDialog.Init (Loc ('Loading Model'));
progressDialog.Open ();
},
onFileListProgress : (current, total) => {
@ -40,10 +41,10 @@ export class ThreeModelLoaderUI
});
},
onImportStart : () => {
progressDialog.SetText ('Importing Model');
progressDialog.SetText (Loc ('Importing Model'));
},
onVisualizationStart : () => {
progressDialog.SetText ('Visualizing Model');
progressDialog.SetText (Loc ('Visualizing Model'));
},
onModelFinished : (importResult, threeObject) => {
progressDialog.Close ();
@ -74,26 +75,26 @@ export class ThreeModelLoaderUI
{
if (importError.code === ImportErrorCode.NoImportableFile) {
return ShowMessageDialog (
'Something went wrong',
'No importable file found.',
Loc ('Something went wrong'),
Loc ('No importable file found.'),
null
);
} else if (importError.code === ImportErrorCode.FailedToLoadFile) {
return ShowMessageDialog (
'Something went wrong',
'Failed to load file for import.',
'The remote server refused to fulfill the request. Check if the url is correct, and make sure that CORS requests are allowed on the remote server.'
Loc ('Something went wrong'),
Loc ('Failed to load file for import.'),
Loc ('The remote server refused to fulfill the request. Check if the url is correct, and make sure that CORS requests are allowed on the remote server.')
);
} else if (importError.code === ImportErrorCode.ImportFailed) {
return ShowMessageDialog (
'Something went wrong',
'Failed to import model.',
Loc ('Something went wrong'),
Loc ('Failed to import model.'),
importError.message
);
} else {
return ShowMessageDialog (
'Something went wrong',
'Unknown error.',
Loc ('Something went wrong'),
Loc ('Unknown error.'),
null
);
}
@ -102,9 +103,9 @@ export class ThreeModelLoaderUI
ShowFileSelectorDialog (fileNames, onSelect)
{
let dialog = new ButtonDialog ();
let contentDiv = dialog.Init ('Select Model', [
let contentDiv = dialog.Init (Loc ('Select Model'), [
{
name : 'Cancel',
name : Loc ('Cancel'),
subClass : 'outline',
onClick () {
dialog.Close ();
@ -115,7 +116,7 @@ export class ThreeModelLoaderUI
onSelect (null);
});
let text = 'Multiple importable models found. Select the model you would like to import from the list below.';
let text = Loc ('Multiple importable models found. Select the model you would like to import from the list below.');
AddDiv (contentDiv, 'ov_dialog_message', text);
let fileListSection = AddDiv (contentDiv, 'ov_dialog_section');

View File

@ -1,6 +1,7 @@
import { RGBColor, RGBColorToHexString } from '../engine/model/color.js';
import { CreateObjectUrl } from '../engine/io/bufferutils.js';
import { AddDiv, CreateDiv, AddDomElement } from '../engine/viewer/domutils.js';
import { Loc } from '../engine/core/localization.js';
export function GetNameOrDefault (originalName, defaultName)
{
@ -12,18 +13,18 @@ export function GetNameOrDefault (originalName, defaultName)
export function GetNodeName (originalName)
{
return GetNameOrDefault (originalName, 'No Name');
return GetNameOrDefault (originalName, Loc ('No Name'));
}
export function GetMeshName (originalNodeName, originalMeshName)
{
let originalName = (originalNodeName.length > 0 ? originalNodeName : originalMeshName);
return GetNameOrDefault (originalName, 'No Name');
return GetNameOrDefault (originalName, Loc ('No Name'));
}
export function GetMaterialName (originalName)
{
return GetNameOrDefault (originalName, 'No Name');
return GetNameOrDefault (originalName, Loc ('No Name'));
}
export function IsHoverEnabled ()

View File

@ -28,6 +28,7 @@ import { CreateVerticalSplitter } from './splitter.js';
import { EnumeratePlugins, PluginType } from './pluginregistry.js';
import { EnvironmentSettings } from '../engine/viewer/shadingmodel.js';
import { IntersectionMode } from '../engine/viewer/viewermodel.js';
import { Loc } from '../engine/core/localization.js';
const WebsiteUIState =
{
@ -338,7 +339,7 @@ export class Website
let items = [];
if (meshUserData === null) {
items.push ({
name : 'Fit model to window',
name : Loc ('Fit model to window'),
icon : 'fit',
onClick : () => {
this.FitModelToWindow (false);
@ -346,7 +347,7 @@ export class Website
});
if (this.navigator.HasHiddenMesh ()) {
items.push ({
name : 'Show all meshes',
name : Loc ('Show all meshes'),
icon : 'visible',
onClick : () => {
this.navigator.ShowAllMeshes (true);
@ -355,14 +356,14 @@ export class Website
}
} else {
items.push ({
name : 'Hide mesh',
name : Loc ('Hide mesh'),
icon : 'hidden',
onClick : () => {
this.navigator.ToggleMeshVisibility (meshUserData.originalMeshInstance.id);
}
});
items.push ({
name : 'Fit mesh to window',
name : Loc ('Fit mesh to window'),
icon : 'fit',
onClick : () => {
this.navigator.FitMeshToWindow (meshUserData.originalMeshInstance.id);
@ -371,7 +372,7 @@ export class Website
if (this.navigator.MeshItemCount () > 1) {
let isMeshIsolated = this.navigator.IsMeshIsolated (meshUserData.originalMeshInstance.id);
items.push ({
name : isMeshIsolated ? 'Remove isolation' : 'Isolate mesh',
name : isMeshIsolated ? Loc ('Remove isolation') : Loc ('Isolate mesh'),
icon : isMeshIsolated ? 'deisolate' : 'isolate',
onClick : () => {
if (isMeshIsolated) {
@ -660,10 +661,10 @@ export class Website
let navigationModeIndex = (this.cameraSettings.navigationMode === NavigationMode.FixedUpVector ? 0 : 1);
let projectionModeIndex = (this.cameraSettings.projectionMode === ProjectionMode.Perspective ? 0 : 1);
AddButton (this.toolbar, 'open', 'Open from your device', [], () => {
AddButton (this.toolbar, 'open', Loc ('Open from your device'), [], () => {
this.OpenFileBrowserDialog ();
});
AddButton (this.toolbar, 'open_url', 'Open from url', [], () => {
AddButton (this.toolbar, 'open_url', Loc ('Open from url'), [], () => {
ShowOpenUrlDialog ((urls) => {
if (urls.length > 0) {
this.hashHandler.SetModelFilesToHash (urls);
@ -671,20 +672,20 @@ export class Website
});
});
AddSeparator (this.toolbar, ['only_on_model']);
AddButton (this.toolbar, 'fit', 'Fit model to window', ['only_on_model'], () => {
AddButton (this.toolbar, 'fit', Loc ('Fit model to window'), ['only_on_model'], () => {
this.FitModelToWindow (false);
});
AddButton (this.toolbar, 'up_y', 'Set Y axis as up vector', ['only_on_model'], () => {
AddButton (this.toolbar, 'up_y', Loc ('Set Y axis as up vector'), ['only_on_model'], () => {
this.viewer.SetUpVector (Direction.Y, true);
});
AddButton (this.toolbar, 'up_z', 'Set Z axis as up vector', ['only_on_model'], () => {
AddButton (this.toolbar, 'up_z', Loc ('Set Z axis as up vector'), ['only_on_model'], () => {
this.viewer.SetUpVector (Direction.Z, true);
});
AddButton (this.toolbar, 'flip', 'Flip up vector', ['only_on_model'], () => {
AddButton (this.toolbar, 'flip', Loc ('Flip up vector'), ['only_on_model'], () => {
this.viewer.FlipUpVector ();
});
AddSeparator (this.toolbar, ['only_full_width', 'only_on_model']);
AddRadioButton (this.toolbar, ['fix_up_on', 'fix_up_off'], ['Fixed up vector', 'Free orbit'], navigationModeIndex, ['only_full_width', 'only_on_model'], (buttonIndex) => {
AddRadioButton (this.toolbar, ['fix_up_on', 'fix_up_off'], [Loc ('Fixed up vector'), Loc ('Free orbit')], navigationModeIndex, ['only_full_width', 'only_on_model'], (buttonIndex) => {
if (buttonIndex === 0) {
this.cameraSettings.navigationMode = NavigationMode.FixedUpVector;
} else if (buttonIndex === 1) {
@ -694,7 +695,7 @@ export class Website
this.viewer.SetNavigationMode (this.cameraSettings.navigationMode);
});
AddSeparator (this.toolbar, ['only_full_width', 'only_on_model']);
AddRadioButton (this.toolbar, ['camera_perspective', 'camera_orthographic'], ['Perspective camera', 'Orthographic camera'], projectionModeIndex, ['only_full_width', 'only_on_model'], (buttonIndex) => {
AddRadioButton (this.toolbar, ['camera_perspective', 'camera_orthographic'], [Loc ('Perspective camera'), Loc ('Orthographic camera')], projectionModeIndex, ['only_full_width', 'only_on_model'], (buttonIndex) => {
if (buttonIndex === 0) {
this.cameraSettings.projectionMode = ProjectionMode.Perspective;
} else if (buttonIndex === 1) {
@ -705,30 +706,30 @@ export class Website
this.sidebar.UpdateControlsVisibility ();
});
AddSeparator (this.toolbar, ['only_full_width', 'only_on_model']);
let measureToolButton = AddPushButton (this.toolbar, 'measure', 'Measure', ['only_full_width', 'only_on_model'], (isSelected) => {
let measureToolButton = AddPushButton (this.toolbar, 'measure', Loc ('Measure'), ['only_full_width', 'only_on_model'], (isSelected) => {
HandleEvent ('measure_tool_activated', isSelected ? 'on' : 'off');
this.navigator.SetSelection (null);
this.measureTool.SetActive (isSelected);
});
this.measureTool.SetButton (measureToolButton);
AddSeparator (this.toolbar, ['only_full_width', 'only_on_model']);
AddButton (this.toolbar, 'download', 'Download', ['only_full_width', 'only_on_model'], () => {
AddButton (this.toolbar, 'download', Loc ('Download'), ['only_full_width', 'only_on_model'], () => {
HandleEvent ('model_downloaded', '');
let importer = this.modelLoaderUI.GetImporter ();
DownloadModel (importer);
});
AddButton (this.toolbar, 'export', 'Export', ['only_full_width', 'only_on_model'], () => {
AddButton (this.toolbar, 'export', Loc ('Export'), ['only_full_width', 'only_on_model'], () => {
ShowExportDialog (this.model, this.viewer, {
isMeshVisible : (meshInstanceId) => {
return this.navigator.IsMeshVisible (meshInstanceId);
}
});
});
AddButton (this.toolbar, 'share', 'Share', ['only_full_width', 'only_on_model'], () => {
AddButton (this.toolbar, 'share', Loc ('Share'), ['only_full_width', 'only_on_model'], () => {
ShowSharingDialog (importer.GetFileList (), this.settings, this.viewer);
});
AddSeparator (this.toolbar, ['only_full_width', 'only_on_model']);
AddButton (this.toolbar, 'snapshot', 'Create snapshot', ['only_full_width', 'only_on_model'], () => {
AddButton (this.toolbar, 'snapshot', Loc ('Create snapshot'), ['only_full_width', 'only_on_model'], () => {
ShowSnapshotDialog (this.viewer);
});
@ -747,7 +748,7 @@ export class Website
});
let selectedTheme = (this.settings.themeId === Theme.Light ? 1 : 0);
AddRadioButton (this.toolbar, ['dark_mode', 'light_mode'], ['Dark mode', 'Light mode'], selectedTheme, ['align_right'], (buttonIndex) => {
AddRadioButton (this.toolbar, ['dark_mode', 'light_mode'], [Loc ('Dark mode'), Loc ('Light mode')], selectedTheme, ['align_right'], (buttonIndex) => {
if (buttonIndex === 0) {
this.settings.themeId = Theme.Dark;
} else if (buttonIndex === 1) {
@ -967,10 +968,10 @@ export class Website
return;
}
let text = 'This website uses cookies to offer you better user experience. See the details at the <a target="_blank" href="info/cookies.html">Cookies Policy</a> page.';
let text = Loc ('This website uses cookies to offer you better user experience. See the details at the <a target="_blank" href="info/cookies.html">Cookies Policy</a> page.');
let popupDiv = AddDiv (document.body, 'ov_bottom_floating_panel');
AddDiv (popupDiv, 'ov_floating_panel_text', text);
let acceptButton = AddDiv (popupDiv, 'ov_button ov_floating_panel_button', 'Accept');
let acceptButton = AddDiv (popupDiv, 'ov_button ov_floating_panel_button', Loc ('Accept'));
acceptButton.addEventListener ('click', () => {
CookieSetBoolVal ('ov_cookie_consent', true);
popupDiv.remove ();