Skip to content

Commit

Permalink
feat: Add details on translation status (#2139)
Browse files Browse the repository at this point in the history
languages specified in `translatedLocales`
- Updates user language preference beta badge text
- Adds link to translation contribution docs
- Refactors component name

---------

Co-authored-by: SuaYoo <[email protected]>
Co-authored-by: Henry Wilkinson <[email protected]>
Co-authored-by: emma <[email protected]>
  • Loading branch information
4 people authored Nov 12, 2024
1 parent 0fb6571 commit ab9edfa
Show file tree
Hide file tree
Showing 14 changed files with 180 additions and 114 deletions.
2 changes: 1 addition & 1 deletion .github/ISSUE_TEMPLATE/localization-request.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name: Localization Request
description: Request a new language or translation.
title: "[L10N]: "
labels: ["enhancement"]
labels: ["localization"]
body:
- type: textarea
attributes:
Expand Down
2 changes: 2 additions & 0 deletions frontend/docs/docs/develop/localization.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ To add a new language directly through code change:
3. Open a pull request with the changes.
4. Once the pull request is merged, manually refresh the language list in the [Weblate Browsertrix project](https://hosted.weblate.org/projects/browsertrix). Translations are managed entirely through the Weblate interface.

New languages will be available in user preferences only after the app is redeployed.

## Making Strings Localizable

All text should be wrapped in the `msg` helper to make them localizable:
Expand Down
3 changes: 3 additions & 0 deletions frontend/src/assets/icons/flask-fill.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
23 changes: 15 additions & 8 deletions frontend/src/components/beta-badges.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,14 @@ const styles = unsafeCSS(stylesheet);
export class BetaIcon extends TailwindElement {
static styles = styles;
render() {
return html`<sl-tooltip content=${msg("Beta feature")} hoist>
return html`<sl-tooltip hoist>
<sl-icon
name="stars"
name="flask-fill"
library="app"
label="Beta"
class="size-4 text-brand-green"
></sl-icon>
<span slot="content" class="text-xs">${msg("Beta feature")}</span>
</sl-tooltip>`;
}
}
Expand All @@ -34,15 +36,20 @@ export class BetaBadge extends TailwindElement {

render() {
return html`<sl-tooltip hoist placement=${this.placement}>
<div slot="content">
<b>${msg("This part of Browsertrix is in beta!")}</b>
${msg(
"Parts might change or be broken. Please share your thoughts with us!",
)}
<div slot="content" class="text-xs">
<slot name="content">
<b>${msg("This part of Browsertrix is in beta!")}</b>
<p>
${msg(
"Parts might change or be broken. Please share your thoughts with us!",
)}
</p>
</slot>
</div>
<span class="inline-block align-middle text-xs text-brand-green">
<sl-icon
name="stars"
name="flask-fill"
library="app"
label="Beta feature"
class="size-4 align-middle"
></sl-icon
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/ui/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import("./details");
import("./file-list");
import("./inline-input");
import("./language-select");
import("./locale-picker");
import("./user-language-select");
import("./markdown-editor");
import("./markdown-viewer");
import("./menu-item-link");
Expand Down
77 changes: 0 additions & 77 deletions frontend/src/components/ui/locale-picker.ts

This file was deleted.

91 changes: 91 additions & 0 deletions frontend/src/components/ui/user-language-select.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import type { SlSelectEvent } from "@shoelace-style/shoelace";
import { html } from "lit";
import { customElement, state } from "lit/decorators.js";

import { sourceLocale } from "@/__generated__/locale-codes";
import { BtrixElement } from "@/classes/BtrixElement";
import { allLocales, type LocaleCodeEnum } from "@/types/localization";
import { getLocale, setLocale } from "@/utils/localization";
import { AppStateService } from "@/utils/state";

/**
* Select language that Browsertrix app will be shown in
*/
@customElement("btrix-user-language-select")
export class LocalePicker extends BtrixElement {
@state()
private localeNames: { [locale: string]: string } = {};

firstUpdated() {
this.setLocaleNames();
}

private setLocaleNames() {
const localeNames: LocalePicker["localeNames"] = {};

// TODO Add browser-preferred languages
// https://github.com/webrecorder/browsertrix/issues/2143
allLocales.forEach((locale) => {
const name = new Intl.DisplayNames([locale], {
type: "language",
}).of(locale);

if (!name) return;

localeNames[locale] = name;
});

this.localeNames = localeNames;
}

render() {
const selectedLocale =
this.appState.userPreferences?.locale || sourceLocale;

return html`
<sl-dropdown
@sl-select=${this.localeChanged}
placement="top-end"
distance="4"
hoist
>
<sl-button
slot="trigger"
size="small"
caret
?disabled=${(allLocales as unknown as string[]).length < 2}
>
<sl-icon slot="prefix" name="translate"></sl-icon>
<span class="capitalize"
>${this.localeNames[selectedLocale as LocaleCodeEnum]}</span
>
</sl-button>
<sl-menu>
${Object.keys(this.localeNames)
.sort()
.map(
(locale) =>
html`<sl-menu-item
class="capitalize"
type="checkbox"
value=${locale}
?checked=${locale === selectedLocale}
>
${this.localeNames[locale]}
</sl-menu-item>`,
)}
</sl-menu>
</sl-dropdown>
`;
}

async localeChanged(event: SlSelectEvent) {
const newLocale = event.detail.item.value as LocaleCodeEnum;

AppStateService.partialUpdateUserPreferences({ locale: newLocale });

if (newLocale !== getLocale()) {
void setLocale(newLocale);
}
}
}
11 changes: 3 additions & 8 deletions frontend/src/features/crawl-workflows/workflow-list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ import type { ListWorkflow } from "@/types/crawler";
import { humanizeSchedule } from "@/utils/cron";
import { srOnly, truncate } from "@/utils/css";
import { formatNumber, getLocale } from "@/utils/localization";
import { numberFormatter } from "@/utils/number";
import { pluralOf } from "@/utils/pluralize";

const formatNumberCompact = (v: number) =>
Expand Down Expand Up @@ -245,13 +244,9 @@ export class WorkflowListItem extends LitElement {
${this.safeRender((workflow) => {
if (workflow.schedule) {
return msg(
str`${humanizeSchedule(
workflow.schedule,
{
length: "short",
},
numberFormatter,
)}`,
str`${humanizeSchedule(workflow.schedule, {
length: "short",
})}`,
);
}
if (workflow.lastStartedByName) {
Expand Down
12 changes: 8 additions & 4 deletions frontend/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import type { NavigateEventDetail } from "@/controllers/navigate";
import type { NotifyEventDetail } from "@/controllers/notify";
import { theme } from "@/theme";
import { type Auth } from "@/types/auth";
import { type LocaleCodeEnum } from "@/types/localization";
import { translatedLocales, type LocaleCodeEnum } from "@/types/localization";
import { type AppSettings } from "@/utils/app";
import {
getLocale,
Expand Down Expand Up @@ -454,9 +454,13 @@ export class App extends BtrixElement {
</sl-dropdown>`
: html`
${this.renderSignUpLink()}
<btrix-locale-picker
@sl-select=${this.onSelectLocale}
></btrix-locale-picker>
${(translatedLocales as unknown as string[]).length > 1
? html`
<btrix-user-language-select
@sl-select=${this.onSelectLocale}
></btrix-user-language-select>
`
: nothing}
`}
</div>
${isSuperAdmin
Expand Down
43 changes: 35 additions & 8 deletions frontend/src/pages/account-settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ export class AccountSettings extends LiteElement {
</form>
${(allLocales as unknown as string[]).length > 1
? this.renderPreferences()
? this.renderLanguage()
: nothing}
`;
}
Expand Down Expand Up @@ -322,18 +322,45 @@ export class AccountSettings extends LiteElement {
`;
}

private renderPreferences() {
private renderLanguage() {
return html`
<h2 class="mb-2 mt-7 text-lg font-medium">${msg("Preferences")}</h2>
<h2 class="mb-2 mt-7 flex items-center gap-2 text-lg font-medium">
${msg("Language")}
<btrix-beta-badge>
<div slot="content">
<b>${msg("Translations are in beta")}</b>
<p>
${msg(
"Parts of the app may not be translated yet in some languages.",
)}
</p>
</div>
</btrix-beta-badge>
</h2>
<section class="mb-5 rounded-lg border">
<div class="flex items-center justify-between px-4 py-2.5">
<h3 class="font-medium">
${msg("Language")} <btrix-beta-badge></btrix-beta-badge>
<div class="flex items-center justify-between gap-2 px-4 py-2.5">
<h3>
${msg(
"Choose your preferred language for displaying Browsertrix in your browser.",
)}
</h3>
<btrix-locale-picker
<btrix-user-language-select
@sl-select=${this.onSelectLocale}
></btrix-locale-picker>
></btrix-user-language-select>
</div>
<footer class="flex items-center justify-start border-t px-4 py-3">
<p class="text-neutral-600">
${msg("Help us translate Browsertrix.")}
<a
class="inline-flex items-center gap-1 text-blue-500 hover:text-blue-600"
href="https://docs.browsertrix.com/develop/localization/"
target="_blank"
>
${msg("Contribute to translations")}
<sl-icon slot="suffix" name="arrow-right"></sl-icon
></a>
</p>
</footer>
</section>
`;
}
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/pages/org/settings/components/billing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,7 @@ export class OrgSettingsBilling extends BtrixElement {
quotas.maxExecMinutesPerMonth &&
humanizeSeconds(
quotas.maxExecMinutesPerMonth * 60,
undefined,
getLocale(),
undefined,
"long",
);
Expand Down
3 changes: 3 additions & 0 deletions frontend/src/types/localization.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,8 @@ import { z } from "zod";
import { allLocales } from "@/__generated__/locale-codes";

export { allLocales };
// Translated languages to show in app:
export const translatedLocales = ["en"] as const;

export const localeCodeEnum = z.enum(allLocales);
export type LocaleCodeEnum = z.infer<typeof localeCodeEnum>;
3 changes: 1 addition & 2 deletions frontend/src/utils/cron.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@ export function humanizeNextDate(
export function humanizeSchedule(
schedule: string,
options: { length?: "short" } = {},
numberFormatter = numberUtils.numberFormatter,
): string {
const interval = getScheduleInterval(schedule);
const parsed = parseCron(schedule);
Expand Down Expand Up @@ -92,7 +91,7 @@ export function humanizeSchedule(
intervalMsg = msg(str`Every ${formattedWeekDay}`);
break;
case "monthly": {
const { format } = numberFormatter(getLocale());
const { format } = numberUtils.numberFormatter(getLocale());
intervalMsg = msg(
str`Monthly on the ${format(days[0], { ordinal: true })}`,
);
Expand Down
Loading

0 comments on commit ab9edfa

Please sign in to comment.