Add pt-br locale (#261)

This commit is contained in:
Luke Vella 2022-07-29 13:25:39 +01:00 committed by GitHub
parent 0b156fabe6
commit 1ef15682ea
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 226 additions and 18 deletions

View file

@ -3,7 +3,7 @@ const path = require("path");
module.exports = {
i18n: {
defaultLocale: "en",
locales: ["en", "es", "de", "fr", "sv"],
locales: ["en", "es", "de", "fr", "sv", "pt-BR"],
localePath: path.resolve("./public/locales"),
reloadOnPrerender: process.env.NODE_ENV === "development",
},

View file

@ -11,6 +11,7 @@
"italian": "Italian",
"language": "Language",
"links": "Links",
"portugueseBr": "Portuguese (Brazil)",
"poweredBy": "Powered by",
"privacyPolicy": "Privacy Policy",
"spanish": "Spanish",

View file

@ -0,0 +1,128 @@
{
"12h": "12-horas",
"24h": "24-horas",
"addParticipant": "Adicionar participante",
"addTimeOption": "Adicionar opção de horário",
"alreadyVoted": "Você já votou",
"applyToAllDates": "Aplicar a todas as datas",
"areYouSure": "Você tem certeza?",
"back": "Voltar",
"calendarHelp": "Você não pode criar uma enquete sem quaisquer opções. Adicione pelo menos uma opção para continuar.",
"calendarHelpTitle": "Esqueceu algo?",
"cancel": "Cancelar",
"comment": "Comentar",
"commentPlaceholder": "Deixe um comentário nesta enquete (visível para todos)",
"comments": "Comentários",
"continue": "Continuar",
"copied": "Copiado",
"copyLink": "Copiar link",
"createdBy": "por <b>{{name}}</b>",
"createPoll": "Criar enquete",
"creatingDemo": "Criando enquete de demonstração…",
"delete": "Excluir",
"deleteComment": "Apagar comentário",
"deleteDate": "Excluir data",
"deletedPoll": "Enquete excluída",
"deletedPollInfo": "Esta enquete não existe mais.",
"deletePoll": "Excluir enquete",
"deletePollDescription": "Todos os dados relacionados a esta enquete serão excluídos. Para confirmar, digite <s>“{{confirmText}}”</s> no espaço abaixo:",
"deletingOptionsWarning": "Você está excluindo opções que outros participantes já votaram. Esses votos serão excluídos também.",
"demoPollNotice": "Enquetes de demonstração são excluídas automaticamente após 1 dia",
"description": "Descrição",
"descriptionPlaceholder": "Olá a todos! Por gentileza, escolha as datas que sirva para você!",
"donate": "Doe",
"editDetails": "Editar detalhes",
"editOptions": "Editar opções",
"email": "E-mail",
"emailPlaceholder": "fulano@email.com.br",
"endingGuestSessionNotice": "Uma vez que uma sessão de convidado termine, ela não poderá ser retomada. Você não poderá editar nenhum voto ou comentário que tenha feito nesta sessão.",
"endSession": "Encerrar sessão",
"errorCreate": "Ops! Houve um problema ao criar sua enquete. O erro foi registrado e tentaremos corrigi-lo.",
"exportToCsv": "Exportar para CSV",
"finish": "Concluir",
"forgetMe": "Esqueça-me",
"goToAdmin": "Ir para Admin",
"guest": "Convidado",
"guestSessionNotice": "Você está usando uma sessão de convidado. Isso nos permite reconhecê-lo caso você voltar mais tarde e poder editar seus votos.",
"guestSessionReadMore": "Leia mais sobre sessões de convidado.",
"hide": "Ocultar",
"ifNeedBe": "Se for necessário",
"linkHasExpired": "Seu link expirou ou não é mais válido",
"loading": "Carregando…",
"loadingParticipants": "Carregando participantes…",
"location": "Local",
"locationPlaceholder": "Loja de Café do Júlio",
"lockPoll": "Bloquear enquete",
"login": "Logar",
"loginCheckInbox": "Por gentileza, verifique sua caixa de entrada.",
"loginMagicLinkSent": "Um link mágico foi enviado para:",
"loginSendMagicLink": "Envie-me um link mágico",
"loginViaMagicLink": "Login via link mágico",
"loginViaMagicLinkDescription": "Enviaremos um e-mail com um link mágico que você possa usar para logar.",
"loginWithValidEmail": "Por favor, insira um endereço de e-mail válido",
"logout": "Deslogar",
"manage": "Gerenciar",
"menu": "Menu",
"mixedOptionsDescription": "Você não pode ter ambas as opções de data e hora na mesma enquete. Qual você gostaria de manter?",
"mixedOptionsKeepDates": "Manter opções de data",
"mixedOptionsKeepTimes": "Manter opções de hora",
"mixedOptionsTitle": "Aguarde um minuto…🤔",
"monday": "Segunda-feira",
"monthView": "Visão mensal",
"name": "Nome",
"namePlaceholder": "Fulano de Tal",
"newPoll": "Nova enquete",
"next": "Avançar",
"nextMonth": "Próximo mês",
"no": "Não",
"noDatesSelected": "Nenhuma data selecionada",
"notificationsDisabled": "As notificações foram desabilitadas",
"notificationsOff": "Notificações desativadas",
"notificationsOn": "Notificações ativadas",
"notificationsOnDescription": "Um e-mail será enviado para <b>{{email}}</b> quando houver atividade nesta enquete.",
"notificationsVerifyEmail": "Você precisa confirmar seu e-mail para ativar as notificações",
"ok": "Ok",
"options": "Opções",
"participant": "Participante",
"participantCount_other": "{{count}} participantes",
"participantCount": "{{count}} participante",
"pollHasBeenLocked": "Esta enquete foi bloqueada",
"pollHasBeenVerified": "Sua enquete foi verificada",
"pollOwnerNotice": "Oi {{name}}, parece que você é o proprietário desta enquete.",
"pollsEmpty": "Nenhuma enquete criada",
"possibleAnswers": "Possíveis respostas",
"preferences": "Preferências",
"previousMonth": "Mês anterior",
"profileLogin": "Perfil - Login",
"profileUser": "Perfil - {{username}}",
"requiredNameError": "Nome é obrigatório",
"save": "Salvar",
"saveInstruction": "Selecione sua disponibilidade e clique <b>{{save}}</b>",
"share": "Compartilhar",
"shareDescription": "Dê este link para os seus <b>participantes</b> para permitir que eles votem na sua enquete.",
"shareLink": "Compartilhar via link",
"specifyTimes": "Especificar horários",
"specifyTimesDescription": "Incluir os horários de início e fim para cada opção",
"stepSummary": "Passo {{current}} de {{total}}",
"sunday": "Domingo",
"timeAndDate": "Hora & data",
"timeFormat": "Formato de hora:",
"timeZone": "Fuso horário:",
"title": "Título",
"titlePlaceholder": "Reunião mensal",
"today": "Hoje",
"unlockPoll": "Desbloquear enquete",
"unverifiedMessage": "Um e-mail foi enviado para <b>{{email}}</b> com um link para verificar o endereço de e-mail.",
"user": "Usuário",
"vote": "Votar",
"voteCount_other": "{{count}} votos",
"voteCount": "{{count}} voto",
"weekStartsOn": "A semana começa em",
"weekView": "Visão semanal",
"whatsThis": "O que é isso?",
"yes": "Sim",
"you": "Você",
"yourDetails": "Seus detalhes",
"yourName": "Seu nome…",
"yourPolls": "Suas enquetes"
}

View file

@ -0,0 +1,21 @@
{
"blog": "Blog",
"discussions": "Discussões",
"donate": "Doe",
"english": "English",
"footerCredit": "Feito por <a>@imlukevella</a>",
"footerSponsor": "Este projeto é financiado pelo usuário. Por gentileza, considere apoiá-lo fazendo uma <a>doação</a>.",
"french": "Français",
"german": "Deutsch",
"home": "Início",
"italian": "L'italiano",
"language": "Idioma",
"links": "Links",
"poweredBy": "Desenvolvido por",
"privacyPolicy": "Política de Privacidade",
"spanish": "Español",
"starOnGithub": "Qualifique-nos no GitHub",
"support": "Suporte",
"swedish": "Svenska",
"volunteerTranslator": "Ajude a traduzir esta página"
}

View file

@ -0,0 +1,6 @@
{
"notFoundTitle": "404 Página não encontrada",
"notFoundDescription": "Não conseguimos encontrar a página que você está procurando.",
"goToHome": "Ir para o início",
"startChat": "Iniciar chat"
}

View file

@ -0,0 +1,36 @@
{
"3Ls": "Sim—com 3 <e>L</e>s",
"adFree": "Sem anúncios",
"adFreeDescription": "Você pode dar um descanso ao seu bloqueador de anúncios — Você não vai precisar dele aqui.",
"comments": "Comentários",
"commentsDescription": "Participantes podem comentar na sua enquete e os comentários ficarão visíveis para todos.",
"features": "Funcionalidades",
"featuresSubheading": "Agendamento, da maneira inteligente",
"follow": "Seguir",
"getStarted": "Comece agora",
"heroSubText": "Encontre o dia certo sem contratempos",
"heroText": "Agende<br/><s>reuniões</s><br />com facilidade",
"links": "Links",
"liveDemo": "Demonstração ao vivo",
"metaDescription": "Crie enquetes e vote para encontrar o melhor dia ou hora. Uma alternativa gratuita ao Doodle.",
"metaTitle": "Rallly - Agende reuniões de grupo",
"mobileFriendly": "Compatível com dispositivos móveis",
"mobileFriendlyDescription": "Funciona muito bem em dispositivos móveis para que os participantes possam responder às enquetes onde estiverem.",
"new": "Novo",
"noLoginRequired": "Não requer login",
"noLoginRequiredDescription": "Você não precisa fazer login para criar ou participar de uma enquete",
"notifications": "Notificações",
"notificationsDescription": "Saiba quem respondeu. Seja notificado quando os participantes votarem ou comentarem na sua enquete.",
"openSource": "Código aberto",
"openSourceDescription": "O projeto é totalmente de código aberto e <a>disponível no GitHub</a>.",
"participant": "Participante",
"participantCount_other": "{{count}} participantes",
"participantCount": "{{count}} participante",
"perfect": "Perfeito!",
"principles": "Princípios",
"principlesSubheading": "Não somos como os outros",
"selfHostable": "Auto-hospedável",
"selfHostableDescription": "Execute em seu próprio servidor para ter controle total dos seus dados",
"timeSlots": "Intervalos de tempo",
"timeSlotsDescription": "Defina os horários de início e fim individuais para cada opção em sua enquete. Os horários podem ser automaticamente ajustados ao fuso horário de cada participante ou podem ser definidos para ignorar completamente o fuso horário."
}

View file

@ -20,8 +20,9 @@ export const LanguageSelect: React.VoidFunctionComponent<{
>
<option value="en">{t("english")}</option>
<option value="es">{t("spanish")}</option>
<option value="fr">{t("french")}</option>
<option value="de">{t("german")}</option>
<option value="pt-BR">{t("portugueseBr")}</option>
<option value="fr">{t("french")}</option>
<option value="sv">{t("swedish")}</option>
</select>
);

View file

@ -1,9 +1,9 @@
import { NextRequest, NextResponse } from "next/server";
const supportedLocales = ["en", "es", "de", "fr", "sv"];
const supportedLocales = ["en", "es", "de", "fr", "pt-BR", "sv"];
export function middleware({ headers, cookies, nextUrl }: NextRequest) {
const locale =
const language =
cookies.get("NEXT_LOCALE") ??
(headers
.get("accept-language")
@ -14,8 +14,11 @@ export function middleware({ headers, cookies, nextUrl }: NextRequest) {
const newUrl = nextUrl.clone();
if (supportedLocales.includes(locale)) {
newUrl.pathname = `/${locale}${newUrl.pathname}`;
if (supportedLocales.includes(language)) {
newUrl.pathname = `/${language}${newUrl.pathname}`;
} else if (language === "pt") {
// For now we send all portuguese language requests to pt-BR
newUrl.pathname = `/pt-BR${newUrl.pathname}`;
}
return NextResponse.rewrite(newUrl);

View file

@ -50,6 +50,11 @@ const dayjsLocales: Record<
timeFormat: "24h",
import: () => import("dayjs/locale/sv"),
},
"pt-BR": {
weekStartsOn: "sunday",
timeFormat: "24h",
import: () => import("dayjs/locale/pt-br"),
},
};
dayjs.extend(localizedFormat);
@ -84,17 +89,17 @@ export const DayjsProvider: React.VoidFunctionComponent<{
// Using language instead of router.locale because when transitioning from homepage to
// the app via <Link locale={false}> it will be set to "en" instead of the current locale.
const locale = i18n.language;
const localeConfig = dayjsLocales[i18n.language];
const [weekStartsOn = dayjsLocales[locale].weekStartsOn, , setWeekStartsOn] =
const [weekStartsOn = localeConfig.weekStartsOn, , setWeekStartsOn] =
useLocalStorage<StartOfWeek>("rallly-week-starts-on");
const [timeFormat = dayjsLocales[locale].timeFormat, setTimeFormat] =
const [timeFormat = localeConfig.timeFormat, setTimeFormat] =
useLocalStorage<TimeFormat>("rallly-time-format");
const { value: dayjsLocale } = useAsync(async () => {
return await dayjsLocales[locale ?? "en"].import();
}, [locale]);
return await localeConfig.import();
}, [localeConfig]);
if (!dayjsLocale) {
// wait for locale to load before rendering content
@ -103,19 +108,26 @@ export const DayjsProvider: React.VoidFunctionComponent<{
dayjs.locale({
...dayjsLocale,
weekStart: weekStartsOn ? (weekStartsOn === "monday" ? 1 : 0) : undefined,
formats: {
...dayjsLocale.formats,
LT: timeFormat === "12h" ? "h:mm A" : "H:mm",
},
weekStart: weekStartsOn
? weekStartsOn === "monday"
? 1
: 0
: dayjsLocale.weekStart,
formats:
localeConfig.timeFormat !== timeFormat
? {
...dayjsLocale.formats,
LT: timeFormat === "12h" ? "h:mm A" : "H:mm",
}
: dayjsLocale.formats,
});
return (
<DayjsContext.Provider
value={{
dayjs,
weekStartsOn: weekStartsOn ?? dayjsLocales[locale].weekStartsOn,
timeFormat: timeFormat ?? dayjsLocales[locale].timeFormat,
weekStartsOn: weekStartsOn ?? localeConfig.weekStartsOn,
timeFormat: timeFormat ?? localeConfig.timeFormat,
setWeekStartsOn,
setTimeFormat,
}}