Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions docs/I18N.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Translations

Liner ships in 11 languages: en, ru, uk, es, de, it, fr, pl, tr, pt, id. English is the
Liner ships in 12 languages: en, ru, uk, es, de, it, fr, pl, tr, pt, id, vi. English is the
source and the fallback for every other language.

## How it works
Expand Down Expand Up @@ -41,7 +41,7 @@ When `count` is a number, the translator first looks for a plural form chosen by
| en, de, tr | `_one`, `_other` |
| es, it, fr, pt | `_one`, `_other`, and `_many` (used for round millions) |
| ru, uk, pl | `_one`, `_few`, `_many`, `_other` |
| id | `_other` |
| id, vi | `_other` |

A missing form does not fall back to `_other`: it goes to `<key>_plural` and then the
plain key. Provide every form in the table, or add a `<key>_plural` as a catch-all.
Expand Down
2 changes: 2 additions & 0 deletions src/languages/data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import pl from "./locales/pl.json";
import tr from "./locales/tr.json";
import pt from "./locales/pt.json";
import id from "./locales/id.json";
import vi from "./locales/vi.json";
import type { Locale } from "./locale";

export const translations: Record<Locale, Record<string, unknown>> = {
Expand All @@ -23,4 +24,5 @@ export const translations: Record<Locale, Record<string, unknown>> = {
tr,
pt,
id,
vi,
};
1 change: 1 addition & 0 deletions src/languages/locale.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ describe("getBrowserLocale", () => {
["pt-BR", "pt"],
["pt-PT", "pt"],
["en-GB", "en"],
["vi-VN", "vi"],
])(
"returns the matching locale when navigator.language is %s",
(language, expected) => {
Expand Down
1 change: 1 addition & 0 deletions src/languages/locale.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export const SUPPORTED_LOCALES = [
"tr",
"pt",
"id",
"vi",
] as const;

export type Locale = (typeof SUPPORTED_LOCALES)[number];
Expand Down
1,126 changes: 1,126 additions & 0 deletions src/languages/locales/vi.json

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions src/languages/options.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,4 +59,9 @@ export const LOCALE_OPTIONS: SelectOption<Locale>[] = [
label: "Bahasa Indonesia",
icon: <Emoji name="flag-indonesia" width={16} />,
},
{
value: "vi",
label: "Tiếng Việt",
icon: <Emoji name="flag-vietnam" width={16} />,
},
];
6 changes: 6 additions & 0 deletions src/languages/translator.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,12 @@ describe("createTranslatorSync with plurals", () => {
expect(tUk("common.tracks", { count: 10 })).toBe("10 треків");
});

it("translates correctly in Vietnamese", () => {
const tVi = createTranslatorSync("vi");
expect(tVi("common.sidebar.library")).toBe("Thư viện");
expect(tVi("common.tracks", { count: 3 })).toBe("3 bài hát");
});

it("falls back to English when key is missing in target locale", () => {
const tRu = createTranslatorSync("ru");
expect(tRu("common.app.name")).toBe("Liner");
Expand Down