Skip to content

Commit 449ce84

Browse files
committed
Add localization technology to the engine.
1 parent 9156b91 commit 449ce84

16 files changed

+141
-55
lines changed

source/engine/core/core.js

+7
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,13 @@ export function IsObjectEmpty (obj)
2828
return Object.keys (obj).length === 0;
2929
}
3030

31+
export function FormatString (template, ...args)
32+
{
33+
return template.replace (/{([0-9]+)}/g, (match, index) => {
34+
return args[index] === undefined ? match : args[index];
35+
});
36+
}
37+
3138
export function EscapeHtmlChars (str)
3239
{
3340
return str.replace (/</g, '&lt;').replace (/>/g, '&gt;');

source/engine/core/localization.js

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { FormatString } from './core.js';
2+
3+
let gLocalizedStrings = null;
4+
let gLanguageCode = null;
5+
6+
export function SetLocalizedStrings (localizedStrings)
7+
{
8+
gLocalizedStrings = localizedStrings;
9+
}
10+
11+
export function SetLanguageCode (languageCode)
12+
{
13+
gLanguageCode = languageCode;
14+
}
15+
16+
export function Loc (str)
17+
{
18+
if (gLocalizedStrings === null || gLanguageCode === null) {
19+
return str;
20+
}
21+
if (!gLocalizedStrings[str] || !gLocalizedStrings[str][gLanguageCode]) {
22+
return str;
23+
}
24+
return gLocalizedStrings[str][gLanguageCode];
25+
}
26+
27+
export function FLoc (str, ...args)
28+
{
29+
return FormatString (Loc (str), ...args);
30+
}

source/engine/export/exporterbase.js

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { ArrayBufferToUtf8String, Utf8StringToArrayBuffer } from '../io/bufferutils.js';
2+
import { Loc } from '../core/localization.js';
23

34
export class ExportedFile
45
{
@@ -68,12 +69,12 @@ export class ExporterBase
6869

6970
GetExportedMaterialName (originalName)
7071
{
71-
return this.GetExportedName (originalName, 'Material');
72+
return this.GetExportedName (originalName, Loc ('Material'));
7273
}
7374

7475
GetExportedMeshName (originalName)
7576
{
76-
return this.GetExportedName (originalName, 'Mesh');
77+
return this.GetExportedName (originalName, Loc ('Mesh'));
7778
}
7879

7980
GetExportedName (originalName, defaultName)

source/engine/import/importer3dm.js

+6-5
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import { TextureMap } from '../model/material.js';
1414
import { Mesh } from '../model/mesh.js';
1515
import { Line } from '../model/line.js';
1616
import { ArrayToCoord3D } from '../geometry/coord3d.js';
17+
import { Loc } from '../core/localization.js';
1718

1819
export class Importer3dm extends ImporterBase
1920
{
@@ -55,7 +56,7 @@ export class Importer3dm extends ImporterBase
5556
onFinish ();
5657
});
5758
}).catch (() => {
58-
this.SetError ('Failed to load rhino3dm.');
59+
this.SetError (Loc ('Failed to load rhino3dm.'));
5960
onFinish ();
6061
});
6162
} else {
@@ -68,12 +69,12 @@ export class Importer3dm extends ImporterBase
6869
{
6970
let rhinoDoc = this.rhino.File3dm.fromByteArray (fileContent);
7071
if (rhinoDoc === null) {
71-
this.SetError ('Failed to read Rhino file.');
72+
this.SetError (Loc ('Failed to read Rhino file.'));
7273
return;
7374
}
7475
this.ImportRhinoDocument (rhinoDoc);
7576
if (IsModelEmpty (this.model)) {
76-
this.SetError ('The model doesn\'t contain any 3D meshes. Try to save the model while you are in shaded view in Rhino.');
77+
this.SetError (Loc ('The model doesn\'t contain any 3D meshes. Try to save the model while you are in shaded view in Rhino.'));
7778
}
7879
}
7980

@@ -105,7 +106,7 @@ export class Importer3dm extends ImporterBase
105106
{
106107
let docStrings = rhinoDoc.strings ();
107108
if (docStrings.count > 0) {
108-
let propertyGroup = new PropertyGroup ('Document user texts');
109+
let propertyGroup = new PropertyGroup (Loc ('Document user texts'));
109110
for (let i = 0; i < docStrings.count; i++) {
110111
let docString = docStrings.get (i);
111112
propertyGroup.AddProperty (new Property (PropertyType.Text, docString[0], docString[1]));
@@ -238,7 +239,7 @@ export class Importer3dm extends ImporterBase
238239

239240
let userStrings = rhinoAttributes.getUserStrings ();
240241
if (userStrings.length > 0) {
241-
let propertyGroup = new PropertyGroup ('User texts');
242+
let propertyGroup = new PropertyGroup (Loc ('User texts'));
242243
for (let i = 0; i < userStrings.length; i++) {
243244
let userString = userStrings[i];
244245
propertyGroup.AddProperty (new Property (PropertyType.Text, userString[0], userString[1]));

source/engine/import/importerbase.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { Direction } from '../geometry/geometry.js';
22
import { Model } from '../model/model.js';
33
import { FinalizeModel } from '../model/modelfinalization.js';
44
import { IsModelEmpty } from '../model/modelutils.js';
5+
import { Loc } from '../core/localization.js';
56

67
export class ImporterBase
78
{
@@ -51,7 +52,7 @@ export class ImporterBase
5152
}
5253

5354
if (IsModelEmpty (this.model)) {
54-
this.SetError ('The model doesn\'t contain any meshes.');
55+
this.SetError (Loc ('The model doesn\'t contain any meshes.'));
5556
callbacks.onError ();
5657
callbacks.onComplete ();
5758
return;

source/engine/import/importerbim.js

+5-4
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { Transformation } from '../geometry/transformation.js';
1212
import { ColorToMaterialConverter } from './importerutils.js';
1313
import { Property, PropertyGroup, PropertyType } from '../model/property.js';
1414
import { Unit } from '../model/unit.js';
15+
import { Loc } from '../core/localization.js';
1516

1617
export class ImporterBim extends ImporterBase
1718
{
@@ -51,7 +52,7 @@ export class ImporterBim extends ImporterBase
5152
try {
5253
bimJson = JSON.parse (textContent);
5354
} catch (err) {
54-
this.SetError ('Failed to parse bim file.');
55+
this.SetError (Loc ('Failed to parse bim file.'));
5556
onFinish ();
5657
return;
5758
}
@@ -170,9 +171,9 @@ export class ImporterBim extends ImporterBase
170171
}
171172

172173
let info = source.info;
173-
let propertyGroup = new PropertyGroup ('Info');
174-
AddProperty (propertyGroup, 'Guid', source.guid);
175-
AddProperty (propertyGroup, 'Type', source.type);
174+
let propertyGroup = new PropertyGroup (Loc ('Info'));
175+
AddProperty (propertyGroup, Loc ('Guid'), source.guid);
176+
AddProperty (propertyGroup, Loc ('Type'), source.type);
176177
for (let propertyName in info) {
177178
if (Object.prototype.hasOwnProperty.call (info, propertyName)) {
178179
if (typeof info[propertyName] === 'string') {

source/engine/import/importerfcstd.js

+5-4
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { Node } from '../model/node.js';
88
import { ColorToMaterialConverter } from './importerutils.js';
99
import { RGBAColor } from '../model/color.js';
1010
import { Property, PropertyGroup, PropertyType } from '../model/property.js';
11+
import { Loc } from '../core/localization.js';
1112

1213
import * as fflate from 'fflate';
1314

@@ -105,7 +106,7 @@ class FreeCadDocument
105106
return false;
106107
}
107108

108-
this.properties = new PropertyGroup ('Properties');
109+
this.properties = new PropertyGroup (Loc ('Properties'));
109110
let documentElements = documentXml.getElementsByTagName ('Document');
110111
for (let documentElement of documentElements) {
111112
for (let childNode of documentElement.childNodes) {
@@ -140,7 +141,7 @@ class FreeCadDocument
140141
}
141142

142143
let object = this.objectData.get (name);
143-
object.properties = new PropertyGroup ('Properties');
144+
object.properties = new PropertyGroup (Loc ('Properties'));
144145
for (let childNode of objectElement.childNodes) {
145146
if (childNode.tagName === 'Properties') {
146147
this.GetPropertiesFromElement (childNode, object.properties);
@@ -322,7 +323,7 @@ export class ImporterFcstd extends ImporterBase
322323
{
323324
let result = this.document.Init (fileContent);
324325
if (result === DocumentInitResult.NoDocumentXml) {
325-
this.SetError ('No Document.xml found.');
326+
this.SetError (Loc ('No Document.xml found.'));
326327
onFinish ();
327328
return;
328329
}
@@ -333,7 +334,7 @@ export class ImporterFcstd extends ImporterBase
333334

334335
let objectsToConvert = this.document.GetObjectListToConvert ();
335336
if (objectsToConvert.length === 0) {
336-
this.SetError ('No importable object found.');
337+
this.SetError (Loc ('No importable object found.'));
337338
onFinish ();
338339
return;
339340
}

source/engine/import/importergltf.js

+12-11
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { Node } from '../model/node.js';
1515
import { Property, PropertyGroup, PropertyType } from '../model/property.js';
1616
import { Triangle } from '../model/triangle.js';
1717
import { ImporterBase } from './importerbase.js';
18+
import { Loc, FLoc } from '../core/localization.js';
1819

1920
const GltfComponentType =
2021
{
@@ -287,7 +288,7 @@ class GltfExtensions
287288
callbacks.onSuccess ();
288289
});
289290
}).catch (() => {
290-
callbacks.onError ('Failed to load draco decoder.');
291+
callbacks.onError (Loc ('Failed to load draco decoder.'));
291292
});
292293
} else {
293294
callbacks.onSuccess ();
@@ -527,7 +528,7 @@ export class ImporterGltf extends ImporterBase
527528
let textContent = ArrayBufferToUtf8String (fileContent);
528529
let gltf = JSON.parse (textContent);
529530
if (gltf.asset.version !== '2.0') {
530-
this.SetError ('Invalid glTF version.');
531+
this.SetError (Loc ('Invalid glTF version.'));
531532
onFinish ();
532533
return;
533534
}
@@ -545,7 +546,7 @@ export class ImporterGltf extends ImporterBase
545546
}
546547
}
547548
if (buffer === null) {
548-
this.SetError ('One of the requested buffers is missing.');
549+
this.SetError (Loc ('One of the requested buffers is missing.'));
549550
onFinish ();
550551
return;
551552
}
@@ -571,19 +572,19 @@ export class ImporterGltf extends ImporterBase
571572
let reader = new BinaryReader (fileContent, true);
572573
let magic = reader.ReadUnsignedInteger32 ();
573574
if (magic !== GltfConstants.GLTF_STRING) {
574-
this.SetError ('Invalid glTF file.');
575+
this.SetError (Loc ('Invalid glTF file.'));
575576
onFinish ();
576577
return;
577578
}
578579
let version = reader.ReadUnsignedInteger32 ();
579580
if (version !== 2) {
580-
this.SetError ('Invalid glTF version.');
581+
this.SetError (Loc ('Invalid glTF version.'));
581582
onFinish ();
582583
return;
583584
}
584585
let length = reader.ReadUnsignedInteger32 ();
585586
if (length !== reader.GetByteLength ()) {
586-
this.SetError ('Invalid glTF file.');
587+
this.SetError (Loc ('Invalid glTF file.'));
587588
onFinish ();
588589
return;
589590
}
@@ -608,7 +609,7 @@ export class ImporterGltf extends ImporterBase
608609
{
609610
let unsupportedExtensions = this.gltfExtensions.GetUnsupportedExtensions (gltf.extensionsRequired);
610611
if (unsupportedExtensions.length > 0) {
611-
this.SetError ('Unsupported extension: ' + unsupportedExtensions.join (', ') + '.');
612+
this.SetError (FLoc ('Unsupported extension: {0}.', unsupportedExtensions.join (', ')));
612613
onFinish ();
613614
return;
614615
}
@@ -641,7 +642,7 @@ export class ImporterGltf extends ImporterBase
641642
}
642643
}
643644

644-
this.ImportProperties (this.model, gltf.asset, 'Asset properties');
645+
this.ImportProperties (this.model, gltf.asset, Loc ('Asset properties'));
645646
this.ImportScene (gltf);
646647
}
647648

@@ -809,7 +810,7 @@ export class ImporterGltf extends ImporterBase
809810
this.ImportPrimitive (gltf, primitive, mesh);
810811
}
811812

812-
this.ImportProperties (mesh, gltfMesh.extras, 'Mesh properties');
813+
this.ImportProperties (mesh, gltfMesh.extras, Loc ('Mesh properties'));
813814
}
814815

815816
ImportPrimitive (gltf, primitive, mesh)
@@ -1006,7 +1007,7 @@ export class ImporterGltf extends ImporterBase
10061007
this.ImportNode (gltf, gltfNode, rootNode);
10071008
}
10081009

1009-
this.ImportProperties (this.model, scene.extras, 'Scene properties');
1010+
this.ImportProperties (this.model, scene.extras, Loc ('Scene properties'));
10101011
}
10111012

10121013
ImportNode (gltf, gltfNode, parentNode)
@@ -1058,7 +1059,7 @@ export class ImporterGltf extends ImporterBase
10581059

10591060
if (gltfNode.mesh !== undefined) {
10601061
let mesh = this.model.GetMesh (gltfNode.mesh);
1061-
this.ImportProperties (mesh, gltfNode.extras, 'Node properties');
1062+
this.ImportProperties (mesh, gltfNode.extras, Loc ('Node properties'));
10621063
node.AddMeshIndex (gltfNode.mesh);
10631064
}
10641065
}

source/engine/import/importerifc.js

+6-5
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { Property, PropertyGroup, PropertyType } from '../model/property.js';
99
import { Triangle } from '../model/triangle.js';
1010
import { ImporterBase } from './importerbase.js';
1111
import { ColorToMaterialConverter } from './importerutils.js';
12+
import { Loc, FLoc } from '../core/localization.js';
1213

1314
export class ImporterIfc extends ImporterBase
1415
{
@@ -50,7 +51,7 @@ export class ImporterIfc extends ImporterBase
5051
onFinish ();
5152
});
5253
}).catch (() => {
53-
this.SetError ('Failed to load web-ifc.');
54+
this.SetError (Loc ('Failed to load web-ifc.'));
5455
onFinish ();
5556
});
5657
} else {
@@ -79,7 +80,7 @@ export class ImporterIfc extends ImporterBase
7980
ImportIfcMesh (modelID, ifcMesh)
8081
{
8182
let mesh = new Mesh ();
82-
mesh.SetName ('Mesh ' + ifcMesh.expressID.toString ());
83+
mesh.SetName (FLoc ('Mesh {0}', ifcMesh.expressID.toString ()));
8384

8485
let vertexOffset = 0;
8586
const ifcGeometries = ifcMesh.geometries;
@@ -170,11 +171,11 @@ export class ImporterIfc extends ImporterBase
170171
break;
171172
case 'IfcBoolean':
172173
case 'IfcLogical':
173-
strValue = 'Unknown';
174+
strValue = Loc ('Unknown');
174175
if (property.NominalValue.value === 'T') {
175-
strValue = 'True';
176+
strValue = Loc ('True');
176177
} else if (property.NominalValue.value === 'F') {
177-
strValue = 'False';
178+
strValue = Loc ('False');
178179
}
179180
elemProperty = new Property (PropertyType.Text, propertyName, strValue);
180181
break;

0 commit comments

Comments
 (0)