From f6a1b2173a619b16820ebbef0a488e16c1e9b2d8 Mon Sep 17 00:00:00 2001
From: Andrew Telnov <andrew.telnov@gmail.com>
Date: Mon, 8 Jan 2024 12:35:58 +0200
Subject: [PATCH] default value attribute doesn't work correctly for custom
 localizable property fix #7630

---
 src/base.ts                     |  8 ++++----
 src/jsonobject.ts               |  5 +++--
 src/localizablestring.ts        |  3 ++-
 tests/jsonobjecttests.ts        | 28 ++++++++++++++++++++++++++++
 tests/localizablestringtests.ts | 21 +++++++++++++++++++++
 5 files changed, 58 insertions(+), 7 deletions(-)

diff --git a/src/base.ts b/src/base.ts
index cb08acde96..bdd597e37b 100644
--- a/src/base.ts
+++ b/src/base.ts
@@ -810,10 +810,10 @@ export class Base {
   public unRegisterFunctionOnPropertiesValueChanged(names: Array<string>, key: string = null): void {
     this.unregisterPropertyChangedHandlers(names, key);
   }
-  public createCustomLocalizableObj(name: string) {
-    var locStr = this.getLocalizableString(name);
-    if (locStr) return;
-    this.createLocalizableString(name, <ILocalizableOwner>(<any>this), false, true);
+  public createCustomLocalizableObj(name: string): LocalizableString {
+    const locStr = this.getLocalizableString(name);
+    if(locStr) return locStr;
+    return this.createLocalizableString(name, <ILocalizableOwner>(<any>this), false, true);
   }
   public getLocale(): string {
     const locOwner = this.getSurvey();
diff --git a/src/jsonobject.ts b/src/jsonobject.ts
index d9d4ddbe9a..9f99a940cb 100644
--- a/src/jsonobject.ts
+++ b/src/jsonobject.ts
@@ -574,7 +574,8 @@ export class CustomPropertiesCollection {
       prop.serializationProperty &&
       obj.createCustomLocalizableObj
     ) {
-      obj.createCustomLocalizableObj(prop.name);
+      const locStr = obj.createCustomLocalizableObj(prop.name);
+      locStr.defaultValue = prop.defaultValue;
       var locDesc = {
         get: function () {
           return obj.getLocalizableString(prop.name);
@@ -583,7 +584,7 @@ export class CustomPropertiesCollection {
       Object.defineProperty(obj, prop.serializationProperty, locDesc);
       var desc = {
         get: function () {
-          return obj.getLocalizableStringText(prop.name, prop.defaultValue);
+          return obj.getLocalizableStringText(prop.name);
         },
         set: function (v: any) {
           obj.setLocalizableStringText(prop.name, v);
diff --git a/src/localizablestring.ts b/src/localizablestring.ts
index c9b39ae1d1..f42001d355 100644
--- a/src/localizablestring.ts
+++ b/src/localizablestring.ts
@@ -54,6 +54,7 @@ export class LocalizableString implements ILocalizableString {
   public searchText: string;
   public searchIndex: number;
   public disableLocalization: boolean;
+  public defaultValue: string;
   constructor(
     public owner: ILocalizableOwner,
     public useMarkdown: boolean = false,
@@ -131,7 +132,7 @@ export class LocalizableString implements ILocalizableString {
         res = this.onGetLocalizationTextCallback(res);
       }
     }
-    if (!res) res = "";
+    if (!res) res = this.defaultValue || "";
     return res;
   }
   private getRootDialect(loc: string): string {
diff --git a/tests/jsonobjecttests.ts b/tests/jsonobjecttests.ts
index f4cc78935e..667b8a298a 100644
--- a/tests/jsonobjecttests.ts
+++ b/tests/jsonobjecttests.ts
@@ -22,6 +22,7 @@ import { SurveyModel } from "../src/survey";
 import { CalculatedValue } from "../src/calculatedValue";
 import { QuestionHtmlModel } from "../src/question_html";
 import { ImageItemValue } from "../src/question_imagepicker";
+import { PageModel } from "../src/page";
 
 class Car extends Base implements ILocalizableOwner {
   public locale: string;
@@ -3101,3 +3102,30 @@ QUnit.test("Validated property values", function (assert) {
   assert.equal(survey.jsonErrors[1].message, "The property value: 'edf' is incorrect for property 'textUpdateMode'.", "errors[1].message");
   assert.equal(survey.jsonErrors[1].element.getType(), "text", "errors[1].element");
 });
+QUnit.test("Create localizable property with default value", function (assert) {
+  Serializer.addProperty("question", { name: "customProp:text", isLocalizable: true, default: "Question text" });
+  Serializer.addProperty("page", { name: "customProp:text", isLocalizable: true, default: "Page text" });
+  const question = new Question("q1");
+  const page = new PageModel("page1");
+  assert.equal(question["customProp"], "Question text", "Question prop #1");
+  assert.equal(page["customProp"], "Page text", "Page prop #1");
+  assert.equal(question.getPropertyValue("customProp"), "Question text", "Question getPropertyValue #1");
+  assert.equal(page.getPropertyValue("customProp"), "Page text", "Page getPropertyValue #1");
+
+  question["customProp"] = "Set question val";
+  page["customProp"] = "Set page val";
+  assert.equal(question["customProp"], "Set question val", "Question prop #2");
+  assert.equal(page["customProp"], "Set page val", "Page prop #2");
+  assert.equal(question.getPropertyValue("customProp"), "Set question val", "Question getPropertyValue #2");
+  assert.equal(page.getPropertyValue("customProp"), "Set page val", "Page getPropertyValue #2");
+
+  question.resetPropertyValue("customProp");
+  page.resetPropertyValue("customProp");
+  assert.equal(question["customProp"], "Question text", "Question prop #3");
+  assert.equal(page["customProp"], "Page text", "Page prop #3");
+  assert.equal(question.getPropertyValue("customProp"), "Question text", "Question getPropertyValue #3");
+  assert.equal(page.getPropertyValue("customProp"), "Page text", "Page getPropertyValue #3");
+
+  Serializer.removeProperty("question", "customProp");
+  Serializer.removeProperty("page", "customProp");
+});
diff --git a/tests/localizablestringtests.ts b/tests/localizablestringtests.ts
index 3fa69a0062..4b50f021c9 100644
--- a/tests/localizablestringtests.ts
+++ b/tests/localizablestringtests.ts
@@ -835,3 +835,24 @@ QUnit.test("Fire onStringChanged when localizationName is set", function (assert
   locString.localizationName = "completeText";
   assert.equal(callCount, 1, "onStringChanged is called");
 });
+QUnit.test("Support defaultValue for localizable strings", function (assert) {
+  const owner = new LocalizableOwnerTester("");
+  const locStr1 = new LocalizableString(owner, true);
+  locStr1.defaultValue = "str1";
+  const locStr2 = new LocalizableString(owner, true, "locStr2");
+  locStr2.defaultValue = "str2";
+  const locStr3 = new LocalizableString(owner, true);
+  locStr3.localizationName = "completeText";
+  locStr3.defaultValue = "str3";
+  assert.equal(locStr1.text, "str1", "str1 #1");
+  assert.equal(locStr2.text, "str2", "str2 #1");
+  assert.equal(locStr3.text, "Complete", "str3 #1");
+
+  locStr1.text = "new str1";
+  assert.equal(locStr1.text, "new str1", "str1 #2");
+
+  owner.locale = "de";
+  assert.equal(locStr1.text, "new str1", "str1 #3");
+  assert.equal(locStr2.text, "str2", "str2 #3");
+  assert.equal(locStr3.text, "Abschließen", "str3 #3");
+});