Skip to content

Commit

Permalink
Fix(rtl): better rtl support (#1236) (#1381)
Browse files Browse the repository at this point in the history
  • Loading branch information
julianpoy authored Jul 27, 2024
2 parents c9679bb + 4745452 commit c692b0c
Show file tree
Hide file tree
Showing 6 changed files with 65 additions and 10 deletions.
3 changes: 2 additions & 1 deletion packages/frontend/src/app/pages/home/home.page.html
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,9 @@
*ngIf="!preferences[preferenceKeys.ShowImages]"
class="no-image-padding"
></div>
<h2 [title]="recipe.title">{{ recipe.title }}</h2>
<h2 dir="auto" [title]="recipe.title">{{ recipe.title }}</h2>
<p
dir="auto"
*ngIf="recipe.description?.length && preferences[preferenceKeys.ShowRecipeDescription]"
[title]="recipe.description"
>
Expand Down
5 changes: 5 additions & 0 deletions packages/frontend/src/app/pages/home/home.page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import { PreferencesService } from "~/services/preferences.service";
import {
MyRecipesPreferenceKey,
GlobalPreferenceKey,
isRtlText,
} from "@recipesage/util/shared";
import { HomePopoverPage } from "~/pages/home-popover/home-popover.page";
import { HomeSearchFilterPopoverPage } from "~/pages/home-search-popover/home-search-filter-popover.page";
Expand Down Expand Up @@ -498,6 +499,10 @@ export class HomePage {
this.selectedRecipeIds = [];
}

isRtlText(text: string, firstWordOnly = false): boolean {
return isRtlText(text, firstWordOnly);
}

async addLabelToSelectedRecipes() {
const header = await this.translate
.get("pages.home.addLabel.header")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
<img src="{{ sortedRecipeImages()[0].image.location }}" />
</ion-thumbnail>

<ion-label>
<ion-label dir="auto">
<h2 class="recipeTitle ion-text-wrap">{{ recipe.title }}</h2>

<ion-grid
Expand Down Expand Up @@ -91,7 +91,7 @@ <h2 class="recipeTitle ion-text-wrap">{{ recipe.title }}</h2>
</ion-col>
</ion-row>
</ion-grid>
<p class="ion-text-wrap">{{ recipe.description }}</p>
<p dir="auto" class="ion-text-wrap">{{ recipe.description }}</p>
</ion-label>
</ion-item>

Expand Down Expand Up @@ -170,10 +170,11 @@ <h2 class="recipeTitle ion-text-wrap">{{ recipe.title }}</h2>
</ion-label>
</ion-item>
<ion-item class="ingredients ion-text-wrap" lines="none">
<ion-label>
<ion-label dir="auto">
<p
*ngFor="let ingredient of ingredients; index as ingredientIdx"
[innerHTML]="ingredient.content"
dir="auto"
class="ingredient ion-text-wrap"
[ngClass]="{ ingredientContent: !ingredient.isHeader, complete: getIngredientComplete(ingredientIdx) }"
(click)="ingredientClicked($event, ingredient, ingredientIdx)"
Expand All @@ -199,23 +200,26 @@ <h2 class="recipeTitle ion-text-wrap">{{ recipe.title }}</h2>
</ion-label>
</ion-item>
<ion-item class="instructions ion-text-wrap" lines="none">
<ion-label>
<ion-label dir="auto">
<p
*ngFor="let instruction of instructions; index as instructionIdx"
class="instruction ion-text-wrap"
dir="auto"
>
<span *ngIf="instruction.isHeader"
><b class="sectionHeader">{{instruction.content}}</b></span
>
<span *ngIf="instruction.isHeader">
<b class="sectionHeader">{{instruction.content}}</b>
</span>
<span
*ngIf="!instruction.isHeader"
(click)="instructionClicked($event, instruction, instructionIdx)"
[ngClass]="{ complete: getInstructionComplete(instructionIdx) }"
dir="auto"
>
<b>{{instruction.count}} &nbsp;</b>
<span
class="instructionContent"
[innerHTML]="instruction.content"
dir="auto"
></span>
</span>
</p>
Expand All @@ -235,9 +239,10 @@ <h2 class="recipeTitle ion-text-wrap">{{ recipe.title }}</h2>
</ion-label>
</ion-item>
<ion-item lines="none" class="ion-text-wrap">
<ion-label>
<ion-label dir="auto">
<p
*ngFor="let note of notes; index as noteIdx"
dir="auto"
[innerHTML]="note.content"
[ngClass]="{ header: note.isHeader }"
class="ion-text-wrap"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,6 @@ export class RecipePage {
ingredients?: ParsedIngredient[];
instructions?: ParsedInstruction[];
notes?: ParsedNote[];

scale = 1;

labelGroupIds: string[] = [];
Expand Down
3 changes: 3 additions & 0 deletions packages/frontend/src/app/services/recipe.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,18 +49,21 @@ export interface ParsedIngredient {
originalContent: string;
isHeader: boolean;
complete: boolean;
isRtl: boolean;
}

export interface ParsedInstruction {
content: string;
isHeader: boolean;
complete: boolean;
count: number;
isRtl: boolean;
}

export interface ParsedNote {
content: string;
isHeader: boolean;
isRtl: boolean;
}

export enum ExportFormat {
Expand Down
42 changes: 42 additions & 0 deletions packages/util/shared/src/parsers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ export const parseIngredients = (
originalContent: string;
complete: boolean;
isHeader: boolean;
isRtl: boolean;
}[] => {
if (!ingredients) return [];

Expand All @@ -147,6 +148,7 @@ export const parseIngredients = (
originalContent: match,
complete: false,
isHeader: false,
isRtl: isRtlText(match),
})) || [];

for (let i = 0; i < lines.length; i++) {
Expand Down Expand Up @@ -226,8 +228,10 @@ export const parseIngredients = (
acc + ingredientPart + (ingredientPartDelimiters[idx] || ""),
"",
);
lines[i].isRtl = isRtlText(lines[i].originalContent);
} else {
lines[i].content = updatedIngredientParts.join(" + ");
lines[i].isRtl = isRtlText(lines[i].originalContent);
}

lines[i].isHeader = false;
Expand All @@ -244,6 +248,7 @@ export const parseInstructions = (
isHeader: boolean;
count: number;
complete: boolean;
isRtl: boolean;
}[] => {
instructions = replaceFractionsInText(instructions);

Expand All @@ -269,13 +274,15 @@ export const parseInstructions = (
isHeader: true,
count: 0,
complete: false,
isRtl: isRtlText(headerContent, true),
};
} else {
return {
content: line,
isHeader: false,
count: stepCount++,
complete: false,
isRtl: isRtlText(line, true),
};
}
});
Expand All @@ -286,6 +293,7 @@ export const parseNotes = (
): {
content: string;
isHeader: boolean;
isRtl: boolean;
}[] => {
// Starts with [, anything inbetween, ends with ]
const headerRegexp = /^\[.*\]$/;
Expand All @@ -301,12 +309,46 @@ export const parseNotes = (
return {
content: headerContent,
isHeader: true,
isRtl: isRtlText(headerContent),
};
} else {
return {
content: line,
isHeader: false,
isRtl: isRtlText(line),
};
}
});
};

/* eslint-disable no-control-regex */
export const isRtlText = (text: string, onlyFirstWord = true): boolean => {
const rtlChars = new RegExp("[\u0591-\u07FF\uFB1D-\uFDFD\uFE70-\uFEFC]");
const ltrChars = new RegExp(
"[\u0000-\u0590\u2000-\u202E\u202A-\u202E\uFB00-\uFB4F]",
);
const aToZ = new RegExp("[a-zA-Z]");
let rtlCount = 0;
let ltrCount = 0;
if (onlyFirstWord) {
const splits = text.split(" ");
for (let i = 0; i < splits.length; i++) {
if (
rtlChars.test(splits[i].charAt(0)) ||
aToZ.test(splits[i].charAt(0))
) {
text = splits[i];
break;
}
}
}
for (let i = 0; i < text.length; i++) {
if (rtlChars.test(text[i])) {
rtlCount++;
} else if (ltrChars.test(text[i])) {
ltrCount++;
}
}

return rtlCount > ltrCount;
};

0 comments on commit c692b0c

Please sign in to comment.