diff --git a/source/engine/core/core.js b/source/engine/core/core.js index cba8113..e9cb94b 100644 --- a/source/engine/core/core.js +++ b/source/engine/core/core.js @@ -28,6 +28,13 @@ export function IsObjectEmpty (obj) return Object.keys (obj).length === 0; } +export function FormatString (template, ...args) +{ + return template.replace (/{([0-9]+)}/g, (match, index) => { + return args[index] === undefined ? match : args[index]; + }); +} + export function EscapeHtmlChars (str) { return str.replace (//g, '>'); diff --git a/source/engine/core/localization.js b/source/engine/core/localization.js new file mode 100644 index 0000000..fbb14e7 --- /dev/null +++ b/source/engine/core/localization.js @@ -0,0 +1,30 @@ +import { FormatString } from './core.js'; + +let gLocalizedStrings = null; +let gLanguageCode = null; + +export function SetLocalizedStrings (localizedStrings) +{ + gLocalizedStrings = localizedStrings; +} + +export function SetLanguageCode (languageCode) +{ + gLanguageCode = languageCode; +} + +export function Loc (str) +{ + if (gLocalizedStrings === null || gLanguageCode === null) { + return str; + } + if (!gLocalizedStrings[str] || !gLocalizedStrings[str][gLanguageCode]) { + return str; + } + return gLocalizedStrings[str][gLanguageCode]; +} + +export function FLoc (str, ...args) +{ + return FormatString (Loc (str), ...args); +} diff --git a/source/engine/export/exporterbase.js b/source/engine/export/exporterbase.js index 721f595..f70508c 100644 --- a/source/engine/export/exporterbase.js +++ b/source/engine/export/exporterbase.js @@ -1,4 +1,5 @@ import { ArrayBufferToUtf8String, Utf8StringToArrayBuffer } from '../io/bufferutils.js'; +import { Loc } from '../core/localization.js'; export class ExportedFile { @@ -68,12 +69,12 @@ export class ExporterBase GetExportedMaterialName (originalName) { - return this.GetExportedName (originalName, 'Material'); + return this.GetExportedName (originalName, Loc ('Material')); } GetExportedMeshName (originalName) { - return this.GetExportedName (originalName, 'Mesh'); + return this.GetExportedName (originalName, Loc ('Mesh')); } GetExportedName (originalName, defaultName) diff --git a/source/engine/import/importer3dm.js b/source/engine/import/importer3dm.js index 973e572..e7e1f3c 100644 --- a/source/engine/import/importer3dm.js +++ b/source/engine/import/importer3dm.js @@ -14,6 +14,7 @@ import { TextureMap } from '../model/material.js'; import { Mesh } from '../model/mesh.js'; import { Line } from '../model/line.js'; import { ArrayToCoord3D } from '../geometry/coord3d.js'; +import { Loc } from '../core/localization.js'; export class Importer3dm extends ImporterBase { @@ -55,7 +56,7 @@ export class Importer3dm extends ImporterBase onFinish (); }); }).catch (() => { - this.SetError ('Failed to load rhino3dm.'); + this.SetError (Loc ('Failed to load rhino3dm.')); onFinish (); }); } else { @@ -68,12 +69,12 @@ export class Importer3dm extends ImporterBase { let rhinoDoc = this.rhino.File3dm.fromByteArray (fileContent); if (rhinoDoc === null) { - this.SetError ('Failed to read Rhino file.'); + this.SetError (Loc ('Failed to read Rhino file.')); return; } this.ImportRhinoDocument (rhinoDoc); if (IsModelEmpty (this.model)) { - this.SetError ('The model doesn\'t contain any 3D meshes. Try to save the model while you are in shaded view in Rhino.'); + this.SetError (Loc ('The model doesn\'t contain any 3D meshes. Try to save the model while you are in shaded view in Rhino.')); } } @@ -105,7 +106,7 @@ export class Importer3dm extends ImporterBase { let docStrings = rhinoDoc.strings (); if (docStrings.count > 0) { - let propertyGroup = new PropertyGroup ('Document user texts'); + let propertyGroup = new PropertyGroup (Loc ('Document user texts')); for (let i = 0; i < docStrings.count; i++) { let docString = docStrings.get (i); propertyGroup.AddProperty (new Property (PropertyType.Text, docString[0], docString[1])); @@ -238,7 +239,7 @@ export class Importer3dm extends ImporterBase let userStrings = rhinoAttributes.getUserStrings (); if (userStrings.length > 0) { - let propertyGroup = new PropertyGroup ('User texts'); + let propertyGroup = new PropertyGroup (Loc ('User texts')); for (let i = 0; i < userStrings.length; i++) { let userString = userStrings[i]; propertyGroup.AddProperty (new Property (PropertyType.Text, userString[0], userString[1])); diff --git a/source/engine/import/importerbase.js b/source/engine/import/importerbase.js index 4e3a41b..1fcbd37 100644 --- a/source/engine/import/importerbase.js +++ b/source/engine/import/importerbase.js @@ -2,6 +2,7 @@ import { Direction } from '../geometry/geometry.js'; import { Model } from '../model/model.js'; import { FinalizeModel } from '../model/modelfinalization.js'; import { IsModelEmpty } from '../model/modelutils.js'; +import { Loc } from '../core/localization.js'; export class ImporterBase { @@ -51,7 +52,7 @@ export class ImporterBase } if (IsModelEmpty (this.model)) { - this.SetError ('The model doesn\'t contain any meshes.'); + this.SetError (Loc ('The model doesn\'t contain any meshes.')); callbacks.onError (); callbacks.onComplete (); return; diff --git a/source/engine/import/importerbim.js b/source/engine/import/importerbim.js index 48103df..1082858 100644 --- a/source/engine/import/importerbim.js +++ b/source/engine/import/importerbim.js @@ -12,6 +12,7 @@ import { Transformation } from '../geometry/transformation.js'; import { ColorToMaterialConverter } from './importerutils.js'; import { Property, PropertyGroup, PropertyType } from '../model/property.js'; import { Unit } from '../model/unit.js'; +import { Loc } from '../core/localization.js'; export class ImporterBim extends ImporterBase { @@ -51,7 +52,7 @@ export class ImporterBim extends ImporterBase try { bimJson = JSON.parse (textContent); } catch (err) { - this.SetError ('Failed to parse bim file.'); + this.SetError (Loc ('Failed to parse bim file.')); onFinish (); return; } @@ -170,9 +171,9 @@ export class ImporterBim extends ImporterBase } let info = source.info; - let propertyGroup = new PropertyGroup ('Info'); - AddProperty (propertyGroup, 'Guid', source.guid); - AddProperty (propertyGroup, 'Type', source.type); + let propertyGroup = new PropertyGroup (Loc ('Info')); + AddProperty (propertyGroup, Loc ('Guid'), source.guid); + AddProperty (propertyGroup, Loc ('Type'), source.type); for (let propertyName in info) { if (Object.prototype.hasOwnProperty.call (info, propertyName)) { if (typeof info[propertyName] === 'string') { diff --git a/source/engine/import/importerfcstd.js b/source/engine/import/importerfcstd.js index 1dc0507..69c150f 100644 --- a/source/engine/import/importerfcstd.js +++ b/source/engine/import/importerfcstd.js @@ -8,6 +8,7 @@ import { Node } from '../model/node.js'; import { ColorToMaterialConverter } from './importerutils.js'; import { RGBAColor } from '../model/color.js'; import { Property, PropertyGroup, PropertyType } from '../model/property.js'; +import { Loc } from '../core/localization.js'; import * as fflate from 'fflate'; @@ -105,7 +106,7 @@ class FreeCadDocument return false; } - this.properties = new PropertyGroup ('Properties'); + this.properties = new PropertyGroup (Loc ('Properties')); let documentElements = documentXml.getElementsByTagName ('Document'); for (let documentElement of documentElements) { for (let childNode of documentElement.childNodes) { @@ -140,7 +141,7 @@ class FreeCadDocument } let object = this.objectData.get (name); - object.properties = new PropertyGroup ('Properties'); + object.properties = new PropertyGroup (Loc ('Properties')); for (let childNode of objectElement.childNodes) { if (childNode.tagName === 'Properties') { this.GetPropertiesFromElement (childNode, object.properties); @@ -322,7 +323,7 @@ export class ImporterFcstd extends ImporterBase { let result = this.document.Init (fileContent); if (result === DocumentInitResult.NoDocumentXml) { - this.SetError ('No Document.xml found.'); + this.SetError (Loc ('No Document.xml found.')); onFinish (); return; } @@ -333,7 +334,7 @@ export class ImporterFcstd extends ImporterBase let objectsToConvert = this.document.GetObjectListToConvert (); if (objectsToConvert.length === 0) { - this.SetError ('No importable object found.'); + this.SetError (Loc ('No importable object found.')); onFinish (); return; } diff --git a/source/engine/import/importergltf.js b/source/engine/import/importergltf.js index 54b19b0..52c59ab 100644 --- a/source/engine/import/importergltf.js +++ b/source/engine/import/importergltf.js @@ -15,6 +15,7 @@ import { Node } from '../model/node.js'; import { Property, PropertyGroup, PropertyType } from '../model/property.js'; import { Triangle } from '../model/triangle.js'; import { ImporterBase } from './importerbase.js'; +import { Loc, FLoc } from '../core/localization.js'; const GltfComponentType = { @@ -287,7 +288,7 @@ class GltfExtensions callbacks.onSuccess (); }); }).catch (() => { - callbacks.onError ('Failed to load draco decoder.'); + callbacks.onError (Loc ('Failed to load draco decoder.')); }); } else { callbacks.onSuccess (); @@ -527,7 +528,7 @@ export class ImporterGltf extends ImporterBase let textContent = ArrayBufferToUtf8String (fileContent); let gltf = JSON.parse (textContent); if (gltf.asset.version !== '2.0') { - this.SetError ('Invalid glTF version.'); + this.SetError (Loc ('Invalid glTF version.')); onFinish (); return; } @@ -545,7 +546,7 @@ export class ImporterGltf extends ImporterBase } } if (buffer === null) { - this.SetError ('One of the requested buffers is missing.'); + this.SetError (Loc ('One of the requested buffers is missing.')); onFinish (); return; } @@ -571,19 +572,19 @@ export class ImporterGltf extends ImporterBase let reader = new BinaryReader (fileContent, true); let magic = reader.ReadUnsignedInteger32 (); if (magic !== GltfConstants.GLTF_STRING) { - this.SetError ('Invalid glTF file.'); + this.SetError (Loc ('Invalid glTF file.')); onFinish (); return; } let version = reader.ReadUnsignedInteger32 (); if (version !== 2) { - this.SetError ('Invalid glTF version.'); + this.SetError (Loc ('Invalid glTF version.')); onFinish (); return; } let length = reader.ReadUnsignedInteger32 (); if (length !== reader.GetByteLength ()) { - this.SetError ('Invalid glTF file.'); + this.SetError (Loc ('Invalid glTF file.')); onFinish (); return; } @@ -608,7 +609,7 @@ export class ImporterGltf extends ImporterBase { let unsupportedExtensions = this.gltfExtensions.GetUnsupportedExtensions (gltf.extensionsRequired); if (unsupportedExtensions.length > 0) { - this.SetError ('Unsupported extension: ' + unsupportedExtensions.join (', ') + '.'); + this.SetError (FLoc ('Unsupported extension: {0}.', unsupportedExtensions.join (', '))); onFinish (); return; } @@ -641,7 +642,7 @@ export class ImporterGltf extends ImporterBase } } - this.ImportProperties (this.model, gltf.asset, 'Asset properties'); + this.ImportProperties (this.model, gltf.asset, Loc ('Asset properties')); this.ImportScene (gltf); } @@ -809,7 +810,7 @@ export class ImporterGltf extends ImporterBase this.ImportPrimitive (gltf, primitive, mesh); } - this.ImportProperties (mesh, gltfMesh.extras, 'Mesh properties'); + this.ImportProperties (mesh, gltfMesh.extras, Loc ('Mesh properties')); } ImportPrimitive (gltf, primitive, mesh) @@ -1006,7 +1007,7 @@ export class ImporterGltf extends ImporterBase this.ImportNode (gltf, gltfNode, rootNode); } - this.ImportProperties (this.model, scene.extras, 'Scene properties'); + this.ImportProperties (this.model, scene.extras, Loc ('Scene properties')); } ImportNode (gltf, gltfNode, parentNode) @@ -1058,7 +1059,7 @@ export class ImporterGltf extends ImporterBase if (gltfNode.mesh !== undefined) { let mesh = this.model.GetMesh (gltfNode.mesh); - this.ImportProperties (mesh, gltfNode.extras, 'Node properties'); + this.ImportProperties (mesh, gltfNode.extras, Loc ('Node properties')); node.AddMeshIndex (gltfNode.mesh); } } diff --git a/source/engine/import/importerifc.js b/source/engine/import/importerifc.js index 3fc019e..417a0b9 100644 --- a/source/engine/import/importerifc.js +++ b/source/engine/import/importerifc.js @@ -9,6 +9,7 @@ import { Property, PropertyGroup, PropertyType } from '../model/property.js'; import { Triangle } from '../model/triangle.js'; import { ImporterBase } from './importerbase.js'; import { ColorToMaterialConverter } from './importerutils.js'; +import { Loc, FLoc } from '../core/localization.js'; export class ImporterIfc extends ImporterBase { @@ -50,7 +51,7 @@ export class ImporterIfc extends ImporterBase onFinish (); }); }).catch (() => { - this.SetError ('Failed to load web-ifc.'); + this.SetError (Loc ('Failed to load web-ifc.')); onFinish (); }); } else { @@ -79,7 +80,7 @@ export class ImporterIfc extends ImporterBase ImportIfcMesh (modelID, ifcMesh) { let mesh = new Mesh (); - mesh.SetName ('Mesh ' + ifcMesh.expressID.toString ()); + mesh.SetName (FLoc ('Mesh {0}', ifcMesh.expressID.toString ())); let vertexOffset = 0; const ifcGeometries = ifcMesh.geometries; @@ -170,11 +171,11 @@ export class ImporterIfc extends ImporterBase break; case 'IfcBoolean': case 'IfcLogical': - strValue = 'Unknown'; + strValue = Loc ('Unknown'); if (property.NominalValue.value === 'T') { - strValue = 'True'; + strValue = Loc ('True'); } else if (property.NominalValue.value === 'F') { - strValue = 'False'; + strValue = Loc ('False'); } elemProperty = new Property (PropertyType.Text, propertyName, strValue); break; diff --git a/source/engine/import/importerobj.js b/source/engine/import/importerobj.js index 897bcee..30b7e4f 100644 --- a/source/engine/import/importerobj.js +++ b/source/engine/import/importerobj.js @@ -9,6 +9,7 @@ import { Mesh } from '../model/mesh.js'; import { Triangle } from '../model/triangle.js'; import { ImporterBase } from './importerbase.js'; import { NameFromLine, ParametersFromLine, ReadLines, UpdateMaterialTransparency } from './importerutils.js'; +import { Loc } from '../core/localization.js'; class ObjMeshConverter { @@ -398,7 +399,7 @@ export class ImporterObj extends ImporterBase let vertexIndex = this.GetRelativeIndex (parseInt (vertexParams[0], 10), this.globalVertices.length); let meshVertexIndex = this.currentMeshConverter.AddVertex (vertexIndex, this.globalVertices); if (meshVertexIndex === null) { - this.SetError ('Invalid vertex index.'); + this.SetError (Loc ('Invalid vertex index.')); break; } vertices.push (meshVertexIndex); @@ -442,7 +443,7 @@ export class ImporterObj extends ImporterBase let v1 = this.currentMeshConverter.AddVertex (vertices[i + 1], this.globalVertices); let v2 = this.currentMeshConverter.AddVertex (vertices[i + 2], this.globalVertices); if (v0 === null || v1 === null || v2 === null) { - this.SetError ('Invalid vertex index.'); + this.SetError (Loc ('Invalid vertex index.')); break; } @@ -453,7 +454,7 @@ export class ImporterObj extends ImporterBase let c1 = this.currentMeshConverter.AddVertexColor (colors[i + 1], this.globalVertexColors); let c2 = this.currentMeshConverter.AddVertexColor (colors[i + 2], this.globalVertexColors); if (c0 === null || c1 === null || c2 === null) { - this.SetError ('Invalid vertex color index.'); + this.SetError (Loc ('Invalid vertex color index.')); break; } triangle.SetVertexColors (c0, c1, c2); @@ -464,7 +465,7 @@ export class ImporterObj extends ImporterBase let n1 = this.currentMeshConverter.AddNormal (normals[i + 1], this.globalNormals); let n2 = this.currentMeshConverter.AddNormal (normals[i + 2], this.globalNormals); if (n0 === null || n1 === null || n2 === null) { - this.SetError ('Invalid normal index.'); + this.SetError (Loc ('Invalid normal index.')); break; } triangle.SetNormals (n0, n1, n2); @@ -475,7 +476,7 @@ export class ImporterObj extends ImporterBase let u1 = this.currentMeshConverter.AddUV (uvs[i + 1], this.globalUvs); let u2 = this.currentMeshConverter.AddUV (uvs[i + 2], this.globalUvs); if (u0 === null || u1 === null || u2 === null) { - this.SetError ('Invalid uv index.'); + this.SetError (Loc ('Invalid uv index.')); break; } triangle.SetTextureUVs (u0, u1, u2); diff --git a/source/engine/import/importerocct.js b/source/engine/import/importerocct.js index a25d2e6..8b80a6e 100644 --- a/source/engine/import/importerocct.js +++ b/source/engine/import/importerocct.js @@ -6,6 +6,7 @@ import { ConvertThreeGeometryToMesh } from '../threejs/threeutils.js'; import { ImporterBase } from './importerbase.js'; import { ColorToMaterialConverter } from './importerutils.js'; import { Unit } from '../model/unit.js'; +import { Loc } from '../core/localization.js'; export class ImporterOcct extends ImporterBase { @@ -46,7 +47,7 @@ export class ImporterOcct extends ImporterBase this.ImportResultJson (ev.data, onFinish); }); this.worker.addEventListener ('error', (ev) => { - this.SetError ('Failed to load occt-import-js.'); + this.SetError (Loc ('Failed to load occt-import-js.')); onFinish (); }); diff --git a/source/engine/import/importerply.js b/source/engine/import/importerply.js index 72fe013..4d3420c 100644 --- a/source/engine/import/importerply.js +++ b/source/engine/import/importerply.js @@ -8,6 +8,7 @@ import { Mesh } from '../model/mesh.js'; import { Triangle } from '../model/triangle.js'; import { ImporterBase } from './importerbase.js'; import { ParametersFromLine, ReadLines, UpdateMaterialTransparency } from './importerutils.js'; +import { Loc, FLoc } from '../core/localization.js'; const PlyHeaderCheckResult = { @@ -113,11 +114,12 @@ class PlyMaterialHandler GetMaterialIndexByColor (color) { - let materialName = 'Color ' + - IntegerToHexString (color[0]) + - IntegerToHexString (color[1]) + - IntegerToHexString (color[2]) + - IntegerToHexString (color[3]); + let materialName = FLoc ('Color {0}{1}{2}{3}', + IntegerToHexString (color[0]), + IntegerToHexString (color[1]), + IntegerToHexString (color[2]), + IntegerToHexString (color[3]) + ); if (this.colorToMaterial.has (materialName)) { return this.colorToMaterial.get (materialName); @@ -177,11 +179,11 @@ export class ImporterPly extends ImporterBase } } else { if (checkResult === PlyHeaderCheckResult.NoVertices) { - this.SetError ('The model contains no vertices.'); + this.SetError (Loc ('The model contains no vertices.')); } else if (checkResult === PlyHeaderCheckResult.NoFaces) { - this.SetError ('The model contains no faces.'); + this.SetError (Loc ('The model contains no faces.')); } else { - this.SetError ('Invalid header information.'); + this.SetError (Loc ('Invalid header information.')); } } onFinish (); diff --git a/source/engine/main.js b/source/engine/main.js index 87404b7..0996453 100644 --- a/source/engine/main.js +++ b/source/engine/main.js @@ -1,5 +1,6 @@ -import { IsDefined, ValueOrDefault, CopyObjectAttributes, IsObjectEmpty, EscapeHtmlChars } from './core/core.js'; +import { IsDefined, ValueOrDefault, CopyObjectAttributes, IsObjectEmpty, FormatString, EscapeHtmlChars } from './core/core.js'; import { EventNotifier } from './core/eventnotifier.js'; +import { SetLocalizedStrings, SetLanguageCode, Loc, FLoc } from './core/localization.js'; import { TaskRunner, RunTaskAsync, RunTasks, RunTasksBatch, WaitWhile } from './core/taskrunner.js'; import { Exporter } from './export/exporter.js'; import { Exporter3dm } from './export/exporter3dm.js'; @@ -80,8 +81,13 @@ export { ValueOrDefault, CopyObjectAttributes, IsObjectEmpty, + FormatString, EscapeHtmlChars, EventNotifier, + SetLocalizedStrings, + SetLanguageCode, + Loc, + FLoc, TaskRunner, RunTaskAsync, RunTasks, diff --git a/source/engine/model/property.js b/source/engine/model/property.js index 1cf8592..f158c1b 100644 --- a/source/engine/model/property.js +++ b/source/engine/model/property.js @@ -1,5 +1,6 @@ import { EscapeHtmlChars } from '../core/core.js'; import { RGBColorToHexString } from './color.js'; +import { Loc } from '../core/localization.js'; export const PropertyType = { @@ -76,7 +77,7 @@ export function PropertyToString (property) maximumFractionDigits: 2 }); } else if (property.type === PropertyType.Boolean) { - return property.value ? 'True' : 'False'; + return property.value ? Loc ('True') : Loc ('False'); } else if (property.type === PropertyType.Percent) { return parseInt (property.value * 100, 10).toString () + '%'; } else if (property.type === PropertyType.Color) { diff --git a/source/engine/viewer/embeddedviewer.js b/source/engine/viewer/embeddedviewer.js index 5f96af5..92c8ad2 100644 --- a/source/engine/viewer/embeddedviewer.js +++ b/source/engine/viewer/embeddedviewer.js @@ -7,6 +7,7 @@ import { ParameterConverter } from '../parameters/parameterlist.js'; import { ThreeModelLoader } from '../threejs/threemodelloader.js'; import { Viewer } from './viewer.js'; import { EnvironmentSettings } from './shadingmodel.js'; +import { Loc } from '../core/localization.js'; /** * This is the main object for embedding the viewer on a website. @@ -124,7 +125,7 @@ export class EmbeddedViewer onLoadStart : () => { this.canvas.style.display = 'none'; progressDiv = document.createElement ('div'); - progressDiv.innerHTML = 'Loading model...'; + progressDiv.innerHTML = Loc ('Loading model...'); this.parentElement.appendChild (progressDiv); }, onFileListProgress : (current, total) => { @@ -132,10 +133,10 @@ export class EmbeddedViewer onFileLoadProgress : (current, total) => { }, onImportStart : () => { - progressDiv.innerHTML = 'Importing model...'; + progressDiv.innerHTML = Loc ('Importing model...'); }, onVisualizationStart : () => { - progressDiv.innerHTML = 'Visualizing model...'; + progressDiv.innerHTML = Loc ('Visualizing model...'); }, onModelFinished : (importResult, threeObject) => { this.parentElement.removeChild (progressDiv); @@ -161,13 +162,13 @@ export class EmbeddedViewer this.viewer.Render (); }, onLoadError : (importError) => { - let message = 'Unknown error.'; + let message = Loc ('Unknown error.'); if (importError.code === ImportErrorCode.NoImportableFile) { - message = 'No importable file found.'; + message = Loc ('No importable file found.'); } else if (importError.code === ImportErrorCode.FailedToLoadFile) { - message = 'Failed to load file for import.'; + message = Loc ('Failed to load file for import.'); } else if (importError.code === ImportErrorCode.ImportFailed) { - message = 'Failed to import model.'; + message = Loc ('Failed to import model.'); } if (importError.message !== null) { message += ' (' + importError.message + ')'; diff --git a/test/tests/core_test.js b/test/tests/core_test.js index 71450e7..1c86885 100644 --- a/test/tests/core_test.js +++ b/test/tests/core_test.js @@ -67,6 +67,36 @@ describe ('Core', function () { assert.ok (!en.HasEventListener ('third_event')); assert.strictEqual (sumValues, 90); }); + + it ('Localization', function () { + assert.strictEqual (OV.Loc ('Test'), 'Test'); + assert.strictEqual (OV.FLoc ('Test {0}', '1'), 'Test 1'); + OV.SetLocalizedStrings ({ + 'Test' : { + 'hu': 'Teszt' + }, + 'Test {0}' : { + 'hu': 'Teszt {0}' + }, + 'Test {0} {0}' : { + 'hu': 'Teszt {0} {0}' + }, + 'Test {0} {0} {1}' : { + 'hu': 'Teszt {0} {0} {1}' + } + }); + OV.SetLanguageCode ('not_existing'); + assert.strictEqual (OV.Loc ('Test'), 'Test'); + + OV.SetLanguageCode ('hu'); + assert.strictEqual (OV.Loc ('Test'), 'Teszt'); + assert.strictEqual (OV.FLoc ('Test {0}', 'a'), 'Teszt a'); + assert.strictEqual (OV.FLoc ('Test {0} {0}', 'a'), 'Teszt a a'); + assert.strictEqual (OV.FLoc ('Test {0} {0} {1}', 'a', 'b'), 'Teszt a a b'); + + OV.SetLocalizedStrings (null); + OV.SetLanguageCode (null); + }); }); }