diff --git a/src/file/paragraph/run/properties.ts b/src/file/paragraph/run/properties.ts
index 19593b62dd..f5ddc4750b 100644
--- a/src/file/paragraph/run/properties.ts
+++ b/src/file/paragraph/run/properties.ts
@@ -2,6 +2,7 @@ import { BorderElement, IBorderOptions } from "@file/border";
import { IShadingAttributesProperties, Shading } from "@file/shading";
import { ChangeAttributes, IChangedAttributesProperties } from "@file/track-revision/track-revision";
import {
+ BuilderElement,
HpsMeasureElement,
IgnoreIfEmptyXmlComponent,
NumberValueElement,
@@ -51,6 +52,16 @@ export interface IRunStylePropertiesOptions {
readonly emboss?: boolean;
readonly imprint?: boolean;
readonly revision?: IRunPropertiesChangeOptions;
+ //
+ //
+ //
+ //
+ //
+ readonly language?: {
+ readonly value?: string;
+ readonly eastAsia?: string;
+ readonly bidirectional?: string;
+ };
readonly border?: IBorderOptions;
readonly vanish?: boolean;
readonly specVanish?: boolean;
@@ -240,6 +251,32 @@ export class RunProperties extends IgnoreIfEmptyXmlComponent {
if (options.scale !== undefined) {
this.push(new NumberValueElement("w:w", options.scale));
}
+
+ if (options.language) {
+ this.push(
+ new BuilderElement<{
+ readonly value: string;
+ readonly eastAsia: string;
+ readonly bidirectional: string;
+ }>({
+ name: "w:lang",
+ attributes: {
+ value: {
+ key: "w:val",
+ value: options.language.value,
+ },
+ eastAsia: {
+ key: "w:eastAsia",
+ value: options.language.eastAsia,
+ },
+ bidirectional: {
+ key: "w:bidi",
+ value: options.language.bidirectional,
+ },
+ },
+ }),
+ );
+ }
}
public push(item: XmlComponent): void {
diff --git a/src/file/paragraph/run/run.spec.ts b/src/file/paragraph/run/run.spec.ts
index b178536435..2a207a7b87 100644
--- a/src/file/paragraph/run/run.spec.ts
+++ b/src/file/paragraph/run/run.spec.ts
@@ -580,5 +580,35 @@ describe("Run", () => {
});
});
});
+
+ describe("#language", () => {
+ it("should correctly set the language", () => {
+ const run = new Run({
+ language: {
+ value: "en-US",
+ eastAsia: "zh-CN",
+ bidirectional: "ar-SA",
+ },
+ });
+ const tree = new Formatter().format(run);
+ expect(tree).to.deep.equal({
+ "w:r": [
+ {
+ "w:rPr": [
+ {
+ "w:lang": {
+ _attr: {
+ "w:val": "en-US",
+ "w:eastAsia": "zh-CN",
+ "w:bidi": "ar-SA",
+ },
+ },
+ },
+ ],
+ },
+ ],
+ });
+ });
+ });
});
});
diff --git a/src/file/xml-components/default-attributes.ts b/src/file/xml-components/default-attributes.ts
index bf84e95eef..c3fb1b8105 100644
--- a/src/file/xml-components/default-attributes.ts
+++ b/src/file/xml-components/default-attributes.ts
@@ -3,14 +3,20 @@ import { IXmlableObject } from "./xmlable-object";
export type AttributeMap = { readonly [P in keyof T]: string };
+export type AttributeData = { readonly [key: string]: boolean | number | string };
+export type AttributePayload = Record<
+ keyof T,
+ {
+ readonly key: string;
+ readonly value?: T[keyof T];
+ }
+>;
+
export abstract class XmlAttributeComponent extends BaseXmlComponent {
- // tslint:disable-next-line:readonly-keyword
- protected readonly root: T;
protected readonly xmlKeys?: AttributeMap;
- public constructor(properties: T) {
+ public constructor(private readonly root: T) {
super("_attr");
- this.root = properties;
}
public prepForXml(_: IContext): IXmlableObject {
@@ -26,3 +32,20 @@ export abstract class XmlAttributeComponent extends BaseXmlCom
return { _attr: attrs };
}
}
+
+export class NextAttributeComponent extends BaseXmlComponent {
+ public constructor(private readonly root: AttributePayload) {
+ super("_attr");
+ }
+
+ public prepForXml(_: IContext): IXmlableObject {
+ const attrs = {};
+ Object.values(this.root).forEach(({ key, value }) => {
+ if (value !== undefined) {
+ // eslint-disable-next-line functional/immutable-data
+ attrs[key] = value;
+ }
+ });
+ return { _attr: attrs };
+ }
+}
diff --git a/src/file/xml-components/simple-elements.ts b/src/file/xml-components/simple-elements.ts
index aca3355c28..b049244746 100644
--- a/src/file/xml-components/simple-elements.ts
+++ b/src/file/xml-components/simple-elements.ts
@@ -1,4 +1,4 @@
-import { Attributes, XmlComponent } from "@file/xml-components";
+import { AttributeData, AttributePayload, Attributes, NextAttributeComponent, XmlComponent } from "@file/xml-components";
import { hpsMeasureValue } from "@util/values";
@@ -70,3 +70,13 @@ export class StringContainer extends XmlComponent {
this.root.push(val);
}
}
+
+export class BuilderElement extends XmlComponent {
+ public constructor(options: { readonly attributes?: AttributePayload; readonly name: string }) {
+ super(options.name);
+
+ if (options.attributes) {
+ this.root.push(new NextAttributeComponent(options.attributes));
+ }
+ }
+}