Split translations between EW and shared components (#31441)

* Split translations between EW and shared components

Uses update module API with global TranslationKey type that can be
overridden.

WIP.

* Removed the wrong script (for now)

* Add the type files

* Add shared components i18n file

* More i18n strings

* Add i18n check for shared conmponents

* Needs a different name

* rerun i18n for merge from develop, fix test

* Move translated strings to shared components file

NB. there are lots of removed strings for a few languages where we
seem to have hit a localazy bug or something where the key/value
for plurals got switched, making the translations invalid. They've
been missing for a while so I'm removing them rather than trying to
restore them,

* Add shared components files to localazy

* Merge element web & shared component translations

for the built app

* Use right translations for shared component tests

and fix missign en_EN strings

* Pull shared components translations too

* Fix/disable warnings

* We can now remove the build:res call

...right? (right?)

* Remove webpack import for languages index

..and just load it using a relative path which we do for the individual
language files and also did anyway for the index because even in non-test
it was an object, not a string, so we always usesd the 'test' code path.

* Make the storybook language selector work

...without referring to the parent app's files

* Revert unnecessary yarn lock change

* Typo

Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>

* Add comment on why we use merge

* Fix localazy download config

to actually put the translations in the right place

* Better typescript syntax

Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>

* Watch both translations files

---------

Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
This commit is contained in:
David Baker
2026-01-07 11:49:01 +00:00
committed by GitHub
co-authored by Michael Telatynski
parent 4ee04d0661
commit 13696af194
131 changed files with 1783 additions and 1763 deletions
@@ -10,16 +10,14 @@ import { WithTooltip, IconButton, TooltipLinkList } from "storybook/internal/com
import React from "react";
import { GlobeIcon } from "@storybook/icons";
// We can't import `shared/i18n.tsx` directly here.
// The storybook addon doesn't seem to benefit the vite config of storybook and we can't resolve the alias in i18n.tsx.
import json from "../../../webapp/i18n/languages.json";
const languages = Object.keys(json).filter((lang) => lang !== "default");
const languages = JSON.parse(process.env.STORYBOOK_LANGUAGES);
/**
* Returns the title of a language in the user's locale.
*/
function languageTitle(language: string): string {
return new Intl.DisplayNames([language], { type: "language", style: "short" }).of(language) || language;
const normalisedLang = language.toLowerCase().replace("_", "-");
return new Intl.DisplayNames([normalisedLang], { type: "language", style: "short" }).of(normalisedLang) || language;
}
export const languageAddon: Addon = {
+44 -3
View File
@@ -7,12 +7,15 @@ Please see LICENSE files in the repository root for full details.
import type { StorybookConfig } from "@storybook/react-vite";
import path from "node:path";
import fs from "node:fs";
import { nodePolyfills } from "vite-plugin-node-polyfills";
import { mergeConfig } from "vite";
// Get a list of available languages so the language selector can display them at runtime
const languages = fs.readdirSync("src/i18n/strings").map((f) => f.slice(0, -5));
const config: StorybookConfig = {
stories: ["../src/**/*.stories.@(js|jsx|mjs|ts|tsx)"],
staticDirs: ["../../../webapp"],
addons: ["@storybook/addon-docs", "@storybook/addon-designs", "@storybook/addon-a11y"],
framework: "@storybook/react-vite",
core: {
@@ -29,8 +32,42 @@ const config: StorybookConfig = {
$webapp: path.resolve("../../webapp"),
},
},
// Needed for counterpart to work
plugins: [nodePolyfills({ include: ["process", "util"] })],
plugins: [
// Needed for counterpart to work
nodePolyfills({ include: ["process", "util"] }),
{
name: "language-middleware",
configureServer(server) {
server.middlewares.use((req, res, next) => {
if (req.url === "/i18n/languages.json") {
// Dynamically generate a languages.json file based on what files are available
const langJson: Record<string, string> = {};
for (const lang of languages) {
const normalizedLanguage = lang.toLowerCase().replace("_", "-");
const languageParts = normalizedLanguage.split("-");
if (languageParts.length === 2 && languageParts[0] === languageParts[1]) {
langJson[languageParts[0]] = `${lang}.json`;
} else {
langJson[normalizedLanguage] = `${lang}.json`;
}
}
res.setHeader("Content-Type", "application/json");
res.end(JSON.stringify(langJson));
} else if (req.url?.startsWith("/i18n/")) {
// Serve the individual language files, which annoyingly can't be a simple
// static dir because the directory structure in src doesn't match what
// the app requests.
const langFile = req.url.split("/").pop();
res.setHeader("Content-Type", "application/json");
fs.createReadStream(`src/i18n/strings/${langFile}`).pipe(res);
} else {
next();
}
});
},
},
],
server: {
allowedHosts: ["localhost", ".docker.internal"],
},
@@ -42,5 +79,9 @@ const config: StorybookConfig = {
url: "https://element-hq.github.io/compound-web/",
},
},
env: (config) => ({
...config,
STORYBOOK_LANGUAGES: JSON.stringify(languages),
}),
};
export default config;
+4 -1
View File
@@ -34,8 +34,11 @@
"package.json"
],
"scripts": {
"i18n": "matrix-gen-i18n src && yarn i18n:sort && yarn i18n:lint",
"i18n:sort": "jq --sort-keys '.' src/i18n/strings/en_EN.json > src/i18n/strings/en_EN.json.tmp && mv src/i18n/strings/en_EN.json.tmp src/i18n/strings/en_EN.json",
"i18n:lint": "matrix-i18n-lint && prettier --log-level=silent --write src/i18n/strings/ --ignore-path /dev/null",
"test": "jest",
"prepare": "patch-package && yarn --cwd ../.. build:res && node scripts/gatherTranslationKeys.ts && vite build",
"prepare": "patch-package && vite build",
"storybook": "storybook dev -p 6007",
"build-storybook": "storybook build",
"lint": "yarn lint:types && yarn lint:js",
@@ -1,67 +0,0 @@
/*
Copyright 2025 Element Creations Ltd.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
Please see LICENSE files in the repository root for full details.
*/
// Gathers all the translation keys from element-web's en_EN.json into a TypeScript type definition file
// that exports a type `TranslationKey` which is a union of all supported translation keys.
// This prevents having to import the json file and make typescript do the work as this results in vite-dts
// generating an import to the json file in the .d.ts which doesn't work at runtime: this way, the type
// gets put into the bundle.
// XXX: It should *not* be in the 'src' directory, being a generated file, but if it isn't then the type
// bundler won't bundle the types and will leave the file as a relative import, which will break.
import * as fs from "fs";
import * as path from "path";
import { dirname } from "node:path";
import { fileURLToPath } from "node:url";
const __dirname = dirname(fileURLToPath(import.meta.url));
const i18nStringsPath = path.resolve(__dirname, "../../../src/i18n/strings/en_EN.json");
const outPath = path.resolve(__dirname, "../src/i18nKeys.d.ts");
function gatherKeys(obj: any, prefix: string[] = []): string[] {
if (typeof obj !== "object" || obj === null) return [];
let keys: string[] = [];
for (const key of Object.keys(obj)) {
const value = obj[key];
// add the path (for both leaves and intermediates as then we include plurals)
keys.push([...prefix, key].join("|"));
if (typeof value === "object" && value !== null) {
// If the value is an object, recurse
keys = keys.concat(gatherKeys(value, [...prefix, key]));
}
}
return keys;
}
function main() {
const json = JSON.parse(fs.readFileSync(i18nStringsPath, "utf8"));
const keys = gatherKeys(json);
const typeDef =
"/*\n" +
" * Copyright 2025 Element Creations Ltd.\n" +
" *\n" +
" * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial\n" +
" * Please see LICENSE files in the repository root for full details.\n" +
" */\n" +
"\n" +
"// This file is auto-generated by gatherTranslationKeys.ts\n" +
"// Do not edit manually.\n\n" +
"export type TranslationKey =\n" +
keys.map((k) => ` | \"${k}\"`).join("\n") +
";\n";
fs.mkdirSync(path.dirname(outPath), { recursive: true });
fs.writeFileSync(outPath, typeDef, "utf8");
console.log(`Wrote ${keys.length} keys to ${outPath}`);
}
if (import.meta.url.startsWith("file:")) {
const modulePath = fileURLToPath(import.meta.url);
if (process.argv[1] === modulePath) {
main();
}
}
+14
View File
@@ -0,0 +1,14 @@
/*
Copyright 2025 Element Creations Ltd.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
Please see LICENSE files in the repository root for full details.
*/
import { type TranslationKey as _TranslationKey } from "matrix-web-i18n";
import type Translations from "../i18n/strings/en_EN.json";
declare global {
type TranslationKey = _TranslationKey<typeof Translations>;
}
@@ -0,0 +1,43 @@
{
"a11y": {
"seek_bar_label": "Panel posunu zvuku"
},
"action": {
"delete": "Smazat",
"dismiss": "Zavřít",
"explore_rooms": "Procházet místnosti",
"pause": "Pozastavit",
"play": "Přehrát",
"search": "Hledání"
},
"encryption": {
"pinned_identity_changed": "Identita %(displayName)s (<b>%(userId)s</b>) se změnila. <a>Další informace</a>",
"withdraw_verification_action": "Zrušit ověření"
},
"left_panel": {
"open_dial_pad": "Otevřít číselník"
},
"time": {
"about_day_ago": "před jedním dnem",
"about_hour_ago": "asi před hodinou",
"about_minute_ago": "před minutou",
"few_seconds_ago": "před pár vteřinami",
"in_about_day": "asi za den",
"in_about_hour": "asi za hodinu",
"in_about_minute": "asi za minutu",
"in_few_seconds": "za pár vteřin",
"in_n_days": "za %(num)s dní",
"in_n_hours": "za %(num)s hodin",
"in_n_minutes": "za %(num)s minut",
"n_days_ago": "před %(num)s dny",
"n_hours_ago": "před %(num)s hodinami",
"n_minutes_ago": "před %(num)s minutami"
},
"timeline": {
"m.audio": {
"audio_player": "Audio přehrávač",
"error_downloading_audio": "Chyba při stahování audia",
"unnamed_audio": "Nepojmenovaný audio soubor"
}
}
}
@@ -0,0 +1,43 @@
{
"a11y": {
"seek_bar_label": "Bar chwilio sain"
},
"action": {
"delete": "Dileu",
"dismiss": "Gwrthod",
"explore_rooms": "Archwilio Ystafelloedd",
"pause": "Oedi",
"play": "Chwarae",
"search": "Chwilio"
},
"encryption": {
"pinned_identity_changed": "Cafodd hunaniaeth (<b>%(userId)s</b>) %(displayName)s ei ailosod. <a>Dysgu rhagor</a>",
"withdraw_verification_action": "Tynnu'r dilysiad yn ôl"
},
"left_panel": {
"open_dial_pad": "Agor y pad deialu"
},
"time": {
"about_day_ago": "tua diwrnod yn ôl",
"about_hour_ago": "tua awr yn ol",
"about_minute_ago": "tua munud yn ôl",
"few_seconds_ago": "ychydig eiliadau yn ôl",
"in_about_day": "tua diwrnod o nawr",
"in_about_hour": "tuag awr o hyn",
"in_about_minute": "tua munud o nawr",
"in_few_seconds": "ychydig eiliadau o nawr",
"in_n_days": "%(num)s diwrnod o nawr",
"in_n_hours": "%(num)s awr o nawr",
"in_n_minutes": "%(num)s munud o nawr",
"n_days_ago": "%(num)s diwrnod yn ôl",
"n_hours_ago": "%(num)s awr yn ôl",
"n_minutes_ago": "%(num)s munud yn ôl"
},
"timeline": {
"m.audio": {
"audio_player": "Chwaraewr sain",
"error_downloading_audio": "Gwall wrth llwytho i lawrsain",
"unnamed_audio": "Sain dienw"
}
}
}
@@ -0,0 +1,35 @@
{
"a11y": {
"seek_bar_label": "Progressionsmarkør for lydafspiller"
},
"action": {
"delete": "Slet",
"dismiss": "Afvis",
"explore_rooms": "Udforsk rum",
"pause": "Pausér",
"play": "Afspil",
"search": "Søg"
},
"time": {
"about_day_ago": "omkring en dag siden",
"about_hour_ago": "for omkring en time siden",
"about_minute_ago": "for omkring et minut siden",
"few_seconds_ago": "for et par sekunder siden",
"in_about_day": "om cirka en dag fra nu",
"in_about_hour": "omkring en time fra nu",
"in_about_minute": "omkring et minut fra nu",
"in_few_seconds": "et par sekunder fra nu",
"in_n_days": "%(num)s dage fra nu",
"in_n_hours": "%(num)s timer fra nu",
"in_n_minutes": "%(num)s minutter fra nu",
"n_days_ago": "%(num)s dage siden",
"n_hours_ago": "%(num)s timer siden",
"n_minutes_ago": "%(num)s minutter siden"
},
"timeline": {
"m.audio": {
"error_downloading_audio": "Fejl ved download af lyd",
"unnamed_audio": "Unavngiven lyd"
}
}
}
@@ -0,0 +1,43 @@
{
"a11y": {
"seek_bar_label": "Audio-Suchleiste"
},
"action": {
"delete": "Löschen",
"dismiss": "Ausblenden",
"explore_rooms": "Chats erkunden",
"pause": "Pausieren",
"play": "Abspielen",
"search": "Suchen"
},
"encryption": {
"pinned_identity_changed": "%(displayName)s's (<b>%(userId)s</b>) Identität wurde zurückgesetzt. <a>Mehr erfahren </a>",
"withdraw_verification_action": "Verifizierung zurückziehen"
},
"left_panel": {
"open_dial_pad": "Wähltastatur öffnen"
},
"time": {
"about_day_ago": "vor etwa einem Tag",
"about_hour_ago": "vor etwa einer Stunde",
"about_minute_ago": "vor etwa einer Minute",
"few_seconds_ago": "vor ein paar Sekunden",
"in_about_day": "in etwa einem Tag",
"in_about_hour": "in etwa einer Stunde",
"in_about_minute": "in etwa einer Minute",
"in_few_seconds": "in ein paar Sekunden",
"in_n_days": "in %(num)s Tagen",
"in_n_hours": "in %(num)s Stunden",
"in_n_minutes": "In etwa %(num)s Minuten",
"n_days_ago": "vor %(num)s Tagen",
"n_hours_ago": "vor %(num)s Stunden",
"n_minutes_ago": "vor %(num)s Minuten"
},
"timeline": {
"m.audio": {
"audio_player": "Audio-Player",
"error_downloading_audio": "Fehler beim Herunterladen der Audiodatei",
"unnamed_audio": "Unbenannte Audiodatei"
}
}
}
@@ -0,0 +1,35 @@
{
"action": {
"delete": "Διαγραφή",
"dismiss": "Απόρριψη",
"explore_rooms": "Εξερευνήστε αίθουσες",
"pause": "Παύση",
"play": "Αναπαραγωγή",
"search": "Αναζήτηση"
},
"left_panel": {
"open_dial_pad": "Άνοιγμα πληκτρολογίου κλήσης"
},
"time": {
"about_day_ago": "σχεδόν μία μέρα πριν",
"about_hour_ago": "σχεδόν μία ώρα πριν",
"about_minute_ago": "σχεδόν ένα λεπτό πριν",
"few_seconds_ago": "λίγα δευτερόλεπτα πριν",
"in_about_day": "περίπου μια μέρα από τώρα",
"in_about_hour": "περίπου μία ώρα από τώρα",
"in_about_minute": "περίπου ένα λεπτό από τώρα",
"in_few_seconds": "λίγα δευτερόλεπτα από τώρα",
"in_n_days": "%(num)s μέρες από τώρα",
"in_n_hours": "%(num)s ώρες από τώρα",
"in_n_minutes": "%(num)s λεπτά από τώρα",
"n_days_ago": "%(num)s μέρες πριν",
"n_hours_ago": "%(num)s ώρες πριν",
"n_minutes_ago": "%(num)s λεπτά πριν"
},
"timeline": {
"m.audio": {
"error_downloading_audio": "Σφάλμα λήψης ήχου",
"unnamed_audio": "Ήχος χωρίς όνομα"
}
}
}
@@ -0,0 +1,48 @@
{
"a11y": {
"seek_bar_label": "Audio seek bar"
},
"action": {
"delete": "Delete",
"dismiss": "Dismiss",
"explore_rooms": "Explore rooms",
"pause": "Pause",
"play": "Play",
"search": "Search"
},
"encryption": {
"pinned_identity_changed": "%(displayName)s's (<b>%(userId)s</b>) identity was reset. <a>Learn more</a>",
"withdraw_verification_action": "Withdraw verification"
},
"left_panel": {
"open_dial_pad": "Open dial pad"
},
"room": {
"status_bar": {
"history_visible": "This room has been configured so that new members can read history. <a>Learn More</a>"
}
},
"time": {
"about_day_ago": "about a day ago",
"about_hour_ago": "about an hour ago",
"about_minute_ago": "about a minute ago",
"few_seconds_ago": "a few seconds ago",
"in_about_day": "about a day from now",
"in_about_hour": "about an hour from now",
"in_about_minute": "about a minute from now",
"in_few_seconds": "a few seconds from now",
"in_n_days": "%(num)s days from now",
"in_n_hours": "%(num)s hours from now",
"in_n_minutes": "%(num)s minutes from now",
"n_days_ago": "%(num)s days ago",
"n_hours_ago": "%(num)s hours ago",
"n_minutes_ago": "%(num)s minutes ago"
},
"timeline": {
"m.audio": {
"audio_player": "Audio player",
"error_downloading_audio": "Error downloading audio",
"unnamed_audio": "Unnamed audio"
}
}
}
@@ -0,0 +1,35 @@
{
"action": {
"delete": "Forigi",
"dismiss": "Rezigni",
"explore_rooms": "Esplori ĉambrojn",
"pause": "Paŭzigi",
"play": "Ludi",
"search": "Serĉi"
},
"left_panel": {
"open_dial_pad": "Malfermi ciferplaton"
},
"time": {
"about_day_ago": "antaŭ ĉirkaŭ tago",
"about_hour_ago": "antaŭ ĉirkaŭ horo",
"about_minute_ago": "antaŭ ĉirkaŭ minuto",
"few_seconds_ago": "antaŭ kelkaj sekundoj",
"in_about_day": "ĉirkaŭ tagon de nun",
"in_about_hour": "ĉirkaŭ horon de nun",
"in_about_minute": "ĉirkaŭ minuton de nun",
"in_few_seconds": "kelkajn sekundojn de nun",
"in_n_days": "%(num)s tagojn de nun",
"in_n_hours": "%(num)s horojn de nun",
"in_n_minutes": "%(num)s minutojn de nun",
"n_days_ago": "antaŭ %(num)s tagoj",
"n_hours_ago": "antaŭ %(num)s horoj",
"n_minutes_ago": "antaŭ %(num)s minutoj"
},
"timeline": {
"m.audio": {
"error_downloading_audio": "Eraris elŝuto de sondosiero",
"unnamed_audio": "Sennoma sondosiero"
}
}
}
@@ -0,0 +1,39 @@
{
"a11y": {
"seek_bar_label": "Barra de búsqueda de audio"
},
"action": {
"delete": "Borrar",
"dismiss": "Omitir",
"explore_rooms": "Explorar salas",
"pause": "Pausar",
"play": "Reproducir",
"search": "Buscar"
},
"left_panel": {
"open_dial_pad": "Abrir teclado numérico"
},
"time": {
"about_day_ago": "hace aprox. un día",
"about_hour_ago": "hace aprox. una hora",
"about_minute_ago": "hace aproximadamente un minuto",
"few_seconds_ago": "hace unos segundos",
"in_about_day": "dentro de un día",
"in_about_hour": "dentro de una hora",
"in_about_minute": "dentro de un minuto",
"in_few_seconds": "dentro de unos segundos",
"in_n_days": "dentro de %(num)s días",
"in_n_hours": "dentro de %(num)s horas",
"in_n_minutes": "dentro de %(num)s minutos",
"n_days_ago": "hace %(num)s días",
"n_hours_ago": "hace %(num)s horas",
"n_minutes_ago": "hace %(num)s minutos"
},
"timeline": {
"m.audio": {
"audio_player": "Reproductor de audio",
"error_downloading_audio": "Error al descargar el audio",
"unnamed_audio": "Audio sin título"
}
}
}
@@ -0,0 +1,48 @@
{
"a11y": {
"seek_bar_label": "Heli kerimisriba"
},
"action": {
"delete": "Kustuta",
"dismiss": "Loobu",
"explore_rooms": "Tutvu jututubadega",
"pause": "Peata",
"play": "Esita",
"search": "Otsing"
},
"encryption": {
"pinned_identity_changed": "Kasutaja %(displayName)s (<b>%(userId)s</b>) võrguidentiteet on lähtestatud. <a>Lisateave</a>",
"withdraw_verification_action": "Eemalda verifitseerimine"
},
"left_panel": {
"open_dial_pad": "Ava numbriklahvistik"
},
"room": {
"status_bar": {
"history_visible": "See jututuba on seadistatud sel viisil, et uued liikmed saavad lugeda varasemat ajalugu.<a> Lisateave</a>"
}
},
"time": {
"about_day_ago": "umbes päev tagasi",
"about_hour_ago": "umbes tund aega tagasi",
"about_minute_ago": "umbes minut tagasi",
"few_seconds_ago": "mõni sekund tagasi",
"in_about_day": "umbes päeva pärast",
"in_about_hour": "umbes tunni pärast",
"in_about_minute": "umbes minuti pärast",
"in_few_seconds": "mõne sekundi pärast",
"in_n_days": "%(num)s päeva pärast",
"in_n_hours": "%(num)s tunni pärast",
"in_n_minutes": "%(num)s minuti pärast",
"n_days_ago": "%(num)s päeva tagasi",
"n_hours_ago": "%(num)s tundi tagasi",
"n_minutes_ago": "%(num)s minutit tagasi"
},
"timeline": {
"m.audio": {
"audio_player": "Meediaesitaja",
"error_downloading_audio": "Helifaili allalaadimine ei õnnestunud",
"unnamed_audio": "Nimetu helifail"
}
}
}
@@ -0,0 +1,29 @@
{
"action": {
"delete": "پاک‌کردن",
"dismiss": "نادیده بگیر",
"explore_rooms": "جستجو در اتاق ها",
"pause": "متوقف‌کردن",
"play": "اجرا کردن",
"search": "جستجو"
},
"left_panel": {
"open_dial_pad": "باز کردن صفحه شماره‌گیری"
},
"time": {
"about_day_ago": "حدود یک روز قبل",
"about_hour_ago": "حدود یک ساعت قبل",
"about_minute_ago": "حدود یک دقیقه قبل",
"few_seconds_ago": "چند ثانیه قبل",
"in_about_day": "حدود یک روز دیگر",
"in_about_hour": "حدود یک ساعت دیگر",
"in_about_minute": "حدود یک دقیقه دیگر",
"in_few_seconds": "چند ثانیه دیگر",
"in_n_days": "%(num)s روز دیگر",
"in_n_hours": "%(num)s ساعت دیگر",
"in_n_minutes": "%(num)s دقیقه دیگر",
"n_days_ago": "%(num)s روز قبل",
"n_hours_ago": "%(num)s ساعت قبل",
"n_minutes_ago": "%(num)s دقیقه قبل"
}
}
@@ -0,0 +1,38 @@
{
"a11y": {
"seek_bar_label": "Äänen siirtymispalkki"
},
"action": {
"delete": "Poista",
"dismiss": "Hylkää",
"explore_rooms": "Selaa huoneita",
"pause": "Keskeytä",
"play": "Toista",
"search": "Haku"
},
"left_panel": {
"open_dial_pad": "Avaa näppäimistö"
},
"time": {
"about_day_ago": "noin päivä sitten",
"about_hour_ago": "noin tunti sitten",
"about_minute_ago": "noin minuutti sitten",
"few_seconds_ago": "muutama sekunti sitten",
"in_about_day": "noin päivä sitten",
"in_about_hour": "noin tunti sitten",
"in_about_minute": "noin minuutti sitten",
"in_few_seconds": "muutama sekunti sitten",
"in_n_days": "%(num)s päivää sitten",
"in_n_hours": "%(num)s tuntia sitten",
"in_n_minutes": "%(num)s minuuttia sitten",
"n_days_ago": "%(num)s päivää sitten",
"n_hours_ago": "%(num)s tuntia sitten",
"n_minutes_ago": "%(num)s minuuttia sitten"
},
"timeline": {
"m.audio": {
"error_downloading_audio": "Virhe ääntä ladattaessa",
"unnamed_audio": "Nimetön ääni"
}
}
}
@@ -0,0 +1,48 @@
{
"a11y": {
"seek_bar_label": "Barre de recherche audio"
},
"action": {
"delete": "Supprimer",
"dismiss": "Ignorer",
"explore_rooms": "Parcourir les salons",
"pause": "Pause",
"play": "Lecture",
"search": "Rechercher"
},
"encryption": {
"pinned_identity_changed": "L'identité de %(displayName)s (<b>%(userId)s</b>) semble avoir changé. <a>En savoir plus</a>",
"withdraw_verification_action": "Révoquer la vérification"
},
"left_panel": {
"open_dial_pad": "Ouvrir le pavé de numérotation"
},
"room": {
"status_bar": {
"history_visible": "Ce salon a été configuré afin que les nouveaux membres puissent lire l'historique.<a> En savori plus</a>"
}
},
"time": {
"about_day_ago": "il y a environ un jour",
"about_hour_ago": "il y a environ une heure",
"about_minute_ago": "il y a environ une minute",
"few_seconds_ago": "il y a quelques secondes",
"in_about_day": "dans un jour environ",
"in_about_hour": "dans une heure environ",
"in_about_minute": "dans une minute environ",
"in_few_seconds": "dans quelques secondes",
"in_n_days": "dans %(num)s jours",
"in_n_hours": "dans %(num)s heures",
"in_n_minutes": "dans %(num)s minutes",
"n_days_ago": "il y a %(num)s jours",
"n_hours_ago": "il y a %(num)s heures",
"n_minutes_ago": "il y a %(num)s minutes"
},
"timeline": {
"m.audio": {
"audio_player": "Lecteur audio",
"error_downloading_audio": "Erreur lors du téléchargement de laudio",
"unnamed_audio": "Audio sans nom"
}
}
}
@@ -0,0 +1,35 @@
{
"action": {
"delete": "Eliminar",
"dismiss": "Rexeitar",
"explore_rooms": "Explorar salas",
"pause": "Deter",
"play": "Reproducir",
"search": "Busca"
},
"left_panel": {
"open_dial_pad": "Abrir marcador"
},
"time": {
"about_day_ago": "onte",
"about_hour_ago": "fai unha hora",
"about_minute_ago": "fai un minuto",
"few_seconds_ago": "fai uns segundos",
"in_about_day": "foi onte",
"in_about_hour": "fará unha hora",
"in_about_minute": "haberá un minuto",
"in_few_seconds": "hai só uns segundos",
"in_n_days": "fará %(num)s días",
"in_n_hours": "fará %(num)s horas",
"in_n_minutes": "fará %(num)s minutos",
"n_days_ago": "fai %(num)s días",
"n_hours_ago": "fai %(num)s horas",
"n_minutes_ago": "fai %(num)s minutos"
},
"timeline": {
"m.audio": {
"error_downloading_audio": "Erro ao descargar o audio",
"unnamed_audio": "Audio sen nome"
}
}
}
@@ -0,0 +1,27 @@
{
"action": {
"delete": "מחק",
"dismiss": "התעלם",
"explore_rooms": "גלה חדרים",
"search": "חפש"
},
"left_panel": {
"open_dial_pad": "פתח לוח חיוג"
},
"time": {
"about_day_ago": "בערך לפני יום",
"about_hour_ago": "בערך לפני כשעה",
"about_minute_ago": "לפני בערך דקה",
"few_seconds_ago": "לפני מספר שניות",
"in_about_day": "בערך בעוד יום מעכשיו",
"in_about_hour": "בערך בעוד כשעה",
"in_about_minute": "בערך עוד דקה אחת",
"in_few_seconds": "בעוד מספר שניות מעכשיו",
"in_n_days": "בעוד %(num)s ימים מעכשיו",
"in_n_hours": "בעוד %(num)s שעות",
"in_n_minutes": "בעוד %(num)s דקות",
"n_days_ago": "לפני %(num)s ימים",
"n_hours_ago": "לפני %(num)s שעות",
"n_minutes_ago": "לפני %(num)s דקות"
}
}
@@ -0,0 +1,43 @@
{
"a11y": {
"seek_bar_label": "Hang keresősávja"
},
"action": {
"delete": "Törlés",
"dismiss": "Eltüntetés",
"explore_rooms": "Szobák felderítése",
"pause": "Szünet",
"play": "Lejátszás",
"search": "Keresés"
},
"encryption": {
"pinned_identity_changed": "Úgy tűnik, hogy %(displayName)s (<b>%(userId)s</b>) személyazonossága megváltozott. <a>További információ</a>",
"withdraw_verification_action": "Ellenőrzés visszavonása"
},
"left_panel": {
"open_dial_pad": "Számlap megnyitása"
},
"time": {
"about_day_ago": "egy napja",
"about_hour_ago": "egy órája",
"about_minute_ago": "egy perce",
"few_seconds_ago": "néhány másodperce",
"in_about_day": "egy nap múlva",
"in_about_hour": "egy óra múlva",
"in_about_minute": "egy perc múlva",
"in_few_seconds": "másodpercek múlva",
"in_n_days": "%(num)s nap múlva",
"in_n_hours": "%(num)s óra múlva",
"in_n_minutes": "%(num)s perc múlva",
"n_days_ago": "%(num)s nappal ezelőtt",
"n_hours_ago": "%(num)s órával ezelőtt",
"n_minutes_ago": "%(num)s perccel ezelőtt"
},
"timeline": {
"m.audio": {
"audio_player": "Hanglejátszó",
"error_downloading_audio": "Hiba a hang letöltésekor",
"unnamed_audio": "Névtelen hang"
}
}
}
@@ -0,0 +1,43 @@
{
"a11y": {
"seek_bar_label": "Աուդիո որոնման գոտի"
},
"action": {
"delete": "Ջնջել",
"dismiss": "Հեռացնել",
"explore_rooms": "Փնտրել սենյակներ",
"pause": "Դադար",
"play": "Միացնել",
"search": "Որոնել"
},
"encryption": {
"pinned_identity_changed": "%(displayName)s-ի (<b>%(userId)s</b> ) ինքնությունը վերակայվել է։ <a> Իմանալ ավելին</a>",
"withdraw_verification_action": "Հետ կանչել հաստատումը"
},
"left_panel": {
"open_dial_pad": "Բացեք թվերի հավաքման վահանակը"
},
"time": {
"about_day_ago": "մոտ մեկ օր առաջ",
"about_hour_ago": "մոտ մեկ ժամ առաջ",
"about_minute_ago": "մոտ մեկ րոպե առաջ",
"few_seconds_ago": "մի քանի վայրկյան առաջ",
"in_about_day": "մոտ մեկ օր անց",
"in_about_hour": "մոտ մեկ ժամ անց",
"in_about_minute": "մոտ մեկ րոպե անց",
"in_few_seconds": "մի քանի վայրկյան անց",
"in_n_days": "%(num)s օր անց",
"in_n_hours": "%(num)s ժամ անց",
"in_n_minutes": "%(num)s րոպեներ անց",
"n_days_ago": "%(num)s օր առաջ",
"n_hours_ago": "%(num)s ժամ առաջ",
"n_minutes_ago": "%(num)s րոպե առաջ"
},
"timeline": {
"m.audio": {
"audio_player": "Աուդիո նվագարկիչ",
"error_downloading_audio": "Աուդիո ներբեռնման սխալ",
"unnamed_audio": "Անանուն աուդիո"
}
}
}
@@ -0,0 +1,43 @@
{
"a11y": {
"seek_bar_label": "Bilah pencarian audio"
},
"action": {
"delete": "Hapus",
"dismiss": "Abaikan",
"explore_rooms": "Jelajahi ruangan",
"pause": "Jeda",
"play": "Mainkan",
"search": "Cari"
},
"encryption": {
"pinned_identity_changed": "Identitas (<b>%(userId)s</b>) %(displayName)s tampaknya telah berubah. <a>Pelajari lebih lanjut</a>",
"withdraw_verification_action": "Tolak verifikasi"
},
"left_panel": {
"open_dial_pad": "Buka tombol penyetel"
},
"time": {
"about_day_ago": "1 hari yang lalu",
"about_hour_ago": "1 jam yang lalu",
"about_minute_ago": "1 menit yang lalu",
"few_seconds_ago": "beberapa detik yang lalu",
"in_about_day": "1 hari dari sekarang",
"in_about_hour": "1 jam dari sekarang",
"in_about_minute": "1 menit dari sekarang",
"in_few_seconds": "beberapa detik dari sekarang",
"in_n_days": "%(num)s hari dari sekarang",
"in_n_hours": "%(num)s jam dari sekarang",
"in_n_minutes": "%(num)s dari sekarang",
"n_days_ago": "%(num)s hari yang lalu",
"n_hours_ago": "%(num)s jam yang lalu",
"n_minutes_ago": "%(num)s menit yang lalu"
},
"timeline": {
"m.audio": {
"audio_player": "Pemutar audio",
"error_downloading_audio": "Terjadi kesalahan mengunduh audio",
"unnamed_audio": "Audio tidak dinamai"
}
}
}
@@ -0,0 +1,35 @@
{
"action": {
"delete": "Eyða",
"dismiss": "Hunsa",
"explore_rooms": "Kanna spjallrásir",
"pause": "Bið",
"play": "Spila",
"search": "Leita"
},
"left_panel": {
"open_dial_pad": "Opna talnaborð"
},
"time": {
"about_day_ago": "fyrir um degi síðan",
"about_hour_ago": "fyrir um klukkustund síðan",
"about_minute_ago": "fyrir um það bil mínútu síðan",
"few_seconds_ago": "fyrir örfáum sekúndum síðan",
"in_about_day": "eftir um það bil einn dag",
"in_about_hour": "eftir um það bil klukkustund",
"in_about_minute": "eftir um það bil mínútu",
"in_few_seconds": "eftir nokkrar sekúndur",
"in_n_days": "eftir %(num)s daga",
"in_n_hours": "eftir %(num)s klukkustundir",
"in_n_minutes": "eftir %(num)s mínútur",
"n_days_ago": "fyrir %(num)s dögum síðan",
"n_hours_ago": "fyrir %(num)s klukkustundum síðan",
"n_minutes_ago": "fyrir %(num)s mínútum síðan"
},
"timeline": {
"m.audio": {
"error_downloading_audio": "Villa við að sækja hljóð",
"unnamed_audio": "Nafnlaust hljóð"
}
}
}
@@ -0,0 +1,38 @@
{
"a11y": {
"seek_bar_label": "Barra di ricerca audio"
},
"action": {
"delete": "Elimina",
"dismiss": "Chiudi",
"explore_rooms": "Esplora stanze",
"pause": "Pausa",
"play": "Riproduci",
"search": "Cerca"
},
"left_panel": {
"open_dial_pad": "Apri tastierino"
},
"time": {
"about_day_ago": "circa un giorno fa",
"about_hour_ago": "circa un'ora fa",
"about_minute_ago": "circa un minuto fa",
"few_seconds_ago": "pochi secondi fa",
"in_about_day": "circa un giorno da adesso",
"in_about_hour": "circa un'ora da adesso",
"in_about_minute": "circa un minuto da adesso",
"in_few_seconds": "pochi secondi da adesso",
"in_n_days": "%(num)s giorni da adesso",
"in_n_hours": "%(num)s ore da adesso",
"in_n_minutes": "%(num)s minuti da adesso",
"n_days_ago": "%(num)s giorni fa",
"n_hours_ago": "%(num)s ore fa",
"n_minutes_ago": "%(num)s minuti fa"
},
"timeline": {
"m.audio": {
"error_downloading_audio": "Errore di scaricamento dell'audio",
"unnamed_audio": "Audio senza nome"
}
}
}
@@ -0,0 +1,35 @@
{
"action": {
"delete": "削除",
"dismiss": "閉じる",
"explore_rooms": "ルームを探す",
"pause": "一時停止",
"play": "再生",
"search": "検索"
},
"left_panel": {
"open_dial_pad": "ダイヤルパッドを開く"
},
"time": {
"about_day_ago": "約1日前",
"about_hour_ago": "約1時間前",
"about_minute_ago": "約1分前",
"few_seconds_ago": "数秒前",
"in_about_day": "今から約1日前",
"in_about_hour": "今から約1時間前",
"in_about_minute": "今から約1分前",
"in_few_seconds": "今から数秒前",
"in_n_days": "今から%(num)s日前",
"in_n_hours": "今から%(num)s時間前",
"in_n_minutes": "今から%(num)s分前",
"n_days_ago": "%(num)s日前",
"n_hours_ago": "%(num)s時間前",
"n_minutes_ago": "%(num)s分前"
},
"timeline": {
"m.audio": {
"error_downloading_audio": "音声をダウンロードする際にエラーが発生しました",
"unnamed_audio": "名前のない音声"
}
}
}
@@ -0,0 +1,32 @@
{
"action": {
"delete": "წაშლა",
"dismiss": "დახურვა",
"explore_rooms": "ოთახების დათავლიერება",
"pause": "პაუზა",
"play": "დაკვრა",
"search": "ძიება"
},
"time": {
"about_day_ago": "დაახლოებით ერთი დღის წინ",
"about_hour_ago": "დაახლოებით ერთი საათის წინ",
"about_minute_ago": "დაახლოებით ერთი წუთის წინ",
"few_seconds_ago": "რამდენიმე წამის წინ",
"in_about_day": "დაახლოებით ერთი დღის შემდეგ",
"in_about_hour": "დაახლოებით ერთი საათის შემდეგ",
"in_about_minute": "დაახლოებით ერთი წუთის შემდეგ",
"in_few_seconds": "რამდენიმე წამის შემდეგ",
"in_n_days": "%(num)sდღეებიდან",
"in_n_hours": "%(num)sსაათის შემდეგ",
"in_n_minutes": "%(num)sწუთის შემდეგ",
"n_days_ago": "%(num)sდღის წინ",
"n_hours_ago": "%(num)sსაათის წინ",
"n_minutes_ago": "%(num)sწუთის წინ"
},
"timeline": {
"m.audio": {
"error_downloading_audio": "შეცდომა აუდიოს ჩამოტვირთვისას",
"unnamed_audio": "უსახელო აუდიო"
}
}
}
@@ -0,0 +1,43 @@
{
"a11y": {
"seek_bar_label": "오디오 탐색 바"
},
"action": {
"delete": "삭제",
"dismiss": "버리기",
"explore_rooms": "방 검색",
"pause": "일시중지",
"play": "재생",
"search": "찾기"
},
"encryption": {
"pinned_identity_changed": "%(displayName)s (<b>%(userId)s</b>)의 신원이 재설정되었습니다. <a>자세히 알아보기</a>",
"withdraw_verification_action": "인증 취소"
},
"left_panel": {
"open_dial_pad": "다이얼 패드 열기"
},
"time": {
"about_day_ago": "약 1일 전",
"about_hour_ago": "약 1 시간 전",
"about_minute_ago": "약 1분 전",
"few_seconds_ago": "몇 초 전",
"in_about_day": "하루 정도 후",
"in_about_hour": "지금부터 한 시간 정도 후에",
"in_about_minute": "지금부터 약 1분 후",
"in_few_seconds": "몇 초 후",
"in_n_days": "지금부터 %(num)s 일 후에",
"in_n_hours": "지금부터 %(num)s 시간 후",
"in_n_minutes": "지금부터 %(num)s분 후",
"n_days_ago": "%(num)s일 전",
"n_hours_ago": "%(num)s 시간 전",
"n_minutes_ago": "%(num)s분 전"
},
"timeline": {
"m.audio": {
"audio_player": "오디오 플레이어",
"error_downloading_audio": "오디오 다운로드 중 오류 발생",
"unnamed_audio": "이름 없는 오디오"
}
}
}
@@ -0,0 +1,35 @@
{
"action": {
"delete": "ລຶບ",
"dismiss": "ຍົກເລີກ",
"explore_rooms": "ການສຳຫຼວດຫ້ອງ",
"pause": "ຢຸດຊົ່ວຄາວ",
"play": "ຫຼິ້ນ",
"search": "ຊອກຫາ"
},
"left_panel": {
"open_dial_pad": "ເປີດແຜ່ນປັດ"
},
"time": {
"about_day_ago": "ປະມານຫນຶ່ງມື້ກ່ອນຫນ້ານີ້",
"about_hour_ago": "ປະມານຫນຶ່ງຊົ່ວໂມງກ່ອນຫນ້ານີ້",
"about_minute_ago": "ປະມານໜຶ່ງວິນາທີກ່ອນຫນ້ານີ້",
"few_seconds_ago": "ສອງສາມວິນາທີກ່ອນຫນ້ານີ້",
"in_about_day": "ປະມານນຶ່ງມື້ຈາກນີ້",
"in_about_hour": "ປະມານຫນຶ່ງຊົ່ວໂມງຈາກປະຈຸບັນນີ້",
"in_about_minute": "ປະມານໜຶ່ງນາທີຕໍ່ຈາກນີ້",
"in_few_seconds": "ສອງສາມວິນາທີຕໍ່ຈາກນີ້ໄປ",
"in_n_days": "%(num)s ມື້ຕໍ່ຈາກນີ້",
"in_n_hours": "%(num)s ຊົ່ວໂມງຈາກປະຈຸບັນນີ້",
"in_n_minutes": "%(num)s ນາທີຕໍ່ຈາກນີ້",
"n_days_ago": "%(num)sມື້ກ່ອນຫນ້ານີ້",
"n_hours_ago": "%(num)s ຊົ່ວໂມງກ່ອນ",
"n_minutes_ago": "%(num)s ນາທີກ່ອນ"
},
"timeline": {
"m.audio": {
"error_downloading_audio": "ເກີດຄວາມຜິດພາດໃນການດາວໂຫຼດສຽງ",
"unnamed_audio": "ສຽງບໍ່ມີຊື່"
}
}
}
@@ -0,0 +1,24 @@
{
"action": {
"delete": "Ištrinti",
"dismiss": "Atmesti",
"explore_rooms": "Žvalgyti kambarius",
"search": "Ieškoti"
},
"time": {
"about_day_ago": "maždaug prieš dieną",
"about_hour_ago": "maždaug prieš valandą",
"about_minute_ago": "maždaug prieš minutę",
"few_seconds_ago": "prieš kelias sekundes",
"in_about_day": "apie dieną nuo dabar",
"in_about_hour": "apie valandą nuo dabar",
"in_about_minute": "apie minutę nuo dabar",
"in_few_seconds": "keletą sekundžių nuo dabar",
"in_n_days": "%(num)s dienas(-ų) nuo dabar",
"in_n_hours": "%(num)s valandas(-ų) nuo dabar",
"in_n_minutes": "%(num)s minutes(-ų) nuo dabar",
"n_days_ago": "prieš %(num)s dienas(-ų)",
"n_hours_ago": "prieš %(num)s valandas(-ų)",
"n_minutes_ago": "prieš %(num)s minutes(-ų)"
}
}
@@ -0,0 +1,35 @@
{
"a11y": {
"seek_bar_label": "Audio meklēšanas josla"
},
"action": {
"delete": "Izdzēst",
"dismiss": "Atmest",
"explore_rooms": "Pārlūkot istabas",
"pause": "Pauzēt",
"play": "Atskaņot",
"search": "Meklēt"
},
"time": {
"about_day_ago": "aptuveni dienu iepriekš",
"about_hour_ago": "aptuveni stundu iepriekš",
"about_minute_ago": "aptuveni minūti iepriekš",
"few_seconds_ago": "pirms dažām sekundēm",
"in_about_day": "aptuveni dienu kopš šī brīža",
"in_about_hour": "aptuveni stundu kopš šī brīža",
"in_about_minute": "aptuveni minūti kopš šī brīža",
"in_few_seconds": "dažas sekundes kopš šī brīža",
"in_n_days": "%(num)s dienas kopš šī brīža",
"in_n_hours": "%(num)s stundas kopš šī brīža",
"in_n_minutes": "%(num)s minūtes kopš šī brīža",
"n_days_ago": "%(num)s dienas iepriekš",
"n_hours_ago": "%(num)s stundas iepriekš",
"n_minutes_ago": "%(num)s minūtes iepriekš"
},
"timeline": {
"m.audio": {
"error_downloading_audio": "Kļūda skaņas lejupielādēšanā",
"unnamed_audio": "Nenosaukts audio"
}
}
}
@@ -0,0 +1,38 @@
{
"a11y": {
"seek_bar_label": "Audio mitady bar"
},
"action": {
"delete": "Esorina",
"dismiss": "Hanario",
"explore_rooms": "Tsidiho ny efitrano",
"pause": "Mihato",
"play": "Milalao",
"search": "Karohina"
},
"left_panel": {
"open_dial_pad": "Sokafy ny dial pad"
},
"time": {
"about_day_ago": "Tokony ho iray andro izay",
"about_hour_ago": "Manakaiky adin'iray Teo ho eo",
"about_minute_ago": "Misy iray minitra Teo izay",
"few_seconds_ago": "Segondra vitsy lasa",
"in_about_day": "Anatiny iray andro eo ho eo",
"in_about_hour": "Adiny iray eo ho eo",
"in_about_minute": "Afaka iray minitra eo ho eo",
"in_few_seconds": "Afaka segondra vitsy",
"in_n_days": "%(num) s andro manomboka izao",
"in_n_hours": "% (num) sAnatiny ora vitsivitsy",
"in_n_minutes": "% (Num) sAfaka minitra vitsy",
"n_days_ago": "%(num)s Andro vitsivitsy izay",
"n_hours_ago": "%(num)sOra maromaro",
"n_minutes_ago": "%(Num)s Minitra vitsivitsy izay"
},
"timeline": {
"m.audio": {
"error_downloading_audio": "Hadisoana tamin'ny fampidinana feo",
"unnamed_audio": "Audio tsy voatonona anarana"
}
}
}
@@ -0,0 +1,43 @@
{
"a11y": {
"seek_bar_label": "Søkelinje for lyd"
},
"action": {
"delete": "Slett",
"dismiss": "Avvis",
"explore_rooms": "Se alle rom",
"pause": "Pause",
"play": "Spill av",
"search": "Søk"
},
"encryption": {
"pinned_identity_changed": "%(displayName)ss (<b>%(userId)s</b>) identitet ser ut til å ha endret seg. <a>Finn ut mer</a>",
"withdraw_verification_action": "Trekk tilbake verifisering"
},
"left_panel": {
"open_dial_pad": "Åpne nummerpanelet"
},
"time": {
"about_day_ago": "cirka 1 dag siden",
"about_hour_ago": "cirka 1 time siden",
"about_minute_ago": "cirka 1 minutt siden",
"few_seconds_ago": "noen sekunder siden",
"in_about_day": "rundt en dag fra nå",
"in_about_hour": "rundt en time fra nå",
"in_about_minute": "rundt et minutt fra nå",
"in_few_seconds": "om noen sekunder fra nå",
"in_n_days": "%(num)s dager fra nå",
"in_n_hours": "%(num)s timer fra nå",
"in_n_minutes": "%(num)s minutter fra nå",
"n_days_ago": "%(num)s dager siden",
"n_hours_ago": "%(num)s timer siden",
"n_minutes_ago": "%(num)s minutter siden"
},
"timeline": {
"m.audio": {
"audio_player": "Lydavspiller",
"error_downloading_audio": "Feil ved nedlasting av lyd",
"unnamed_audio": "Ikke navngitt lyd"
}
}
}
@@ -0,0 +1,38 @@
{
"a11y": {
"seek_bar_label": "Audio zoekbalk"
},
"action": {
"delete": "Verwijderen",
"dismiss": "Sluiten",
"explore_rooms": "Kamers ontdekken",
"pause": "Pauze",
"play": "Afspelen",
"search": "Zoeken"
},
"left_panel": {
"open_dial_pad": "Kiestoetsen openen"
},
"time": {
"about_day_ago": "ongeveer een dag geleden",
"about_hour_ago": "ongeveer een uur geleden",
"about_minute_ago": "ongeveer een minuut geleden",
"few_seconds_ago": "enige tellen geleden",
"in_about_day": "over een dag of zo",
"in_about_hour": "over ongeveer een uur",
"in_about_minute": "over ongeveer een minuut",
"in_few_seconds": "over een paar tellen",
"in_n_days": "over %(num)s dagen",
"in_n_hours": "over %(num)s uur",
"in_n_minutes": "over %(num)s minuten",
"n_days_ago": "%(num)s dagen geleden",
"n_hours_ago": "%(num)s uur geleden",
"n_minutes_ago": "%(num)s minuten geleden"
},
"timeline": {
"m.audio": {
"error_downloading_audio": "Fout bij downloaden van audio",
"unnamed_audio": "Naamloze audio"
}
}
}
@@ -0,0 +1,43 @@
{
"a11y": {
"seek_bar_label": "Pasek wyszukiwania audio"
},
"action": {
"delete": "Usuń",
"dismiss": "Pomiń",
"explore_rooms": "Przeglądaj pokoje",
"pause": "Wstrzymaj",
"play": "Odtwórz",
"search": "Szukaj"
},
"encryption": {
"pinned_identity_changed": "Tożsamość %(displayName)s (<b>%(userId)s</b>) została zresetowana. <a>Dowiedz się więcej</a>",
"withdraw_verification_action": "Wycofaj weryfikację"
},
"left_panel": {
"open_dial_pad": "Otwórz klawiaturę numeryczną"
},
"time": {
"about_day_ago": "około dzień temu",
"about_hour_ago": "około godziny temu",
"about_minute_ago": "około minuty temu",
"few_seconds_ago": "kilka sekund temu",
"in_about_day": "około dnia od teraz",
"in_about_hour": "około godziny od teraz",
"in_about_minute": "około minuty od teraz",
"in_few_seconds": "za kilka sekund",
"in_n_days": "za %(num)s dni",
"in_n_hours": "za %(num)s godzin",
"in_n_minutes": "za %(num)s minut",
"n_days_ago": "%(num)s dni temu",
"n_hours_ago": "%(num)s godzin temu",
"n_minutes_ago": "%(num)s minut temu"
},
"timeline": {
"m.audio": {
"audio_player": "Odtwarzacz audio",
"error_downloading_audio": "Wystąpił błąd w trakcie pobierania audio",
"unnamed_audio": "Audio bez nazwy"
}
}
}
@@ -0,0 +1,42 @@
{
"a11y": {
"seek_bar_label": "Barra de procura de áudio"
},
"action": {
"delete": "Apagar",
"dismiss": "Descartar",
"explore_rooms": "Explorar rooms",
"pause": "Pausar",
"play": "Reproduzir",
"search": "Pesquisar"
},
"encryption": {
"pinned_identity_changed": "A identidade de %(displayName)s (<b>%(userId)s</b> ) foi alterada. <a> Saber mais</a>",
"withdraw_verification_action": "Retirar verificação"
},
"left_panel": {
"open_dial_pad": "Abre o teclado de marcação"
},
"time": {
"about_day_ago": "há cerca de um dia",
"about_hour_ago": "há cerca de uma hora",
"about_minute_ago": "há cerca de um minuto",
"few_seconds_ago": "há alguns segundos atrás",
"in_about_day": "daqui a um dia",
"in_about_hour": "daqui a uma hora",
"in_about_minute": "daqui a um minuto",
"in_few_seconds": "daqui a alguns segundos",
"in_n_days": "daqui a %(num)s dias",
"in_n_hours": "daqui a %(num)s horas",
"in_n_minutes": "daqui a %(num)s minutos",
"n_days_ago": "%(num)s dias atrás",
"n_hours_ago": "%(num)s horas atrás",
"n_minutes_ago": "%(num)s minutos atrás"
},
"timeline": {
"m.audio": {
"error_downloading_audio": "Erro ao descarregar áudio",
"unnamed_audio": "Áudio sem nome"
}
}
}
@@ -0,0 +1,43 @@
{
"a11y": {
"seek_bar_label": "Barra de busca de áudio"
},
"action": {
"delete": "Excluir",
"dismiss": "Dispensar",
"explore_rooms": "Explorar salas",
"pause": "Pausar",
"play": "Reproduzir",
"search": "Buscar"
},
"encryption": {
"pinned_identity_changed": "A identidade de %(displayName)s (<b>%(userId)s</b>) parece ter mudado. <a>Saiba mais</a>",
"withdraw_verification_action": "Retirar verificação"
},
"left_panel": {
"open_dial_pad": "Abrir o teclado de discagem"
},
"time": {
"about_day_ago": "há aproximadamente um dia",
"about_hour_ago": "há aproximadamente uma hora",
"about_minute_ago": "há aproximadamente um minuto",
"few_seconds_ago": "há alguns segundos",
"in_about_day": "dentro de aproximadamente um dia",
"in_about_hour": "dentro de aproximadamente uma hora",
"in_about_minute": "dentro de aproximadamente um minuto",
"in_few_seconds": "dentro de alguns segundos",
"in_n_days": "dentro de %(num)s dias",
"in_n_hours": "dentro de %(num)s horas",
"in_n_minutes": "dentro de %(num)s minutos",
"n_days_ago": "há %(num)s dias",
"n_hours_ago": "há %(num)s horas",
"n_minutes_ago": "há %(num)s minutos"
},
"timeline": {
"m.audio": {
"audio_player": "Reprodutor de Áudio",
"error_downloading_audio": "Erro ao baixar o áudio",
"unnamed_audio": "Áudio sem nome"
}
}
}
@@ -0,0 +1,43 @@
{
"a11y": {
"seek_bar_label": "Панель поиска аудио"
},
"action": {
"delete": "Удалить",
"dismiss": "Закрыть",
"explore_rooms": "Обзор комнат",
"pause": "Пауза",
"play": "Воспроизведение",
"search": "Поиск"
},
"encryption": {
"pinned_identity_changed": "Идентичность %(displayName)s (<b>%(userId)s</b>), похоже, изменилась. <a>Узнать больше</a>",
"withdraw_verification_action": "Подтверждение верификации"
},
"left_panel": {
"open_dial_pad": "Открыть панель набора номера"
},
"time": {
"about_day_ago": "около суток назад",
"about_hour_ago": "около часа назад",
"about_minute_ago": "около минуты назад",
"few_seconds_ago": "несколько секунд назад",
"in_about_day": "примерно через день",
"in_about_hour": "примерно через час",
"in_about_minute": "примерно через минуту",
"in_few_seconds": "несколько секунд назад",
"in_n_days": "%(num)s дней спустя",
"in_n_hours": "%(num)s часов спустя",
"in_n_minutes": "%(num)s минут спустя",
"n_days_ago": "%(num)s дней назад",
"n_hours_ago": "%(num)s часов назад",
"n_minutes_ago": "%(num)s минут назад"
},
"timeline": {
"m.audio": {
"audio_player": "Аудиоплеер",
"error_downloading_audio": "Ошибка загрузки аудио",
"unnamed_audio": "Безымянное аудио"
}
}
}
@@ -0,0 +1,48 @@
{
"a11y": {
"seek_bar_label": "Panel vyhľadávania zvuku"
},
"action": {
"delete": "Vymazať",
"dismiss": "Zamietnuť",
"explore_rooms": "Preskúmať miestnosti",
"pause": "Pozastaviť",
"play": "Prehrať",
"search": "Hľadať"
},
"encryption": {
"pinned_identity_changed": "Zdá sa, že identita (<b>%(userId)s</b>) používateľa %(displayName)s bola obnovená. <a>Zistiť viac </a>",
"withdraw_verification_action": "Zrušiť overenie"
},
"left_panel": {
"open_dial_pad": "Otvoriť číselník"
},
"room": {
"status_bar": {
"history_visible": "Správy, ktoré odošlete, budú zdieľané s novými členmi pozvanými do tejto miestnosti. <a>Zistiť viac</a>"
}
},
"time": {
"about_day_ago": "asi pred jedným dňom",
"about_hour_ago": "približne pred hodinou",
"about_minute_ago": "približne pred minútou",
"few_seconds_ago": "pred pár sekundami",
"in_about_day": "približne o deň",
"in_about_hour": "približne o hodinu",
"in_about_minute": "približne o minútu",
"in_few_seconds": "o pár sekúnd",
"in_n_days": "o %(num)s dní",
"in_n_hours": "o %(num)s hodín",
"in_n_minutes": "o %(num)s minút",
"n_days_ago": "pred %(num)s dňami",
"n_hours_ago": "pred %(num)s hodinami",
"n_minutes_ago": "pred %(num)s minútami"
},
"timeline": {
"m.audio": {
"audio_player": "Prehrávač zvuku",
"error_downloading_audio": "Chyba pri sťahovaní zvuku",
"unnamed_audio": "Nepomenovaný zvukový záznam"
}
}
}
@@ -0,0 +1,35 @@
{
"action": {
"delete": "Fshije",
"dismiss": "Mos e merr parasysh",
"explore_rooms": "Eksploroni dhoma",
"pause": "Ndalesë",
"play": "Luaje",
"search": "Kërkoni"
},
"left_panel": {
"open_dial_pad": "Hap butona numrash"
},
"time": {
"about_day_ago": "rreth një ditë më parë",
"about_hour_ago": "rreth një orë më parë",
"about_minute_ago": "rreth një minutë më parë",
"few_seconds_ago": "pak sekonda më parë",
"in_about_day": "rreth një ditë nga tani",
"in_about_hour": "rreth një orë nga tani",
"in_about_minute": "rreth një minutë nga tani",
"in_few_seconds": "pak sekonda nga tani",
"in_n_days": "%(num)s ditë nga tani",
"in_n_hours": "%(num)s orë nga tani",
"in_n_minutes": "%(num)s minuta nga tani",
"n_days_ago": "%(num)s ditë më parë",
"n_hours_ago": "%(num)s orë më parë",
"n_minutes_ago": "%(num)s minuta më parë"
},
"timeline": {
"m.audio": {
"error_downloading_audio": "Gabim në shkarkim audioje",
"unnamed_audio": "Audio pa emër"
}
}
}
@@ -0,0 +1,43 @@
{
"a11y": {
"seek_bar_label": "Förloppsfält för ljud"
},
"action": {
"delete": "Radera",
"dismiss": "Avvisa",
"explore_rooms": "Utforska rum",
"pause": "Pausa",
"play": "Spela",
"search": "Sök"
},
"encryption": {
"pinned_identity_changed": "%(displayName)ss (<b>%(userId)s</b> ) identitet verkar ha ändrats.<a> Läs mer</a>",
"withdraw_verification_action": "Återkalla verifieringen"
},
"left_panel": {
"open_dial_pad": "Öppna knappsats"
},
"time": {
"about_day_ago": "cirka en dag sedan",
"about_hour_ago": "cirka en timme sedan",
"about_minute_ago": "cirka en minut sedan",
"few_seconds_ago": "några sekunder sedan",
"in_about_day": "om cirka en dag",
"in_about_hour": "om cirka en timme",
"in_about_minute": "om cirka en minut",
"in_few_seconds": "om några sekunder",
"in_n_days": "om %(num)s dagar",
"in_n_hours": "om %(num)s timmar",
"in_n_minutes": "om %(num)s minuter",
"n_days_ago": "%(num)s dagar sedan",
"n_hours_ago": "%(num)s timmar sedan",
"n_minutes_ago": "%(num)s minuter sedan"
},
"timeline": {
"m.audio": {
"audio_player": "Ljudspelare",
"error_downloading_audio": "Fel vid nedladdning av ljud",
"unnamed_audio": "Namnlöst ljud"
}
}
}
@@ -0,0 +1,42 @@
{
"a11y": {
"seek_bar_label": "Ses arama çubuğu"
},
"action": {
"delete": "Sil",
"dismiss": "Kapat",
"explore_rooms": "Odaları keşfet",
"pause": "Durdur",
"play": "Oynat",
"search": "Ara"
},
"encryption": {
"pinned_identity_changed": "%(displayName)s'ın (<b>%(userId)s</b>) kimliği değişmiş gibi görünüyor. <a>Daha fazla bilgi </a>",
"withdraw_verification_action": "Doğrulamayı iptal et"
},
"left_panel": {
"open_dial_pad": "Arama tuşlarını aç"
},
"time": {
"about_day_ago": "yaklaşık bir gün önce",
"about_hour_ago": "yaklaşık bir saat önce",
"about_minute_ago": "yaklaşık bir dakika önce",
"few_seconds_ago": "bir kaç saniye önce",
"in_about_day": "şu andan itibaren yaklaşık bir gün",
"in_about_hour": "şu andan itibaren yaklaşık bir saat",
"in_about_minute": "şu andan itibaren yaklaşık bir dakika",
"in_few_seconds": "şu andan itibaren bir kaç saniye",
"in_n_days": "şu andan itibaren %(num)s gün",
"in_n_hours": "şu andan itibaren %(num)s saat",
"in_n_minutes": "şu andan itibaren %(num)s dakika",
"n_days_ago": "%(num)s gün önce",
"n_hours_ago": "%(num)s saat önce",
"n_minutes_ago": "%(num)s dakika önce"
},
"timeline": {
"m.audio": {
"error_downloading_audio": "Ses dosyası indirilirken hata oluştu",
"unnamed_audio": "İsimsiz ses"
}
}
}
@@ -0,0 +1,43 @@
{
"a11y": {
"seek_bar_label": "Панель гортання аудіо"
},
"action": {
"delete": "Видалити",
"dismiss": "Відхилити",
"explore_rooms": "Каталог кімнат",
"pause": "Призупинити",
"play": "Відтворити",
"search": "Пошук"
},
"encryption": {
"pinned_identity_changed": "Ідентичність %(displayName)s (<b>%(userId)s</b>) скинуто. <a>Докладніше</a>",
"withdraw_verification_action": "Відкликати верифікацію"
},
"left_panel": {
"open_dial_pad": "Відкрити номеронабирач"
},
"time": {
"about_day_ago": "близько доби тому",
"about_hour_ago": "близько години тому",
"about_minute_ago": "близько хвилини тому",
"few_seconds_ago": "Декілька секунд тому",
"in_about_day": "приблизно через день",
"in_about_hour": "приблизно через годину",
"in_about_minute": "приблизно через хвилинку",
"in_few_seconds": "декілька секунд тому",
"in_n_days": "%(num)s днів по тому",
"in_n_hours": "%(num)s годин по тому",
"in_n_minutes": "%(num)s хвилин по тому",
"n_days_ago": "%(num)s днів тому",
"n_hours_ago": "%(num)s годин тому",
"n_minutes_ago": "%(num)s хвилин тому"
},
"timeline": {
"m.audio": {
"audio_player": "Звуковий програвач",
"error_downloading_audio": "Помилка завантаження аудіо",
"unnamed_audio": "Аудіо без назви"
}
}
}
@@ -0,0 +1,35 @@
{
"action": {
"delete": "Xoá",
"dismiss": "Bỏ qua",
"explore_rooms": "Khám phá các phòng",
"pause": "Tạm dừng",
"play": "Chạy",
"search": "Tìm kiếm"
},
"left_panel": {
"open_dial_pad": "Mở bàn phím quay số"
},
"time": {
"about_day_ago": "khoảng một ngày trước",
"about_hour_ago": "khoảng một giờ trước",
"about_minute_ago": "khoảng một phút trước",
"few_seconds_ago": "vài giây trước",
"in_about_day": "khoảng một ngày kể từ bây giờ",
"in_about_hour": "khoảng một giờ kể từ bây giờ",
"in_about_minute": "khoảng một phút kể từ bây giờ",
"in_few_seconds": "một vài giây kể từ bây giờ",
"in_n_days": "%(num)s ngày kể từ bây giờ",
"in_n_hours": "%(num)s giờ kể từ bây giờ",
"in_n_minutes": "%(num)s phút kể từ bây giờ",
"n_days_ago": "%(num)s ngày trước",
"n_hours_ago": "%(num)s giờ trước",
"n_minutes_ago": "%(num)s phút trước"
},
"timeline": {
"m.audio": {
"error_downloading_audio": "Lỗi khi tải xuống âm thanh",
"unnamed_audio": "Âm thanh không tên"
}
}
}
@@ -0,0 +1,35 @@
{
"action": {
"delete": "删除",
"dismiss": "忽略",
"explore_rooms": "查找房间",
"pause": "暂停",
"play": "播放",
"search": "搜索"
},
"left_panel": {
"open_dial_pad": "打开拨号键盘"
},
"time": {
"about_day_ago": "约一天前",
"about_hour_ago": "约一小时前",
"about_minute_ago": "约一分钟前",
"few_seconds_ago": "数秒前",
"in_about_day": "从现在开始约一天",
"in_about_hour": "从现在开始约一小时",
"in_about_minute": "从现在开始约一分钟",
"in_few_seconds": "从现在开始数秒",
"in_n_days": "从现在开始%(num)s天",
"in_n_hours": "从现在开始%(num)s小时",
"in_n_minutes": "从现在开始%(num)s分钟",
"n_days_ago": "%(num)s天前",
"n_hours_ago": "%(num)s小时前",
"n_minutes_ago": "%(num)s分钟前"
},
"timeline": {
"m.audio": {
"error_downloading_audio": "下载音频时出错",
"unnamed_audio": "未命名的音频"
}
}
}
@@ -0,0 +1,35 @@
{
"action": {
"delete": "刪除",
"dismiss": "關閉",
"explore_rooms": "探索聊天室",
"pause": "暫停",
"play": "播放",
"search": "搜尋"
},
"left_panel": {
"open_dial_pad": "開啟撥號鍵盤"
},
"time": {
"about_day_ago": "大約一天前",
"about_hour_ago": "大約一小時前",
"about_minute_ago": "大約一分鐘前",
"few_seconds_ago": "數秒前",
"in_about_day": "從現在開始大約一天",
"in_about_hour": "從現在開始大約一小時",
"in_about_minute": "從現在開始大約一分鐘",
"in_few_seconds": "從現在開始數秒鐘",
"in_n_days": "從現在開始 %(num)s 天",
"in_n_hours": "從現在開始 %(num)s 小時",
"in_n_minutes": "從現在開始 %(num)s 分鐘",
"n_days_ago": "%(num)s 天前",
"n_hours_ago": "%(num)s 小時前",
"n_minutes_ago": "%(num)s 分鐘前"
},
"timeline": {
"m.audio": {
"error_downloading_audio": "下載音訊時發生錯誤",
"unnamed_audio": "未命名的音訊"
}
}
}
-4
View File
@@ -36,7 +36,3 @@ export * from "./utils/I18nApi";
export * from "./viewmodel";
export * from "./useMockedViewModel";
export * from "./useViewModel";
// i18n (we must export this directly in order to not confuse the type bundler, it seems,
// otherwise it will leave it as a relative import rather than bundling it)
export type * from "./i18nKeys.d.ts";
@@ -8,7 +8,7 @@ Please see LICENSE files in the repository root for full details.
import fetchMock from "fetch-mock-jest";
import { setLanguage } from "../../src/utils/i18n";
import en from "../../../../src/i18n/strings/en_EN.json";
import en from "../i18n/strings/en_EN.json";
export function setupLanguageMock(): void {
fetchMock
@@ -5,14 +5,13 @@
* Please see LICENSE files in the repository root for full details.
*/
import { type TranslationKey } from "../i18nKeys";
import { I18nApi } from "./I18nApi";
describe("I18nApi", () => {
it("can register a translation and use it", () => {
const i18n = new I18nApi();
i18n.register({
"hello.world": {
["hello.world" as TranslationKey]: {
en: "Hello, World!",
},
});
@@ -9,7 +9,6 @@ import { type I18nApi as II18nApi, type Variables, type Translations } from "@el
import { humanizeTime } from "./humanize";
import { _t, getLocale, registerTranslations } from "./i18n";
import { type TranslationKey } from "../i18nKeys";
export class I18nApi implements II18nApi {
/**
@@ -24,10 +23,11 @@ export class I18nApi implements II18nApi {
*/
public register(translations: Partial<Translations>): void {
const langs: Record<string, Record<string, string>> = {};
for (const key in translations) {
for (const lang in translations[key]) {
for (const lang in translations[key as keyof Translations]) {
langs[lang] = langs[lang] || {};
langs[lang][key] = translations[key][lang];
langs[lang][key] = translations[key as keyof Translations]![lang];
}
}
+4 -12
View File
@@ -25,13 +25,11 @@ import React from "react";
import { KEY_SEPARATOR } from "matrix-web-i18n";
import counterpart from "counterpart";
import type { TranslationKey } from "../index";
// @ts-ignore - $webapp is a webpack resolve alias pointing to the output directory, see webpack config
import webpackLangJsonUrl from "$webapp/i18n/languages.json";
export { KEY_SEPARATOR, normalizeLanguageKey, getNormalizedLanguageKeys } from "matrix-web-i18n";
// Path where we load language files from (the index plus translations for each language)
// The filename is appended to this, so a relative path here will result in a fetch for
// a relative URL.
const i18nFolder = "i18n/";
// Control whether to also return original, untranslated strings
@@ -421,13 +419,7 @@ async function getLanguage(langPath: string): Promise<ICounterpartTranslation> {
}
export async function getLangsJson(): Promise<Languages> {
let url: string;
if (typeof webpackLangJsonUrl === "string") {
// in Jest this 'url' isn't a URL, so just fall through
url = webpackLangJsonUrl;
} else {
url = i18nFolder + "languages.json";
}
const url = i18nFolder + "languages.json";
const res = await fetch(url, { method: "GET" });