diff --git a/source/website/dialogs.js b/source/website/dialogs.js index 602de83c..a5ea97ec 100644 --- a/source/website/dialogs.js +++ b/source/website/dialogs.js @@ -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 (); } diff --git a/source/website/exportdialog.js b/source/website/exportdialog.js index 65cd15d3..988a6bcf 100644 --- a/source/website/exportdialog.js +++ b/source/website/exportdialog.js @@ -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'); diff --git a/source/website/measuretool.js b/source/website/measuretool.js index 73426084..c3a79f48 100644 --- a/source/website/measuretool.js +++ b/source/website/measuretool.js @@ -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]); diff --git a/source/website/navigatorfilespanel.js b/source/website/navigatorfilespanel.js index 4879c8e8..b77dc5de 100644 --- a/source/website/navigatorfilespanel.js +++ b/source/website/navigatorfilespanel.js @@ -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++) { diff --git a/source/website/navigatormaterialspanel.js b/source/website/navigatormaterialspanel.js index ea33f80e..8677e4ea 100644 --- a/source/website/navigatormaterialspanel.js +++ b/source/website/navigatormaterialspanel.js @@ -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 () diff --git a/source/website/navigatormeshespanel.js b/source/website/navigatormeshespanel.js index 19303380..d9a9c25b 100644 --- a/source/website/navigatormeshespanel.js +++ b/source/website/navigatormeshespanel.js @@ -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 diff --git a/source/website/openurldialog.js b/source/website/openurldialog.js index ca5aa2c6..f934e706 100644 --- a/source/website/openurldialog.js +++ b/source/website/openurldialog.js @@ -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 (); diff --git a/source/website/sharingdialog.js b/source/website/sharingdialog.js index db96a7ff..0feb5b04 100644 --- a/source/website/sharingdialog.js +++ b/source/website/sharingdialog.js @@ -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 (); } diff --git a/source/website/sidebardetailspanel.js b/source/website/sidebardetailspanel.js index 73211bc1..294331b6 100644 --- a/source/website/sidebardetailspanel.js +++ b/source/website/sidebardetailspanel.js @@ -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) { diff --git a/source/website/sidebarsettingspanel.js b/source/website/sidebarsettingspanel.js index 5ed9008f..5332ee19 100644 --- a/source/website/sidebarsettingspanel.js +++ b/source/website/sidebarsettingspanel.js @@ -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 () diff --git a/source/website/snapshotdialog.js b/source/website/snapshotdialog.js index 26dd97c0..93c66644 100644 --- a/source/website/snapshotdialog.js +++ b/source/website/snapshotdialog.js @@ -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); diff --git a/source/website/threemodelloaderui.js b/source/website/threemodelloaderui.js index 8e32afb0..ed744a2c 100644 --- a/source/website/threemodelloaderui.js +++ b/source/website/threemodelloaderui.js @@ -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'); diff --git a/source/website/utils.js b/source/website/utils.js index a51592f8..2a6eaa38 100644 --- a/source/website/utils.js +++ b/source/website/utils.js @@ -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 () diff --git a/source/website/website.js b/source/website/website.js index c75450c4..45c38de8 100644 --- a/source/website/website.js +++ b/source/website/website.js @@ -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 Cookies Policy page.'; + let text = Loc ('This website uses cookies to offer you better user experience. See the details at the Cookies Policy 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 ();